@mastra/react 0.0.7 → 0.0.8-alpha.1

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,5 +1,25 @@
1
1
  # @mastra/react-hooks
2
2
 
3
+ ## 0.0.8-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix perf issue: removed flush sync ([#9014](https://github.com/mastra-ai/mastra/pull/9014))
8
+
9
+ - Fix tool result in playground ([#9087](https://github.com/mastra-ai/mastra/pull/9087))
10
+
11
+ - Show agent tool output better in playground ([#9021](https://github.com/mastra-ai/mastra/pull/9021))
12
+
13
+ - Updated dependencies []:
14
+ - @mastra/client-js@0.16.2-alpha.1
15
+
16
+ ## 0.0.8-alpha.0
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies []:
21
+ - @mastra/client-js@0.16.2-alpha.0
22
+
3
23
  ## 0.0.7
4
24
 
5
25
  ### Patch Changes
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');
@@ -276,13 +275,22 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
276
275
  };
277
276
  } else {
278
277
  const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
278
+ const isAgent = chunk?.from === "AGENT";
279
+ let output;
280
+ if (isWorkflow) {
281
+ output = chunk.payload.result?.result;
282
+ } else if (isAgent) {
283
+ output = parts[toolPartIndex].output ?? chunk.payload.result;
284
+ } else {
285
+ output = chunk.payload.result;
286
+ }
279
287
  parts[toolPartIndex] = {
280
288
  type: "dynamic-tool",
281
289
  toolName: toolPart.toolName,
282
290
  toolCallId: toolPart.toolCallId,
283
291
  state: "output-available",
284
292
  input: toolPart.input,
285
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
293
+ output,
286
294
  callProviderMetadata: chunk.payload.providerMetadata
287
295
  };
288
296
  }
@@ -316,6 +324,8 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
316
324
  ...toolPart,
317
325
  output: updatedWorkflowState
318
326
  };
327
+ } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
328
+ return toUIMessageFromAgent(chunk.payload.output, conversation);
319
329
  } else {
320
330
  const currentOutput = toolPart.output || [];
321
331
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
@@ -431,6 +441,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
431
441
  return result;
432
442
  }
433
443
  };
444
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
445
+ const lastMessage = conversation[conversation.length - 1];
446
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
447
+ const parts = [...lastMessage.parts];
448
+ if (chunk.type === "text-delta") {
449
+ const agentChunk = chunk.payload;
450
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
451
+ if (toolPartIndex === -1) return conversation;
452
+ const toolPart = parts[toolPartIndex];
453
+ const childMessages = toolPart?.output?.childMessages || [];
454
+ const lastChildMessage = childMessages[childMessages.length - 1];
455
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
456
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
457
+ parts[toolPartIndex] = {
458
+ ...toolPart,
459
+ output: {
460
+ childMessages: nextMessages
461
+ }
462
+ };
463
+ } else if (chunk.type === "tool-call") {
464
+ const agentChunk = chunk.payload;
465
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
466
+ if (toolPartIndex === -1) return conversation;
467
+ const toolPart = parts[toolPartIndex];
468
+ const childMessages = toolPart?.output?.childMessages || [];
469
+ parts[toolPartIndex] = {
470
+ ...toolPart,
471
+ output: {
472
+ ...toolPart?.output,
473
+ childMessages: [
474
+ ...childMessages,
475
+ {
476
+ type: "tool",
477
+ toolCallId: agentChunk.toolCallId,
478
+ toolName: agentChunk.toolName,
479
+ args: agentChunk.args
480
+ }
481
+ ]
482
+ }
483
+ };
484
+ } else if (chunk.type === "tool-output") {
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
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
490
+ const childMessages = toolPart?.output?.childMessages || [];
491
+ const lastToolIndex = childMessages.length - 1;
492
+ const currentMessage = childMessages[lastToolIndex];
493
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
494
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
495
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
496
+ parts[toolPartIndex] = {
497
+ ...toolPart,
498
+ output: {
499
+ ...toolPart?.output,
500
+ childMessages: [
501
+ ...childMessages.slice(0, -1),
502
+ {
503
+ ...currentMessage,
504
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
505
+ }
506
+ ]
507
+ }
508
+ };
509
+ }
510
+ }
511
+ } else if (chunk.type === "tool-result") {
512
+ const agentChunk = chunk.payload;
513
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
514
+ if (toolPartIndex === -1) return conversation;
515
+ const toolPart = parts[toolPartIndex];
516
+ const childMessages = toolPart?.output?.childMessages || [];
517
+ const lastToolIndex = childMessages.length - 1;
518
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
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
+ ...childMessages[lastToolIndex],
528
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
529
+ }
530
+ ]
531
+ }
532
+ };
533
+ }
534
+ }
535
+ return [
536
+ ...conversation.slice(0, -1),
537
+ {
538
+ ...lastMessage,
539
+ parts
540
+ }
541
+ ];
542
+ };
434
543
 
