@mastra/react 0.0.0-usechat-duplicate-20251016110554 → 0.0.0-vnext-20251119160359

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,6 @@ 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');
9
8
  const lucideReact = require('lucide-react');
10
9
  const tailwindMerge = require('tailwind-merge');
11
10
  const hastUtilToJsxRuntime = require('hast-util-to-jsx-runtime');
@@ -254,6 +253,7 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
254
253
  }
255
254
  ];
256
255
  }
256
+ case "tool-error":
257
257
  case "tool-result": {
258
258
  const lastMessage = result[result.length - 1];
259
259
  if (!lastMessage || lastMessage.role !== "assistant") return result;
@@ -264,25 +264,35 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
264
264
  if (toolPartIndex !== -1) {
265
265
  const toolPart = parts[toolPartIndex];
266
266
  if (toolPart.type === "dynamic-tool") {
267
- if (chunk.payload.isError) {
267
+ if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
268
+ const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
268
269
  parts[toolPartIndex] = {
269
270
  type: "dynamic-tool",
270
271
  toolName: toolPart.toolName,
271
272
  toolCallId: toolPart.toolCallId,
272
273
  state: "output-error",
273
274
  input: toolPart.input,
274
- errorText: String(chunk.payload.result),
275
+ errorText: String(error),
275
276
  callProviderMetadata: chunk.payload.providerMetadata
276
277
  };
277
278
  } else {
278
279
  const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
280
+ const isAgent = chunk?.from === "AGENT";
281
+ let output;
282
+ if (isWorkflow) {
283
+ output = chunk.payload.result?.result;
284
+ } else if (isAgent) {
285
+ output = parts[toolPartIndex].output ?? chunk.payload.result;
286
+ } else {
287
+ output = chunk.payload.result;
288
+ }
279
289
  parts[toolPartIndex] = {
280
290
  type: "dynamic-tool",
281
291
  toolName: toolPart.toolName,
282
292
  toolCallId: toolPart.toolCallId,
283
293
  state: "output-available",
284
294
  input: toolPart.input,
285
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
295
+ output,
286
296
  callProviderMetadata: chunk.payload.providerMetadata
287
297
  };
288
298
  }
@@ -316,6 +326,8 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
316
326
  ...toolPart,
317
327
  output: updatedWorkflowState
318
328
  };
329
+ } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
330
+ return toUIMessageFromAgent(chunk.payload.output, conversation);
319
331
  } else {
320
332
  const currentOutput = toolPart.output || [];
321
333
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
@@ -389,15 +401,37 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
389
401
  }
390
402
  ];
391
403
  }
404
+ case "tool-call-approval": {
405
+ const lastMessage = result[result.length - 1];
406
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
407
+ const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
408
+ return [
409
+ ...result.slice(0, -1),
410
+ {
411
+ ...lastMessage,
412
+ metadata: {
413
+ ...lastMessage.metadata,
414
+ mode: "stream",
415
+ requireApprovalMetadata: {
416
+ ...lastRequireApprovalMetadata,
417
+ [chunk.payload.toolCallId]: {
418
+ toolCallId: chunk.payload.toolCallId,
419
+ toolName: chunk.payload.toolName,
420
+ args: chunk.payload.args
421
+ }
422
+ }
423
+ }
424
+ }
425
+ ];
426
+ }
392
427
  case "finish": {
393
428
  const lastMessage = result[result.length - 1];
394
429
  if (!lastMessage || lastMessage.role !== "assistant") return result;
395
430
  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" };
431
+ if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
432
+ if (part.type === "text" || part.type === "reasoning") {
433
+ return { ...part, state: "done" };
434
+ }
401
435
  }
402
436
  return part;
403
437
  });
@@ -431,6 +465,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
431
465
  return result;
432
466
  }
433
467
  };
