@mastra/react 0.0.0-model-router-unknown-provider-20251017212006 → 0.0.0-playground-studio-cloud-20251031080052

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/CHANGELOG.md CHANGED
@@ -1,11 +1,76 @@
1
1
  # @mastra/react-hooks
2
2
 
3
- ## 0.0.0-model-router-unknown-provider-20251017212006
3
+ ## 0.0.0-playground-studio-cloud-20251031080052
4
+
5
+ ### Patch Changes
6
+
7
+ - Add tool call approval ([#8649](https://github.com/mastra-ai/mastra/pull/8649))
8
+
9
+ - Fix multi modal in react sdk ([#9373](https://github.com/mastra-ai/mastra/pull/9373))
10
+
11
+ - Updated dependencies [[`1ee3411`](https://github.com/mastra-ai/mastra/commit/1ee34113192b11aa8bcdd8d9d5830ae13254b345), [`5df9cce`](https://github.com/mastra-ai/mastra/commit/5df9cce1a753438413f64c11eeef8f845745c2a8), [`c576fc0`](https://github.com/mastra-ai/mastra/commit/c576fc0b100b2085afded91a37c97a0ea0ec09c7), [`ea0b8de`](https://github.com/mastra-ai/mastra/commit/ea0b8dec0d4bc86a72a7e75b2f56c6017c58786d), [`f0f8f12`](https://github.com/mastra-ai/mastra/commit/f0f8f125c308f2d0fd36942ef652fd852df7522f), [`63f2f18`](https://github.com/mastra-ai/mastra/commit/63f2f1863dffe3ad23221d0660ed4e4f2b81789d)]:
12
+ - @mastra/client-js@0.0.0-playground-studio-cloud-20251031080052
13
+
14
+ ## 0.0.10
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies []:
19
+ - @mastra/client-js@0.16.4
20
+
21
+ ## 0.0.10-alpha.0
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies []:
26
+ - @mastra/client-js@0.16.4-alpha.0
27
+
28
+ ## 0.0.9
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies []:
33
+ - @mastra/client-js@0.16.3
34
+
35
+ ## 0.0.9-alpha.0
36
+
37
+ ### Patch Changes
38
+
39
+ - Updated dependencies []:
40
+ - @mastra/client-js@0.16.3-alpha.0
41
+
42
+ ## 0.0.8
43
+
44
+ ### Patch Changes
45
+
46
+ - Fix perf issue: removed flush sync ([#9014](https://github.com/mastra-ai/mastra/pull/9014))
47
+
48
+ - Fix tool result in playground ([#9087](https://github.com/mastra-ai/mastra/pull/9087))
49
+
50
+ - Show agent tool output better in playground ([#9021](https://github.com/mastra-ai/mastra/pull/9021))
51
+
52
+ - Updated dependencies []:
53
+ - @mastra/client-js@0.16.2
54
+
55
+ ## 0.0.8-alpha.1
56
+
57
+ ### Patch Changes
58
+
59
+ - Fix perf issue: removed flush sync ([#9014](https://github.com/mastra-ai/mastra/pull/9014))
60
+
61
+ - Fix tool result in playground ([#9087](https://github.com/mastra-ai/mastra/pull/9087))
62
+
63
+ - Show agent tool output better in playground ([#9021](https://github.com/mastra-ai/mastra/pull/9021))
64
+
65
+ - Updated dependencies []:
66
+ - @mastra/client-js@0.16.2-alpha.1
67
+
68
+ ## 0.0.8-alpha.0
4
69
 
5
70
  ### Patch Changes
6
71
 
7
72
  - Updated dependencies []:
8
- - @mastra/client-js@0.0.0-model-router-unknown-provider-20251017212006
73
+ - @mastra/client-js@0.16.2-alpha.0
9
74
 
10
75
  ## 0.0.7
11
76
 
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,6 +401,29 @@ 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;
@@ -431,6 +466,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
431
466
  return result;
432
467
  }
433
468
  };
469
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
470
+ const lastMessage = conversation[conversation.length - 1];
471
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
472
+ const parts = [...lastMessage.parts];
473
+ if (chunk.type === "text-delta") {
474
+ const agentChunk = chunk.payload;
475
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
476
+ if (toolPartIndex === -1) return conversation;
477
+ const toolPart = parts[toolPartIndex];
478
+ const childMessages = toolPart?.output?.childMessages || [];
479
+ const lastChildMessage = childMessages[childMessages.length - 1];
480
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
481
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
482
+ parts[toolPartIndex] = {
483
+ ...toolPart,
484
+ output: {
485
+ childMessages: nextMessages
486
+ }
487
+ };
488
+ } else if (chunk.type === "tool-call") {
489
+ const agentChunk = chunk.payload;
490
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
491
+ if (toolPartIndex === -1) return conversation;
492
+ const toolPart = parts[toolPartIndex];
493
+ const childMessages = toolPart?.output?.childMessages || [];
494
+ parts[toolPartIndex] = {
495
+ ...toolPart,
496
+ output: {
497
+ ...toolPart?.output,
498
+ childMessages: [
499
+ ...childMessages,
500
+ {
501
+ type: "tool",
502
+ toolCallId: agentChunk.toolCallId,
503
+ toolName: agentChunk.toolName,
504
+ args: agentChunk.args
505
+ }
506
+ ]
507
+ }
508
+ };
509
+ } else if (chunk.type === "tool-output") {
510
+ const agentChunk = chunk.payload;
511
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
512
+ if (toolPartIndex === -1) return conversation;
513
+ const toolPart = parts[toolPartIndex];
514
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
515
+ const childMessages = toolPart?.output?.childMessages || [];
516
+ const lastToolIndex = childMessages.length - 1;
517
+ const currentMessage = childMessages[lastToolIndex];
518
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
519
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
520
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
521
+ parts[toolPartIndex] = {
522
+ ...toolPart,
523
+ output: {
524
+ ...toolPart?.output,
525
+ childMessages: [
526
+ ...childMessages.slice(0, -1),
527
+ {
528
+ ...currentMessage,
529
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
530
+ }
531
+ ]
532
+ }
533
+ };
534
+ }
535
+ }
536
+ } else if (chunk.type === "tool-result") {
537
+ const agentChunk = chunk.payload;
538
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
539
+ if (toolPartIndex === -1) return conversation;
540
+ const toolPart = parts[toolPartIndex];
541
+ const childMessages = toolPart?.output?.childMessages || [];
542
+ const lastToolIndex = childMessages.length - 1;
543
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
544
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
545
+ parts[toolPartIndex] = {
546
+ ...toolPart,
547
+ output: {
548
+ ...toolPart?.output,
549
+ childMessages: [
550
+ ...childMessages.slice(0, -1),
551
+ {
552
+ ...childMessages[lastToolIndex],
553
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
554
+ }
555
+ ]
556
+ }
557
+ };
558
+ }
559
+ }
560
+ return [
561
+ ...conversation.slice(0, -1),
562
+ {
563
+ ...lastMessage,
564
+ parts
565
+ }
566
+ ];
567
+ };
434
568
 
435
569
  const toAssistantUIMessage = (message) => {
436
570
  const extendedMessage = message;
@@ -470,13 +604,23 @@ const toAssistantUIMessage = (message) => {
470
604
  };
471
605
  }
472
606
  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
- };
607
+ const type = part.mediaType.includes("image/") ? "image" : "file";
608
+ if (type === "file") {
609
+ return {
610
+ type,
611
+ mimeType: part.mediaType,
612
+ data: part.url,
613
+ // Use URL as data source
614
+ metadata: message.metadata
615
+ };
616
+ }
617
+ if (type === "image") {
618
+ return {
619
+ type,
620
+ image: part.url,
621
+ metadata: message.metadata
622
+ };
623
+ }
480
624
  }
481
625
  if (part.type === "dynamic-tool") {
482
626
  const baseToolCall = {
@@ -551,6 +695,110 @@ const toAssistantUIMessage = (message) => {
551
695
  return threadMessage;
552
696
  };
553
697
 
698
+ const resolveInitialMessages = (messages) => {
699
+ return messages.map((message) => {
700
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
701
+ if (networkPart && networkPart.type === "text") {
702
+ try {
703
+ const json = JSON.parse(networkPart.text);
704
+ if (json.isNetwork === true) {
705
+ const selectionReason = json.selectionReason || "";
706
+ const primitiveType = json.primitiveType || "";
707
+ const primitiveId = json.primitiveId || "";
708
+ const finalResult = json.finalResult;
709
+ const toolCalls = finalResult?.toolCalls || [];
710
+ const childMessages = [];
711
+ for (const toolCall of toolCalls) {
712
+ if (toolCall.type === "tool-call" && toolCall.payload) {
713
+ const toolCallId = toolCall.payload.toolCallId;
714
+ let toolResult;
715
+ for (const message2 of finalResult?.messages || []) {
716
+ for (const part of message2.content || []) {
717
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
718
+ toolResult = part;
719
+ break;
720
+ }
721
+ }
722
+ }
723
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
724
+ childMessages.push({
725
+ type: "tool",
726
+ toolCallId: toolCall.payload.toolCallId,
727
+ toolName: toolCall.payload.toolName,
728
+ args: toolCall.payload.args,
729
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
730
+ });
731
+ }
732
+ }
733
+ if (finalResult && finalResult.text) {
734
+ childMessages.push({
735
+ type: "text",
736
+ content: finalResult.text
737
+ });
738
+ }
739
+ const result = {
740
+ childMessages,
741
+ result: finalResult?.text || ""
742
+ };
743
+ console.log("json", json);
744
+ const nextMessage = {
745
+ role: "assistant",
746
+ parts: [
747
+ {
748
+ type: "dynamic-tool",
749
+ toolCallId: primitiveId,
750
+ toolName: primitiveId,
751
+ state: "output-available",
752
+ input: json.input,
753
+ output: result
754
+ }
755
+ ],
756
+ id: message.id,
757
+ metadata: {
758
+ ...message.metadata,
759
+ mode: "network",
760
+ selectionReason,
761
+ agentInput: json.input,
762
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
763
+ }
764
+ };
765
+ return nextMessage;
766
+ }
767
+ } catch (error) {
768
+ return message;
769
+ }
770
+ }
771
+ return message;
772
+ });
773
+ };
774
+ const resolveToChildMessages = (messages) => {
775
+ const assistantMessage = messages.find((message) => message.role === "assistant");
776
+ if (!assistantMessage) return [];
777
+ const parts = assistantMessage.parts;
778
+ let childMessages = [];
779
+ for (const part of parts) {
780
+ const toolPart = part;
781
+ if (part.type.startsWith("tool-")) {
782
+ const toolName = part.type.substring("tool-".length);
783
+ const isWorkflow = toolName.startsWith("workflow-");
784
+ childMessages.push({
785
+ type: "tool",
786
+ toolCallId: toolPart.toolCallId,
787
+ toolName,
788
+ args: toolPart.input,
789
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
790
+ });
791
+ }
792
+ if (part.type === "text") {
793
+ childMessages.push({
794
+ type: "text",
795
+ content: toolPart.text
796
+ });
797
+ }
798
+ }
799
+ return childMessages;
800
+ };
801
+
554
802
  class AISdkNetworkTransformer {
555
803
  transform({ chunk, conversation, metadata }) {
556
804
  const newConversation = [...conversation];
@@ -923,87 +1171,58 @@ class AISdkNetworkTransformer {
923
1171
  };
924
1172
  }
925
1173
 
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;
1174
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1175
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1176
+ const parts = typeof coreUserMessage.content === "string" ? [
1177
+ {
1178
+ type: "text",
1179
+ text: coreUserMessage.content
1180
+ }
1181
+ ] : coreUserMessage.content.map((part) => {
1182
+ switch (part.type) {
1183
+ case "text": {
1184
+ return {
1185
+ type: "text",
1186
+ text: part.text
1187
+ };
1188
+ }
1189
+ case "image": {
1190
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1191
+ return {
1192
+ type: "file",
1193
+ mediaType: part.mimeType ?? "image/*",
1194
+ url
1195
+ };
1196
+ }
1197
+ case "file": {
1198
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1199
+ return {
1200
+ type: "file",
1201
+ mediaType: part.mimeType,
1202
+ url,
1203
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1204
+ };
1205
+ }
1206
+ default: {
1207
+ const exhaustiveCheck = part;
1208
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
997
1209
  }
998
1210
  }
999
- return message;
1000
1211
  });
1212
+ return {
1213
+ id,
1214
+ role: "user",
1215
+ parts
1216
+ };
1001
1217
  };
1002
1218
 
1003
1219
  const useChat = ({ agentId, initializeMessages }) => {
1220
+ const _currentRunId = react.useRef(void 0);
1221
+ const _onChunk = react.useRef(void 0);
1004
1222
  const [messages, setMessages] = react.useState(
1005
1223
  () => resolveInitialMessages(initializeMessages?.() || [])
1006
1224
  );
1225
+ const [toolCallApprovals, setToolCallApprovals] = react.useState({});
1007
1226
  const baseClient = useMastraClient();
1008
1227
  const [isRunning, setIsRunning] = react.useState(false);
1009
1228
  const generate = async ({
@@ -1073,7 +1292,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1073
1292
  topP,
1074
1293
  instructions,
1075
1294
  providerOptions,
1076
- maxSteps
1295
+ maxSteps,
1296
+ requireToolApproval
1077
1297
  } = modelSettings || {};
1078
1298
  setIsRunning(true);
1079
1299
  const clientWithAbort = new clientJs.MastraClient({
@@ -1081,9 +1301,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1081
1301
  abortSignal: signal
1082
1302
  });
1083
1303
  const agent = clientWithAbort.getAgent(agentId);
1304
+ const runId = agentId;
1084
1305
  const response = await agent.stream({
1085
1306
  messages: coreUserMessages,
1086
- runId: agentId,
1307
+ runId,
1087
1308
  maxSteps,
1088
1309
  modelSettings: {
1089
1310
  frequencyPenalty,
@@ -1097,17 +1318,14 @@ const useChat = ({ agentId, initializeMessages }) => {
1097
1318
  instructions,
1098
1319
  runtimeContext,
1099
1320
  ...threadId ? { threadId, resourceId: agentId } : {},
1100
- providerOptions
1321
+ providerOptions,
1322
+ requireToolApproval
1101
1323
  });
1102
- if (!response.body) {
1103
- setIsRunning(false);
1104
- throw new Error("[Stream] No response body");
1105
- }
1324
+ _onChunk.current = onChunk;
1325
+ _currentRunId.current = runId;
1106
1326
  await response.processDataStream({
1107
1327
  onChunk: async (chunk) => {
1108
- reactDom.flushSync(() => {
1109
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1110
- });
1328
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1111
1329
  onChunk?.(chunk);
1112
1330
  }
1113
1331
  });
@@ -1147,24 +1365,65 @@ const useChat = ({ agentId, initializeMessages }) => {
1147
1365
  const transformer = new AISdkNetworkTransformer();
1148
1366
  await response.processDataStream({
1149
1367
  onChunk: async (chunk) => {
1150
- reactDom.flushSync(() => {
1151
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1152
- });
1368
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1153
1369
  onNetworkChunk?.(chunk);
1154
1370
  }
1155
1371
  });
1156
1372
  setIsRunning(false);
1157
1373
  };
1374
+ const handleCancelRun = () => {
1375
+ setIsRunning(false);
1376
+ _currentRunId.current = void 0;
1377
+ _onChunk.current = void 0;
1378
+ };
1379
+ const approveToolCall = async (toolCallId) => {
1380
+ const onChunk = _onChunk.current;
1381
+ const currentRunId = _currentRunId.current;
1382
+ if (!currentRunId)
1383
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1384
+ setIsRunning(true);
1385
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1386
+ const agent = baseClient.getAgent(agentId);
1387
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1388
+ await response.processDataStream({
1389
+ onChunk: async (chunk) => {
1390
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1391
+ onChunk?.(chunk);
1392
+ }
1393
+ });
1394
+ setIsRunning(false);
1395
+ };
1396
+ const declineToolCall = async (toolCallId) => {
1397
+ const onChunk = _onChunk.current;
1398
+ const currentRunId = _currentRunId.current;
1399
+ if (!currentRunId)
1400
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1401
+ setIsRunning(true);
1402
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1403
+ const agent = baseClient.getAgent(agentId);
1404
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1405
+ await response.processDataStream({
1406
+ onChunk: async (chunk) => {
1407
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1408
+ onChunk?.(chunk);
1409
+ }
1410
+ });
1411
+ setIsRunning(false);
1412
+ };
1158
1413
  const sendMessage = async ({ mode = "stream", ...args }) => {
1159
1414
  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 }] }]);
1415
+ const coreUserMessages = [nextMessage];
1416
+ if (args.coreUserMessages) {
1417
+ coreUserMessages.push(...args.coreUserMessages);
1418
+ }
1419
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1420
+ setMessages((s) => [...s, ...uiMessages]);
1162
1421
  if (mode === "generate") {
1163
- await generate({ ...args, coreUserMessages: messages2 });
1422
+ await generate({ ...args, coreUserMessages });
1164
1423
  } else if (mode === "stream") {
1165
- await stream({ ...args, coreUserMessages: messages2 });
1424
+ await stream({ ...args, coreUserMessages });
1166
1425
  } else if (mode === "network") {
1167
- await network({ ...args, coreUserMessages: messages2 });
1426
+ await network({ ...args, coreUserMessages });
1168
1427
  }
1169
1428
  };
1170
1429
  return {
@@ -1172,7 +1431,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1172
1431
  sendMessage,
1173
1432
  isRunning,
1174
1433
  messages,
1175
- cancelRun: () => setIsRunning(false)
1434
+ approveToolCall,
1435
+ declineToolCall,
1436
+ cancelRun: handleCancelRun,
1437
+ toolCallApprovals
1176
1438
  };
1177
1439
  };
1178
1440
 
@@ -1546,6 +1808,7 @@ exports.TooltipContentClass = TooltipContentClass;
1546
1808
  exports.TooltipTrigger = TooltipTrigger;
1547
1809
  exports.WorkflowIcon = WorkflowIcon;
1548
1810
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1811
+ exports.resolveToChildMessages = resolveToChildMessages;
1549
1812
  exports.toAssistantUIMessage = toAssistantUIMessage;
1550
1813
  exports.toUIMessage = toUIMessage;
1551
1814
  exports.useChat = useChat;