@mastra/playground-ui 6.5.1 → 6.6.0-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/dist/index.es.js CHANGED
@@ -47,7 +47,7 @@ import * as LabelPrimitive from '@radix-ui/react-label';
47
47
  import { ZodProvider, getFieldConfigInZodStack, getDefaultValueInZodStack } from '@autoform/zod/v4';
48
48
  import { z as z$1 } from 'zod/v3';
49
49
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
50
- import { useMastraClient, useChat, toAssistantUIMessage } from '@mastra/react';
50
+ import { useMastraClient, resolveToChildMessages, useChat, toAssistantUIMessage } from '@mastra/react';
51
51
  import { useQuery, useMutation, QueryClient, QueryClientProvider } from '@tanstack/react-query';
52
52
  import './index.css';export * from '@tanstack/react-query';
53
53
  import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
@@ -4350,11 +4350,12 @@ const useCodemirrorTheme$2 = () => {
4350
4350
  };
4351
4351
  const SyntaxHighlighter$2 = ({
4352
4352
  data,
4353
- className
4353
+ className,
4354
+ ...props
4354
4355
  }) => {
4355
4356
  const formattedCode = JSON.stringify(data, null, 2);
4356
4357
  const theme = useCodemirrorTheme$2();
4357
- return /* @__PURE__ */ jsxs("div", { className: clsx("rounded-md bg-surface4 p-1 font-mono relative", className), children: [
4358
+ return /* @__PURE__ */ jsxs("div", { className: clsx("rounded-md bg-surface4 p-1 font-mono relative", className), ...props, children: [
4358
4359
  /* @__PURE__ */ jsx(CopyButton, { content: formattedCode, className: "absolute top-2 right-2 z-20" }),
4359
4360
  /* @__PURE__ */ jsx(CodeMirror, { value: formattedCode, theme, extensions: [jsonLanguage] })
4360
4361
  ] });
@@ -4515,11 +4516,11 @@ const ToolBadge = ({ toolName, args, result, metadata, toolOutput }) => {
4515
4516
  let argSlot = null;
4516
4517
  try {
4517
4518
  const { __mastraMetadata: _, ...formattedArgs } = typeof args === "object" ? args : JSON.parse(args);
4518
- argSlot = /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: formattedArgs });
4519
+ argSlot = /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: formattedArgs, "data-testid": "tool-args" });
4519
4520
  } catch {
4520
4521
  argSlot = /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap", children: args });
4521
4522
  }
4522
- let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap bg-surface4 p-4 rounded-md", children: result }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: result });
4523
+ let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap bg-surface4 p-4 rounded-md", children: result }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: result, "data-testid": "tool-result" });
4523
4524
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
4524
4525
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
4525
4526
  return /* @__PURE__ */ jsx(
@@ -4546,7 +4547,7 @@ const ToolBadge = ({ toolName, args, result, metadata, toolOutput }) => {
4546
4547
  ] }),
4547
4548
  toolOutput.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
4548
4549
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool output" }),
4549
- /* @__PURE__ */ jsx("div", { className: "h-40 overflow-y-auto", children: /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: toolOutput }) })
4550
+ /* @__PURE__ */ jsx("div", { className: "h-40 overflow-y-auto", children: /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: toolOutput, "data-testid": "tool-output" }) })
4550
4551
  ] })
4551
4552
  ] })
4552
4553
  }