468
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
469
+ const lastMessage = conversation[conversation.length - 1];
470
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
471
+ const parts = [...lastMessage.parts];
472
+ if (chunk.type === "text-delta") {
473
+ const agentChunk = chunk.payload;
474
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
475
+ if (toolPartIndex === -1) return conversation;
476
+ const toolPart = parts[toolPartIndex];
477
+ const childMessages = toolPart?.output?.childMessages || [];
478
+ const lastChildMessage = childMessages[childMessages.length - 1];
479
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
480
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
481
+ parts[toolPartIndex] = {
482
+ ...toolPart,
483
+ output: {
484
+ childMessages: nextMessages
485
+ }
486
+ };
487
+ } else if (chunk.type === "tool-call") {
488
+ const agentChunk = chunk.payload;
489
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
490
+ if (toolPartIndex === -1) return conversation;
491
+ const toolPart = parts[toolPartIndex];
492
+ const childMessages = toolPart?.output?.childMessages || [];
493
+ parts[toolPartIndex] = {
494
+ ...toolPart,
495
+ output: {
496
+ ...toolPart?.output,
497
+ childMessages: [
498
+ ...childMessages,
499
+ {
500
+ type: "tool",
501
+ toolCallId: agentChunk.toolCallId,
502
+ toolName: agentChunk.toolName,
503
+ args: agentChunk.args
504
+ }
505
+ ]
506
+ }
507
+ };
508
+ } else if (chunk.type === "tool-output") {
509
+ const agentChunk = chunk.payload;
510
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
511
+ if (toolPartIndex === -1) return conversation;
512
+ const toolPart = parts[toolPartIndex];
513
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
514
+ const childMessages = toolPart?.output?.childMessages || [];
515
+ const lastToolIndex = childMessages.length - 1;
516
+ const currentMessage = childMessages[lastToolIndex];
517
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
518
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
519
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
520
+ parts[toolPartIndex] = {
521
+ ...toolPart,
522
+ output: {
523
+ ...toolPart?.output,
524
+ childMessages: [
525
+ ...childMessages.slice(0, -1),
526
+ {
527
+ ...currentMessage,
528
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
529
+ }
530
+ ]
531
+ }
532
+ };
533
+ }
534
+ }
535
+ } else if (chunk.type === "tool-result") {
536
+ const agentChunk = chunk.payload;
537
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
538
+ if (toolPartIndex === -1) return conversation;
539
+ const toolPart = parts[toolPartIndex];
540
+ const childMessages = toolPart?.output?.childMessages || [];
541
+ const lastToolIndex = childMessages.length - 1;
542
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
543
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
544
+ parts[toolPartIndex] = {
545
+ ...toolPart,
546
+ output: {
547
+ ...toolPart?.output,
548
+ childMessages: [
549
+ ...childMessages.slice(0, -1),
550
+ {
551
+ ...childMessages[lastToolIndex],
552
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
553
+ }
554
+ ]
555
+ }
556
+ };
557
+ }
558
+ }
559
+ return [
560
+ ...conversation.slice(0, -1),
561
+ {
562
+ ...lastMessage,
563
+ parts
564
+ }
565
+ ];
566
+ };
434
567
 
435
568
  const toAssistantUIMessage = (message) => {
436
569
  const extendedMessage = message;
@@ -470,13 +603,23 @@ const toAssistantUIMessage = (message) => {
470
603
  };
471
604
  }
472
605
  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
- };
606
+ const type = part.mediaType.includes("image/") ? "image" : "file";
607
+ if (type === "file") {
608
+ return {
609
+ type,
610
+ mimeType: part.mediaType,
611
+ data: part.url,
612
+ // Use URL as data source
613
+ metadata: message.metadata
614
+ };
615
+ }
616
+ if (type === "image") {
617
+ return {
618
+ type,
619
+ image: part.url,
620
+ metadata: message.metadata
621
+ };
622
+ }
480
623
  }