435
544
  const toAssistantUIMessage = (message) => {
436
545
  const extendedMessage = message;
@@ -551,6 +660,110 @@ const toAssistantUIMessage = (message) => {
551
660
  return threadMessage;
552
661
  };
553
662
 
663
+ const resolveInitialMessages = (messages) => {
664
+ return messages.map((message) => {
665
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
666
+ if (networkPart && networkPart.type === "text") {
667
+ try {
668
+ const json = JSON.parse(networkPart.text);
669
+ if (json.isNetwork === true) {
670
+ const selectionReason = json.selectionReason || "";
671
+ const primitiveType = json.primitiveType || "";
672
+ const primitiveId = json.primitiveId || "";
673
+ const finalResult = json.finalResult;
674
+ const toolCalls = finalResult?.toolCalls || [];
675
+ const childMessages = [];
676
+ for (const toolCall of toolCalls) {
677
+ if (toolCall.type === "tool-call" && toolCall.payload) {
678
+ const toolCallId = toolCall.payload.toolCallId;
679
+ let toolResult;
680
+ for (const message2 of finalResult?.messages || []) {
681
+ for (const part of message2.content || []) {
682
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
683
+ toolResult = part;
684
+ break;
685
+ }
686
+ }
687
+ }
688
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
689
+ childMessages.push({
690
+ type: "tool",
691
+ toolCallId: toolCall.payload.toolCallId,
692
+ toolName: toolCall.payload.toolName,
693
+ args: toolCall.payload.args,
694
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
695
+ });
696
+ }
697
+ }
698
+ if (finalResult && finalResult.text) {
699
+ childMessages.push({
700
+ type: "text",
701
+ content: finalResult.text
702
+ });
703
+ }
704
+ const result = {
705
+ childMessages,
706
+ result: finalResult?.text || ""
707
+ };
708
+ console.log("json", json);
709
+ const nextMessage = {
710
+ role: "assistant",
711
+ parts: [
712
+ {
713
+ type: "dynamic-tool",
714
+ toolCallId: primitiveId,
715
+ toolName: primitiveId,
716
+ state: "output-available",
717
+ input: json.input,
718
+ output: result
719
+ }
720
+ ],
721
+ id: message.id,
722
+ metadata: {
723
+ ...message.metadata,
724
+ mode: "network",
725
+ selectionReason,
726
+ agentInput: json.input,
727
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
728
+ }
729
+ };
730
+ return nextMessage;
731
+ }
732
+ } catch (error) {
733
+ return message;
734
+ }
735
+ }
736
+ return message;
737
+ });
738
+ };
739
+ const resolveToChildMessages = (messages) => {
740
+ const assistantMessage = messages.find((message) => message.role === "assistant");
741
+ if (!assistantMessage) return [];
742
+ const parts = assistantMessage.parts;
743
+ let childMessages = [];
744
+ for (const part of parts) {
745
+ const toolPart = part;
746
+ if (part.type.startsWith("tool-")) {
747
+ const toolName = part.type.substring("tool-".length);
748
+ const isWorkflow = toolName.startsWith("workflow-");
749
+ childMessages.push({
750
+ type: "tool",
751
+ toolCallId: toolPart.toolCallId,
752
+ toolName,
753
+ args: toolPart.input,
754
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
755
+ });
756
+ }
757
+ if (part.type === "text") {
758
+ childMessages.push({
759
+ type: "text",
760
+ content: toolPart.text
761
+ });
762
+ }
763
+ }
764
+ return childMessages;
765
+ };
766
+
554
767
  class AISdkNetworkTransformer {
555
768
  transform({ chunk, conversation, metadata }) {
556
769
  const newConversation = [...conversation];
@@ -923,83 +1136,6 @@ class AISdkNetworkTransformer {
923
1136
  };
924
1137
  }
925
1138
 
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;
997
- }
998
- }
999
- return message;
1000
- });
1001
- };
1002
-
1003
1139
  const useChat = ({ agentId, initializeMessages }) => {
1004
1140
  const [messages, setMessages] = react.useState(
1005
1141
  () => resolveInitialMessages(initializeMessages?.() || [])
@@ -1105,9 +1241,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1105
1241
  }
1106
1242
  await response.processDataStream({
1107
1243
  onChunk: async (chunk) => {
1108
- reactDom.flushSync(() => {
1109
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1110
- });
1244
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1111
1245
  onChunk?.(chunk);
1112
1246
  }
1113
1247
  });
@@ -1147,9 +1281,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1147
1281
  const transformer = new AISdkNetworkTransformer();
1148
1282
  await response.processDataStream({
1149
1283
  onChunk: async (chunk) => {
1150
- reactDom.flushSync(() => {
1151
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1152
- });
1284
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1153
1285
  onNetworkChunk?.(chunk);
1154
1286
  }
1155
1287
  });
@@ -1546,6 +1678,7 @@ exports.TooltipContentClass = TooltipContentClass;
1546
1678
  exports.TooltipTrigger = TooltipTrigger;
1547
1679
  exports.WorkflowIcon = WorkflowIcon;
1548
1680
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1681
+ exports.resolveToChildMessages = resolveToChildMessages;
1549
1682
  exports.toAssistantUIMessage = toAssistantUIMessage;
1550
1683
  exports.toUIMessage = toUIMessage;
1551
1684
  exports.useChat = useChat;