@@ -6606,12 +6607,16 @@ const SelectField$1 = ({ field, inputProps, error, id, value }) => {
6606
6607
 
6607
6608
  const ObjectWrapper = ({ label, children }) => {
6608
6609
  const hasLabel = label !== "​" && label !== "";
6610
+ const [isOpen, setIsOpen] = useState(false);
6609
6611
  return /* @__PURE__ */ jsxs("div", { className: "", children: [
6610
- hasLabel && /* @__PURE__ */ jsxs(Txt, { as: "h3", variant: "ui-sm", className: "text-icon3 flex items-center gap-1 pb-2", children: [
6611
- /* @__PURE__ */ jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsx(Braces, {}) }),
6612
- label
6612
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
6613
+ hasLabel && /* @__PURE__ */ jsxs(Txt, { as: "h3", variant: "ui-sm", className: "text-icon3 flex items-center gap-1 pb-2", children: [
6614
+ /* @__PURE__ */ jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsx(Braces, {}) }),
6615
+ label
6616
+ ] }),
6617
+ /* @__PURE__ */ jsx(Button$1, { onClick: () => setIsOpen(!isOpen), type: "button", className: "ml-auto", children: /* @__PURE__ */ jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("transition-all", isOpen ? "rotate-180" : "rotate-0") }) }) })
6613
6618
  ] }),
6614
- /* @__PURE__ */ jsx(
6619
+ isOpen && /* @__PURE__ */ jsx(
6615
6620
  "div",
6616
6621
  {
6617
6622
  className: hasLabel ? "flex flex-col gap-1 [&>*]:border-dashed [&>*]:border-l [&>*]:border-l-border1 [&>*]:pl-4" : "",
@@ -7757,7 +7762,46 @@ const EmptyWorkflowsTable = () => /* @__PURE__ */ jsx("div", { className: "flex
7757
7762
  }
7758
7763
  ) });
7759
7764
 
7760
- const WorkflowBadge = ({ workflow, runId, workflowId, isStreaming, metadata }) => {
7765
+ const LoadingBadge = () => {
7766
+ return /* @__PURE__ */ jsx(
7767
+ BadgeWrapper,
7768
+ {
7769
+ icon: /* @__PURE__ */ jsx(Spinner, { color: IconColors.icon3 }),
7770
+ title: /* @__PURE__ */ jsx(Skeleton, { className: "ml-2 w-12 h-2" }),
7771
+ collapsible: false
7772
+ }
7773
+ );
7774
+ };
7775
+
7776
+ const useInView = () => {
7777
+ const [inView, setInView] = useState(false);
7778
+ const setRef = useCallback((node) => {
7779
+ if (node) {
7780
+ const observer = new IntersectionObserver(([entry]) => {
7781
+ setInView(entry.isIntersecting);
7782
+ });
7783
+ observer.observe(node);
7784
+ return () => observer.disconnect();
7785
+ }
7786
+ }, []);
7787
+ return { inView, setRef };
7788
+ };
7789
+
7790
+ const useWorkflow = (workflowId) => {
7791
+ const client = useMastraClient();
7792
+ const { runtimeContext } = usePlaygroundStore();
7793
+ return useQuery({
7794
+ queryKey: ["workflow", workflowId],
7795
+ queryFn: () => workflowId ? client.getWorkflow(workflowId).details(runtimeContext) : null,
7796
+ enabled: Boolean(workflowId),
7797
+ retry: false,
7798
+ refetchOnWindowFocus: false,
7799
+ throwOnError: false
7800
+ });
7801
+ };
7802
+
7803
+ const WorkflowBadge = ({ runId, workflowId, isStreaming, metadata }) => {
7804
+ const { data: workflow, isLoading: isWorkflowLoading } = useWorkflow(workflowId);
7761
7805
  const { data: runs, isLoading: isRunsLoading } = useWorkflowRuns(workflowId, {
7762
7806
  enabled: Boolean(runId) && !isStreaming
7763
7807
  });
@@ -7766,6 +7810,7 @@ const WorkflowBadge = ({ workflow, runId, workflowId, isStreaming, metadata }) =
7766
7810
  const snapshot = typeof run?.snapshot === "object" ? run?.snapshot : void 0;
7767
7811
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
7768
7812
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
7813
+ if (isWorkflowLoading || !workflow) return /* @__PURE__ */ jsx(LoadingBadge, {});
7769
7814
  return /* @__PURE__ */ jsxs(
7770
7815
  BadgeWrapper,
7771
7816
  {
@@ -7792,7 +7837,7 @@ const WorkflowBadgeExtended = ({ workflowId, workflow, runId }) => {
7792
7837
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7793
7838
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pb-2", children: [
7794
7839
  /* @__PURE__ */ jsx(Button$1, { as: Link, href: `/workflows/${workflowId}/graph`, children: "Go to workflow" }),
7795
- /* @__PURE__ */ jsx(Button$1, { as: Link, href: `/workflows/${workflowId}/graph/${runId}`, children: "See run" })
7840
+ runId && /* @__PURE__ */ jsx(Button$1, { as: Link, href: `/workflows/${workflowId}/graph/${runId}`, children: "See run" })
7796
7841
  ] }),
7797
7842
  /* @__PURE__ */ jsx("div", { className: "rounded-md overflow-hidden h-[60vh] w-full", children: /* @__PURE__ */ jsx(WorkflowGraph, { workflowId, workflow }) })
7798
7843
  ] });