481
624
  if (part.type === "dynamic-tool") {
482
625
  const baseToolCall = {
@@ -551,6 +694,112 @@ const toAssistantUIMessage = (message) => {
551
694
  return threadMessage;
552
695
  };
553
696
 
697
+ const resolveInitialMessages = (messages) => {
698
+ return messages.map((message) => {
699
+ const networkPart = message.parts.find(
700
+ (part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
701
+ );
702
+ if (networkPart && networkPart.type === "text") {
703
+ try {
704
+ const json = JSON.parse(networkPart.text);
705
+ if (json.isNetwork === true) {
706
+ const selectionReason = json.selectionReason || "";
707
+ const primitiveType = json.primitiveType || "";
708
+ const primitiveId = json.primitiveId || "";
709
+ const finalResult = json.finalResult;
710
+ const toolCalls = finalResult?.toolCalls || [];
711
+ const childMessages = [];
712
+ for (const toolCall of toolCalls) {
713
+ if (toolCall.type === "tool-call" && toolCall.payload) {
714
+ const toolCallId = toolCall.payload.toolCallId;
715
+ let toolResult;
716
+ for (const message2 of finalResult?.messages || []) {
717
+ for (const part of message2.content || []) {
718
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
719
+ toolResult = part;
720
+ break;
721
+ }
722
+ }
723
+ }
724
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
725
+ childMessages.push({
726
+ type: "tool",
727
+ toolCallId: toolCall.payload.toolCallId,
728
+ toolName: toolCall.payload.toolName,
729
+ args: toolCall.payload.args,
730
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
731
+ });
732
+ }
733
+ }
734
+ if (finalResult && finalResult.text) {
735
+ childMessages.push({
736
+ type: "text",
737
+ content: finalResult.text
738
+ });
739
+ }
740
+ const result = {
741
+ childMessages,
742
+ result: finalResult?.text || ""
743
+ };
744
+ console.log("json", json);
745
+ const nextMessage = {
746
+ role: "assistant",
747
+ parts: [
748
+ {
749
+ type: "dynamic-tool",
750
+ toolCallId: primitiveId,
751
+ toolName: primitiveId,
752
+ state: "output-available",
753
+ input: json.input,
754
+ output: result
755
+ }
756
+ ],
757
+ id: message.id,
758
+ metadata: {
759
+ ...message.metadata,
760
+ mode: "network",
761
+ selectionReason,
762
+ agentInput: json.input,
763
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
764
+ }
765
+ };
766
+ return nextMessage;
767
+ }
768
+ } catch (error) {
769
+ return message;
770
+ }
771
+ }
772
+ return message;
773
+ });
774
+ };
775
+ const resolveToChildMessages = (messages) => {
776
+ const assistantMessage = messages.find((message) => message.role === "assistant");
777
+ if (!assistantMessage) return [];
778
+ const parts = assistantMessage.parts;
779
+ let childMessages = [];
780
+ for (const part of parts) {
781
+ const toolPart = part;
782
+ if (part.type.startsWith("tool-")) {
783
+ const toolName = part.type.substring("tool-".length);
784
+ const isWorkflow = toolName.startsWith("workflow-");
785
+ childMessages.push({
786
+ type: "tool",
787
+ toolCallId: toolPart.toolCallId,
788
+ toolName,
789
+ args: toolPart.input,
790
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
791
+ });
792
+ }
793
+ if (part.type === "text") {
794
+ childMessages.push({
795
+ type: "text",
796
+ content: toolPart.text
797
+ });
798
+ }
799
+ }
800
+ return childMessages;
801
+ };
802
+
554
803
  class AISdkNetworkTransformer {
555
804
  transform({ chunk, conversation, metadata }) {
556
805
  const newConversation = [...conversation];
@@ -923,92 +1172,63 @@ class AISdkNetworkTransformer {
923
1172
  };
924
1173
  }
925
1174
 
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;
1175
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1176
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1177
+ const parts = typeof coreUserMessage.content === "string" ? [
1178
+ {
1179
+ type: "text",
1180
+ text: coreUserMessage.content
1181
+ }
1182
+ ] : coreUserMessage.content.map((part) => {
1183
+ switch (part.type) {
1184
+ case "text": {
1185
+ return {
1186
+ type: "text",
1187
+ text: part.text
1188
+ };
1189
+ }
1190
+ case "image": {
1191
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1192
+ return {
1193
+ type: "file",
1194
+ mediaType: part.mimeType ?? "image/*",
1195
+ url
1196
+ };
1197
+ }
1198
+ case "file": {
1199
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1200
+ return {
1201
+ type: "file",
1202
+ mediaType: part.mimeType,
1203
+ url,
1204
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1205
+ };
1206
+ }
1207
+ default: {
1208
+ const exhaustiveCheck = part;
1209
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
997
1210
  }
998
1211
  }
999
- return message;
1000
1212
  });
1213
+ return {
1214
+ id,
1215
+ role: "user",
1216
+ parts
1217
+ };
1001
1218
  };
1002
1219
 
1003
1220
  const useChat = ({ agentId, initializeMessages }) => {
1221
+ const _currentRunId = react.useRef(void 0);
1222
+ const _onChunk = react.useRef(void 0);
1004
1223
  const [messages, setMessages] = react.useState(
1005
1224
  () => resolveInitialMessages(initializeMessages?.() || [])
1006
1225
  );
1226
+ const [toolCallApprovals, setToolCallApprovals] = react.useState({});
1007
1227
  const baseClient = useMastraClient();
1008
1228
  const [isRunning, setIsRunning] = react.useState(false);
1009
1229
  const generate = async ({
1010
1230
  coreUserMessages,
1011
- runtimeContext,
1231
+ requestContext,
1012
1232
  threadId,
1013
1233
  modelSettings,
1014
1234
  signal,
@@ -1046,7 +1266,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1046
1266
  topP
1047
1267
  },
1048
1268
  instructions,
1049
- runtimeContext,
1269
+ requestContext,
1050
1270
  ...threadId ? { threadId, resourceId: agentId } : {},
1051
1271
  providerOptions
1052
1272
  });
@@ -1062,7 +1282,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1062
1282
  setMessages((prev) => [...prev, ...mastraUIMessages]);
1063
1283
  }
1064
1284
  };
1065
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1285
+ const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1066
1286
  const {
1067
1287
  frequencyPenalty,
1068
1288
  presencePenalty,
@@ -1073,7 +1293,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1073
1293
  topP,
1074
1294
  instructions,
1075
1295
  providerOptions,
1076
- maxSteps
1296
+ maxSteps,
1297
+ requireToolApproval
1077
1298
  } = modelSettings || {};
1078
1299
  setIsRunning(true);
1079
1300
  const clientWithAbort = new clientJs.MastraClient({
@@ -1081,9 +1302,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1081
1302
  abortSignal: signal
1082
1303
  });
1083
1304
  const agent = clientWithAbort.getAgent(agentId);
1305
+ const runId = agentId;
1084
1306
  const response = await agent.stream({
1085
1307
  messages: coreUserMessages,
1086
- runId: agentId,
1308
+ runId,
1087
1309
  maxSteps,
1088
1310
  modelSettings: {
1089
1311
  frequencyPenalty,
@@ -1095,19 +1317,16 @@ const useChat = ({ agentId, initializeMessages }) => {
1095
1317
  topP
1096
1318
  },
1097
1319
  instructions,
1098
- runtimeContext,
1320
+ requestContext,
1099
1321
  ...threadId ? { threadId, resourceId: agentId } : {},
1100
- providerOptions
1322
+ providerOptions,
1323
+ requireToolApproval
1101
1324
  });
1102
- if (!response.body) {
1103
- setIsRunning(false);
1104
- throw new Error("[Stream] No response body");
1105
- }
1325
+ _onChunk.current = onChunk;
1326
+ _currentRunId.current = runId;
1106
1327
  await response.processDataStream({
1107
1328
  onChunk: async (chunk) => {
1108
- reactDom.flushSync(() => {
1109
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1110
- });
1329
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1111
1330
  onChunk?.(chunk);
1112
1331
  }
1113
1332
  });
@@ -1115,7 +1334,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1115
1334
  };