@@ -7805,30 +7850,6 @@ const useWorkflowStream = (workflowFullState) => {
7805
7850
  }, [workflowFullState]);
7806
7851
  };
7807
7852
 
7808
- const useWorkflow = (workflowId) => {
7809
- const client = useMastraClient();
7810
- const { runtimeContext } = usePlaygroundStore();
7811
- return useQuery({
7812
- queryKey: ["workflow", workflowId],
7813
- queryFn: () => workflowId ? client.getWorkflow(workflowId).details(runtimeContext) : null,
7814
- enabled: Boolean(workflowId),
7815
- retry: false,
7816
- refetchOnWindowFocus: false,
7817
- throwOnError: false
7818
- });
7819
- };
7820
-
7821
- const LoadingBadge = () => {
7822
- return /* @__PURE__ */ jsx(
7823
- BadgeWrapper,
7824
- {
7825
- icon: /* @__PURE__ */ jsx(Spinner, { color: IconColors.icon3 }),
7826
- title: /* @__PURE__ */ jsx(Skeleton, { className: "ml-2 w-12 h-2" }),
7827
- collapsible: false
7828
- }
7829
- );
7830
- };
7831
-
7832
7853
  const AgentBadge = ({ agentId, messages = [], metadata }) => {
7833
7854
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
7834
7855
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
@@ -7873,25 +7894,51 @@ const AgentBadge = ({ agentId, messages = [], metadata }) => {
7873
7894
  );
7874
7895
  };
7875
7896
 
7897
+ const useAgentMessages = ({
7898
+ threadId,
7899
+ agentId,
7900
+ memory
7901
+ }) => {
7902
+ const client = useMastraClient();
7903
+ return useQuery({
7904
+ queryKey: ["memory", "messages", threadId, agentId],
7905
+ queryFn: () => client.getThreadMessages(threadId, { agentId }),
7906
+ enabled: memory && Boolean(threadId),
7907
+ staleTime: 0,
7908
+ gcTime: 0,
7909
+ retry: false,
7910
+ refetchOnWindowFocus: false
7911
+ });
7912
+ };
7913
+
7914
+ const AgentBadgeWrapper = ({ agentId, result, metadata }) => {
7915
+ const { data: memoryMessages } = useAgentMessages({
7916
+ threadId: result?.subAgentThreadId ?? "",
7917
+ agentId,
7918
+ memory: true
7919
+ });
7920
+ const childMessages = result?.childMessages ?? resolveToChildMessages(memoryMessages?.uiMessages ?? []);
7921
+ return /* @__PURE__ */ jsx(AgentBadge, { agentId, messages: childMessages, metadata });
7922
+ };
7923
+
7876
7924
  const ToolFallback = ({ toolName, result, args, ...props }) => {
7877
7925
  return /* @__PURE__ */ jsx(WorkflowRunProvider, { children: /* @__PURE__ */ jsx(ToolFallbackInner, { toolName, result, args, ...props }) });
7878
7926
  };