1116
1335
  const network = async ({
1117
1336
  coreUserMessages,
1118
- runtimeContext,
1337
+ requestContext,
1119
1338
  threadId,
1120
1339
  onNetworkChunk,
1121
1340
  modelSettings,
@@ -1141,30 +1360,71 @@ const useChat = ({ agentId, initializeMessages }) => {
1141
1360
  topP
1142
1361
  },
1143
1362
  runId: agentId,
1144
- runtimeContext,
1363
+ requestContext,
1145
1364
  ...threadId ? { thread: threadId, resourceId: agentId } : {}
1146
1365
  });
1147
1366
  const transformer = new AISdkNetworkTransformer();
1148
1367
  await response.processDataStream({
1149
1368
  onChunk: async (chunk) => {
1150
- reactDom.flushSync(() => {
1151
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1152
- });
1369
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1153
1370
  onNetworkChunk?.(chunk);
1154
1371
  }
1155
1372
  });
1156
1373
  setIsRunning(false);
1157
1374
  };
1375
+ const handleCancelRun = () => {
1376
+ setIsRunning(false);
1377
+ _currentRunId.current = void 0;
1378
+ _onChunk.current = void 0;
1379
+ };
1380
+ const approveToolCall = async (toolCallId) => {
1381
+ const onChunk = _onChunk.current;
1382
+ const currentRunId = _currentRunId.current;
1383
+ if (!currentRunId)
1384
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1385
+ setIsRunning(true);
1386
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1387
+ const agent = baseClient.getAgent(agentId);
1388
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1389
+ await response.processDataStream({
1390
+ onChunk: async (chunk) => {
1391
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1392
+ onChunk?.(chunk);
1393
+ }
1394
+ });
1395
+ setIsRunning(false);
1396
+ };
1397
+ const declineToolCall = async (toolCallId) => {
1398
+ const onChunk = _onChunk.current;
1399
+ const currentRunId = _currentRunId.current;
1400
+ if (!currentRunId)
1401
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1402
+ setIsRunning(true);
1403
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1404
+ const agent = baseClient.getAgent(agentId);
1405
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1406
+ await response.processDataStream({
1407
+ onChunk: async (chunk) => {
1408
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1409
+ onChunk?.(chunk);
1410
+ }
1411
+ });
1412
+ setIsRunning(false);
1413
+ };
1158
1414
  const sendMessage = async ({ mode = "stream", ...args }) => {
1159
1415
  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 }] }]);
1416
+ const coreUserMessages = [nextMessage];
1417
+ if (args.coreUserMessages) {
1418
+ coreUserMessages.push(...args.coreUserMessages);
1419
+ }
1420
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1421
+ setMessages((s) => [...s, ...uiMessages]);
1162
1422
  if (mode === "generate") {
1163
- await generate({ ...args, coreUserMessages: messages2 });
1423
+ await generate({ ...args, coreUserMessages });
1164
1424
  } else if (mode === "stream") {
1165
- await stream({ ...args, coreUserMessages: messages2 });
1425
+ await stream({ ...args, coreUserMessages });
1166
1426
  } else if (mode === "network") {
1167
- await network({ ...args, coreUserMessages: messages2 });
1427
+ await network({ ...args, coreUserMessages });
1168
1428
  }
1169
1429
  };
1170
1430
  return {
@@ -1172,7 +1432,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1172
1432
  sendMessage,
1173
1433
  isRunning,
1174
1434
  messages,
1175
- cancelRun: () => setIsRunning(false)
1435
+ approveToolCall,
1436
+ declineToolCall,
1437
+ cancelRun: handleCancelRun,
1438
+ toolCallApprovals
1176
1439
  };
1177
1440
  };
1178
1441
 
@@ -1546,6 +1809,7 @@ exports.TooltipContentClass = TooltipContentClass;
1546
1809
  exports.TooltipTrigger = TooltipTrigger;
1547
1810
  exports.WorkflowIcon = WorkflowIcon;
1548
1811
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1812
+ exports.resolveToChildMessages = resolveToChildMessages;
1549
1813
  exports.toAssistantUIMessage = toAssistantUIMessage;
1550
1814
  exports.toUIMessage = toUIMessage;
1551
1815
  exports.useChat = useChat;