7879
7927
  const ToolFallbackInner = ({ toolName, result, args, metadata, ...props }) => {
7928
+ const isAgent = metadata?.mode === "network" && metadata.from === "AGENT" || toolName.startsWith("agent-");
7929
+ const isWorkflow = metadata?.mode === "network" && metadata.from === "WORKFLOW" || toolName.startsWith("workflow-");
7930
+ const agentToolName = toolName.startsWith("agent-") ? toolName.substring("agent-".length) : toolName;
7931
+ const workflowToolName = toolName.startsWith("workflow-") ? toolName.substring("workflow-".length) : toolName;
7880
7932
  useWorkflowStream(result);
7881
- const { data: workflow, isLoading } = useWorkflow(toolName);
7882
- const isAgent = metadata?.mode === "network" && metadata.from === "AGENT";
7883
7933
  if (isAgent) {
7884
- const messages = result?.childMessages ?? [];
7885
- return /* @__PURE__ */ jsx(AgentBadge, { agentId: toolName, messages, metadata });
7934
+ return /* @__PURE__ */ jsx(AgentBadgeWrapper, { agentId: agentToolName, result, metadata });
7886
7935
  }
7887
- if (isLoading) return /* @__PURE__ */ jsx(LoadingBadge, {});
7888
- if (workflow) {
7936
+ if (isWorkflow) {
7889
7937
  const isStreaming = metadata?.mode === "stream" || metadata?.mode === "network";
7890
7938
  return /* @__PURE__ */ jsx(
7891
7939
  WorkflowBadge,
7892
7940
  {
7893
- workflowId: toolName,
7894
- workflow,
7941
+ workflowId: workflowToolName,
7895
7942
  isStreaming,
7896
7943
  runId: result?.runId,
7897
7944
  metadata
@@ -9108,7 +9155,7 @@ const Thread = ({ agentName, agentId, hasMemory, hasModelList }) => {
9108
9155
  ] });
9109
9156
  };
9110
9157
  const ThreadWrapper = ({ children }) => {
9111
- return /* @__PURE__ */ jsx(ThreadPrimitive.Root, { className: "grid grid-rows-[1fr_auto] h-full overflow-y-auto", children });
9158
+ return /* @__PURE__ */ jsx(ThreadPrimitive.Root, { className: "grid grid-rows-[1fr_auto] h-full overflow-y-auto", "data-testid": "thread-wrapper", children });
9112
9159
  };
9113
9160
  const ThreadWelcome = ({ agentName }) => {
9114
9161
  const safeAgentName = agentName ?? "";
@@ -9643,6 +9690,9 @@ function MastraRuntimeProvider({
9643
9690
  if (chunk.type === "tool-execution-end" && chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9644
9691
  refreshWorkingMemory?.();
9645
9692
  }
9693
+ if (chunk.type === "network-execution-event-step-finish") {
9694
+ refreshThreadList?.();
9695
+ }
9646
9696
  }
9647
9697
  });
9648
9698
  } else {
@@ -9656,6 +9706,7 @@ function MastraRuntimeProvider({
9656
9706
  modelSettings: modelSettingsArgs,
9657
9707
  signal: controller.signal
9658
9708
  });
9709
+ await refreshThreadList?.();
9659
9710
  return;
9660
9711
  } else {
9661
9712
  await sendMessage({
@@ -9666,6 +9717,9 @@ function MastraRuntimeProvider({
9666
9717
  threadId,
9667
9718
  modelSettings: modelSettingsArgs,
9668
9719
  onChunk: async (chunk) => {
9720
+ if (chunk.type === "finish") {
9721
+ await refreshThreadList?.();
9722
+ }
9669
9723
  if (chunk.type === "tool-result" && chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9670
9724
  refreshWorkingMemory?.();
9671
9725
  }
@@ -10061,15 +10115,36 @@ const AgentChat = ({
10061
10115
  agentId,
10062
10116
  agentName,
10063
10117
  threadId,
10064
- initialMessages,
10065
- initialLegacyMessages,
10066
10118
  memory,
10067
10119
  refreshThreadList,
10068
10120
  modelVersion,
10069
- modelList
10121
+ modelList,
10122
+ messageId
10070
10123
  }) => {
10071
10124
  const { settings } = useAgentSettings();
10072
10125
  const { runtimeContext } = usePlaygroundStore();
10126
+ const { data: messages, isLoading: isMessagesLoading } = useAgentMessages({
10127
+ agentId,
10128
+ threadId: threadId ?? "",
10129
+ memory: memory ?? false
10130
+ });
10131
+ useEffect(() => {
10132
+ if (messageId && messages && !isMessagesLoading) {
10133
+ setTimeout(() => {
10134
+ const messageElement = document.querySelector(`[data-message-id="${messageId}"]`);
10135
+ if (messageElement) {
10136
+ messageElement.scrollIntoView({ behavior: "smooth", block: "center" });
10137
+ messageElement.classList.add("bg-surface4");
10138
+ setTimeout(() => {
10139
+ messageElement.classList.remove("bg-surface4");
10140
+ }, 2e3);
10141
+ }
10142
+ }, 100);
10143
+ }
10144
+ }, [messageId, messages, isMessagesLoading]);
10145
+ if (isMessagesLoading) {
10146
+ return null;
10147
+ }
10073
10148
  return /* @__PURE__ */ jsx(
10074
10149
  MastraRuntimeProvider,
10075
10150
  {
@@ -10077,8 +10152,8 @@ const AgentChat = ({
10077
10152
  agentName,
10078
10153
  modelVersion,
10079
10154
  threadId,
10080
- initialMessages,
10081
- initialLegacyMessages,
10155
+ initialMessages: messages?.uiMessages || [],
10156
+ initialLegacyMessages: messages?.legacyMessages || [],
10082
10157
  memory,
10083
10158
  refreshThreadList,
10084
10159
  settings,
@@ -14016,7 +14091,7 @@ const ThreadLink = ({ children, as: Component = "a", href, className, prefetch,
14016
14091
  );
14017
14092
  };
14018
14093
  const ThreadList = ({ children }) => {
14019
- return /* @__PURE__ */ jsx("ol", { children });
14094
+ return /* @__PURE__ */ jsx("ol", { "data-testid": "thread-list", children });
14020
14095
  };
14021
14096
  const ThreadItem = ({ children, isActive, className }) => {
14022
14097
  return /* @__PURE__ */ jsx(
@@ -14413,7 +14488,7 @@ function TemplatesList({ templates, linkComponent, className, isLoading }) {
14413
14488
  "grid-cols-[8rem_1fr] lg:grid-cols-[12rem_1fr]": template.imageURL
14414
14489
  }),
14415
14490
  children: [
14416
- template.imageURL && /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden"), children: /* @__PURE__ */ jsx(
14491
+ template.imageURL && /* @__PURE__ */ jsx("div", { className: cn("overflow-hidden"), children: /* @__PURE__ */ jsx(
14417
14492
  "div",
14418
14493
  {
14419
14494
  className: "w-full h-full bg-cover thumb transition-scale duration-150",
@@ -17312,20 +17387,6 @@ function usePolling({
17312
17387
  };
17313
17388
  }
17314
17389
 
17315
- const useInView = () => {
17316
- const [inView, setInView] = useState(false);
17317
- const setRef = useCallback((node) => {
17318
- if (node) {
17319
- const observer = new IntersectionObserver(([entry]) => {
17320
- setInView(entry.isIntersecting);
17321
- });
17322
- observer.observe(node);
17323
- return () => observer.disconnect();
17324
- }
17325
- }, []);
17326
- return { inView, setRef };
17327
- };
17328
-
17329
17390
  const PlaygroundQueryClient = ({ children }) => {
17330
17391
  const queryClient = new QueryClient();
17331
17392
  return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });