@mastra/playground-ui 7.0.0-beta.11 → 7.0.0-beta.14

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
@@ -32,6 +32,7 @@ import { Highlight, themes } from 'prism-react-renderer';
32
32
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
33
33
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
34
34
  import { EditorView } from '@codemirror/view';
35
+ import { javascript } from '@codemirror/lang-javascript';
35
36
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
36
37
  import { format, isValid, formatDate, isToday } from 'date-fns';
37
38
  import { useDebouncedCallback, useThrottledCallback } from 'use-debounce';
@@ -4645,7 +4646,8 @@ const ToolBadge = ({
4645
4646
  metadata,
4646
4647
  toolOutput,
4647
4648
  toolCallId,
4648
- toolApprovalMetadata
4649
+ toolApprovalMetadata,
4650
+ suspendPayload
4649
4651
  }) => {
4650
4652
  let argSlot = null;
4651
4653
  try {
@@ -4655,6 +4657,7 @@ const ToolBadge = ({
4655
4657
  argSlot = /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: args });
4656
4658
  }
4657
4659
  let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: result }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: result, "data-testid": "tool-result" });
4660
+ let suspendPayloadSlot = typeof suspendPayload === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: suspendPayload }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: suspendPayload, "data-testid": "tool-suspend-payload" });
4658
4661
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
4659
4662
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
4660
4663
  const toolCalled = result || toolOutput.length > 0;
@@ -4671,12 +4674,16 @@ const ToolBadge = ({
4671
4674
  input: agentNetworkInput
4672
4675
  }
4673
4676
  ),
4674
- initialCollapsed: !!!toolApprovalMetadata,
4677
+ initialCollapsed: !!!(toolApprovalMetadata ?? suspendPayload),
4675
4678
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4676
4679
  /* @__PURE__ */ jsxs("div", { children: [
4677
4680
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool arguments" }),
4678
4681
  argSlot
4679
4682
  ] }),
4683
+ suspendPayloadSlot !== void 0 && suspendPayload && /* @__PURE__ */ jsxs("div", { children: [
4684
+ /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool suspend payload" }),
4685
+ suspendPayloadSlot
4686
+ ] }),
4680
4687
  resultSlot !== void 0 && result && /* @__PURE__ */ jsxs("div", { children: [
4681
4688
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool result" }),
4682
4689
  resultSlot
@@ -4993,7 +5000,8 @@ const useExecuteWorkflow = () => {
4993
5000
  requestContext.set(key, value);
4994
5001
  });
4995
5002
  const workflow = client.getWorkflow(workflowId);
4996
- await workflow.start({ runId, inputData: input || {}, requestContext });
5003
+ const run = await workflow.createRun({ runId });
5004
+ await run.start({ inputData: input || {}, requestContext });
4997
5005
  } catch (error) {
4998
5006
  console.error("Error starting workflow run:", error);
4999
5007
  throw error;
@@ -5013,7 +5021,8 @@ const useExecuteWorkflow = () => {
5013
5021
  requestContext.set(key, value);
5014
5022
  });
5015
5023
  const workflow = client.getWorkflow(workflowId);
5016
- const result = await workflow.startAsync({ runId, inputData: input || {}, requestContext });
5024
+ const run = await workflow.createRun({ runId });
5025
+ const result = await run.startAsync({ inputData: input || {}, requestContext });
5017
5026
  return result;
5018
5027
  } catch (error) {
5019
5028
  console.error("Error starting workflow run:", error);
@@ -5106,8 +5115,8 @@ const useStreamWorkflow = () => {
5106
5115
  requestContext.set(key, value);
5107
5116
  });
5108
5117
  const workflow = client.getWorkflow(workflowId);
5109
- const stream = await workflow.streamVNext({
5110
- runId,
5118
+ const run = await workflow.createRun({ runId });
5119
+ const stream = await run.streamVNext({
5111
5120
  inputData,
5112
5121
  requestContext,
5113
5122
  closeOnSuspend: true,
@@ -5169,7 +5178,8 @@ const useStreamWorkflow = () => {
5169
5178
  return;
5170
5179
  }
5171
5180
  const workflow = client.getWorkflow(workflowId);
5172
- const stream = await workflow.observeStreamVNext({ runId });
5181
+ const run = await workflow.createRun({ runId });
5182
+ const stream = await run.observeStreamVNext();
5173
5183
  if (!stream) {
5174
5184
  return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
5175
5185
  }
@@ -5227,8 +5237,8 @@ const useStreamWorkflow = () => {
5227
5237
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5228
5238
  requestContext.set(key, value);
5229
5239
  });
5230
- const stream = await workflow.resumeStreamVNext({
5231
- runId,
5240
+ const run = await workflow.createRun({ runId });
5241
+ const stream = await run.resumeStreamVNext({
5232
5242
  step,
5233
5243
  resumeData,
5234
5244
  requestContext,
@@ -5277,6 +5287,7 @@ const useStreamWorkflow = () => {
5277
5287
  mutationFn: async ({
5278
5288
  workflowId,
5279
5289
  requestContext: playgroundRequestContext,
5290
+ runId,
5280
5291
  ...params
5281
5292
  }) => {
5282
5293
  if (timeTravelStreamRef.current) {
@@ -5289,7 +5300,8 @@ const useStreamWorkflow = () => {
5289
5300
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5290
5301
  requestContext.set(key, value);
5291
5302
  });
5292
- const stream = await workflow.timeTravelStream({
5303
+ const run = await workflow.createRun({ runId });
5304
+ const stream = await run.timeTravelStream({
5293
5305
  ...params,
5294
5306
  requestContext,
5295
5307
  tracingOptions: settings?.tracingOptions
@@ -5380,7 +5392,9 @@ const useCancelWorkflowRun = () => {
5380
5392
  const cancelWorkflowRun = useMutation({
5381
5393
  mutationFn: async ({ workflowId, runId }) => {
5382
5394
  try {
5383
- const response = await client.getWorkflow(workflowId).cancelRun(runId);
5395
+ const workflow = client.getWorkflow(workflowId);
5396
+ const run = await workflow.createRun({ runId });
5397
+ const response = await run.cancelRun();
5384
5398
  return response;
5385
5399
  } catch (error) {
5386
5400
  console.error("Error canceling workflow run:", error);
@@ -5474,6 +5488,58 @@ const useDeleteWorkflowRun = (workflowId) => {
5474
5488
  });
5475
5489
  };
5476
5490
 
5491
+ const WorkflowStepDetailContext = createContext(null);
5492
+ function useWorkflowStepDetail() {
5493
+ const context = useContext(WorkflowStepDetailContext);
5494
+ if (!context) {
5495
+ throw new Error("useWorkflowStepDetail must be used within WorkflowStepDetailProvider");
5496
+ }
5497
+ return context;
5498
+ }
5499
+ function WorkflowStepDetailProvider({ children }) {
5500
+ const [stepDetail, setStepDetail] = useState(null);
5501
+ const showMapConfig = useCallback(
5502
+ ({ stepName, stepId, mapConfig }) => {
5503
+ setStepDetail({
5504
+ type: "map-config",
5505
+ stepName,
5506
+ stepId,
5507
+ mapConfig
5508
+ });
5509
+ },
5510
+ []
5511
+ );
5512
+ const showNestedGraph = useCallback(
5513
+ ({ label, stepGraph, fullStep }) => {
5514
+ setStepDetail({
5515
+ type: "nested-graph",
5516
+ stepName: label,
5517
+ nestedGraph: {
5518
+ label,
5519
+ stepGraph,
5520
+ fullStep
5521
+ }
5522
+ });
5523
+ },
5524
+ []
5525
+ );
5526
+ const closeStepDetail = useCallback(() => {
5527
+ setStepDetail(null);
5528
+ }, []);
5529
+ return /* @__PURE__ */ jsx(
5530
+ WorkflowStepDetailContext.Provider,
5531
+ {
5532
+ value: {
5533
+ stepDetail,
5534
+ showMapConfig,
5535
+ showNestedGraph,
5536
+ closeStepDetail
5537
+ },
5538
+ children
5539
+ }
5540
+ );
5541
+ }
5542
+
5477
5543
  const WorkflowRunContext = createContext({});
5478
5544
  function WorkflowRunProvider({
5479
5545
  children,
@@ -5575,7 +5641,7 @@ function WorkflowRunProvider({
5575
5641
  isLoadingRunExecutionResult,
5576
5642
  withoutTimeTravel
5577
5643
  },
5578
- children
5644
+ children: /* @__PURE__ */ jsx(WorkflowStepDetailProvider, { children })
5579
5645
  }
5580
5646
  );
5581
5647
  }
@@ -6234,26 +6300,46 @@ const SyntaxHighlighter$1 = ({ data }) => {
6234
6300
  return /* @__PURE__ */ jsx("div", { className: "rounded-md bg-[#1a1a1a] p-1 font-mono", children: /* @__PURE__ */ jsx(CodeMirror, { value: formattedCode, theme, extensions: [jsonLanguage] }) });
6235
6301
  };
6236
6302
 
6237
- const CodeDialogContent = ({ data }) => {
6303
+ const CodeDialogContent = ({
6304
+ data,
6305
+ language = "auto"
6306
+ }) => {
6238
6307
  const theme = useCodemirrorTheme$1();
6308
+ const getExtensions = (content) => {
6309
+ if (language === "javascript") {
6310
+ return [javascript(), EditorView.lineWrapping];
6311
+ }
6312
+ if (language === "json") {
6313
+ return [jsonLanguage, EditorView.lineWrapping];
6314
+ }
6315
+ try {
6316
+ JSON.parse(content);
6317
+ return [jsonLanguage, EditorView.lineWrapping];
6318
+ } catch {
6319
+ if (content.includes("=>") || content.includes("function") || content.includes("const ") || content.includes("return ")) {
6320
+ return [javascript(), EditorView.lineWrapping];
6321
+ }
6322
+ return [EditorView.lineWrapping];
6323
+ }
6324
+ };
6239
6325
  if (typeof data !== "string") {
6326
+ const content = JSON.stringify(data, null, 2);
6240
6327
  return /* @__PURE__ */ jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6241
- /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsx(CopyButton, { content: JSON.stringify(data, null, 2) }) }),
6242
- /* @__PURE__ */ jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsx(CodeMirror, { value: JSON.stringify(data, null, 2), theme, extensions: [jsonLanguage] }) })
6328
+ /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsx(CopyButton, { content }) }),
6329
+ /* @__PURE__ */ jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsx(CodeMirror, { value: content, theme, extensions: [jsonLanguage, EditorView.lineWrapping] }) })
6243
6330
  ] });
6244
6331
  }
6332
+ const extensions = getExtensions(data);
6333
+ let displayContent = data;
6245
6334
  try {
6246
6335
  const json = JSON.parse(data);
6247
- return /* @__PURE__ */ jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6248
- /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsx(CopyButton, { content: data }) }),
6249
- /* @__PURE__ */ jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsx(CodeMirror, { value: JSON.stringify(json, null, 2), theme, extensions: [jsonLanguage] }) })
6250
- ] });
6251
- } catch (error) {
6252
- return /* @__PURE__ */ jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6253
- /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsx(CopyButton, { content: data }) }),
6254
- /* @__PURE__ */ jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsx(CodeMirror, { value: data, theme, extensions: [] }) })
6255
- ] });
6336
+ displayContent = JSON.stringify(json, null, 2);
6337
+ } catch {
6256
6338
  }
6339
+ return /* @__PURE__ */ jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6340
+ /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsx(CopyButton, { content: data }) }),
6341
+ /* @__PURE__ */ jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsx(CodeMirror, { value: displayContent, theme, extensions }) })
6342
+ ] });
6257
6343
  };
6258
6344
 
6259
6345
  const Form = React__default.forwardRef(({ children, ...props }, ref) => {
@@ -7767,9 +7853,9 @@ const WorkflowTimeTravelForm = ({ stepKey, closeModal }) => {
7767
7853
  const parsedResume = resumeData.trim() ? JSON.parse(resumeData) : {};
7768
7854
  const parsedContext = contextValue.trim() ? JSON.parse(contextValue) : {};
7769
7855
  const parsedNestedContext = nestedContextValue.trim() ? JSON.parse(nestedContextValue) : {};
7770
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
7856
+ const run = await createWorkflowRun({ workflowId, prevRunId });
7771
7857
  const payload = {
7772
- runId,
7858
+ runId: run.runId,
7773
7859
  workflowId,
7774
7860
  step: stepKey,
7775
7861
  inputData: data,
@@ -7881,12 +7967,29 @@ const WorkflowStepActionBar = ({
7881
7967
  const [isResumeDataOpen, setIsResumeDataOpen] = useState(false);
7882
7968
  const [isErrorOpen, setIsErrorOpen] = useState(false);
7883
7969
  const [isTripwireOpen, setIsTripwireOpen] = useState(false);
7884
- const [isMapConfigOpen, setIsMapConfigOpen] = useState(false);
7885
7970
  const [isTimeTravelOpen, setIsTimeTravelOpen] = useState(false);
7886
7971
  const { withoutTimeTravel } = useContext(WorkflowRunContext);
7972
+ const { showMapConfig, stepDetail, closeStepDetail } = useWorkflowStepDetail();
7887
7973
  const dialogContentClass = "bg-surface2 rounded-lg border-sm border-border1 max-w-4xl w-full px-0";
7888
7974
  const dialogTitleClass = "border-b-sm border-border1 pb-4 px-6";
7889
7975
  const showTimeTravel = !withoutTimeTravel && stepKey && !mapConfig;
7976
+ const isMapConfigOpen = stepDetail?.type === "map-config" && stepDetail?.stepName === stepName;
7977
+ const isNestedGraphOpen = stepDetail?.type === "nested-graph" && stepDetail?.stepName === stepName;
7978
+ const activeButtonClass = "ring-2 ring-accent1 ring-offset-1 ring-offset-transparent";
7979
+ const handleMapConfigClick = () => {
7980
+ if (isMapConfigOpen) {
7981
+ closeStepDetail();
7982
+ } else {
7983
+ showMapConfig({ stepName, stepId, mapConfig });
7984
+ }
7985
+ };
7986
+ const handleNestedGraphClick = () => {
7987
+ if (isNestedGraphOpen) {
7988
+ closeStepDetail();
7989
+ } else {
7990
+ onShowNestedGraph?.();
7991
+ }
7992
+ };
7890
7993
  return /* @__PURE__ */ jsx(Fragment, { children: (input || output || error || tripwire || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxs(
7891
7994
  "div",
7892
7995
  {
@@ -7900,7 +8003,7 @@ const WorkflowStepActionBar = ({
7900
8003
  status === "running" && "bg-accent6Dark"
7901
8004
  ),
7902
8005
  children: [
7903
- onShowNestedGraph && /* @__PURE__ */ jsx(Button$1, { onClick: onShowNestedGraph, children: "View nested graph" }),
8006
+ onShowNestedGraph && /* @__PURE__ */ jsx(Button$1, { onClick: handleNestedGraphClick, className: cn(isNestedGraphOpen && activeButtonClass), children: "View nested graph" }),
7904
8007
  showTimeTravel && /* @__PURE__ */ jsxs(Fragment, { children: [
7905
8008
  /* @__PURE__ */ jsx(Button$1, { onClick: () => setIsTimeTravelOpen(true), children: "Time travel" }),
7906
8009
  /* @__PURE__ */ jsx(Dialog, { open: isTimeTravelOpen, onOpenChange: setIsTimeTravelOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -7911,19 +8014,7 @@ const WorkflowStepActionBar = ({
7911
8014
  /* @__PURE__ */ jsx("div", { className: "px-4 overflow-scroll max-h-[600px]", children: /* @__PURE__ */ jsx(WorkflowTimeTravelForm, { stepKey, closeModal: () => setIsTimeTravelOpen(false) }) })
7912
8015
  ] }) })
7913
8016
  ] }),
7914
- mapConfig && /* @__PURE__ */ jsxs(Fragment, { children: [
7915
- /* @__PURE__ */ jsx(Button$1, { onClick: () => setIsMapConfigOpen(true), children: "Map config" }),
7916
- /* @__PURE__ */ jsx(Dialog, { open: isMapConfigOpen, onOpenChange: setIsMapConfigOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: dialogContentClass, children: [
7917
- /* @__PURE__ */ jsx(DialogTitle, { className: dialogTitleClass, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
7918
- /* @__PURE__ */ jsxs("div", { children: [
7919
- stepName,
7920
- " Map Config"
7921
- ] }),
7922
- stepId && stepId !== stepName && /* @__PURE__ */ jsx("div", { className: "text-xs text-icon3 font-normal", children: stepId })
7923
- ] }) }),
7924
- /* @__PURE__ */ jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsx(CodeDialogContent, { data: mapConfig }) })
7925
- ] }) })
7926
- ] }),
8017
+ mapConfig && /* @__PURE__ */ jsx(Button$1, { onClick: handleMapConfigClick, className: cn(isMapConfigOpen && activeButtonClass), children: "Map config" }),
7927
8018
  input && /* @__PURE__ */ jsxs(Fragment, { children: [
7928
8019
  /* @__PURE__ */ jsx(Button$1, { onClick: () => setIsInputOpen(true), children: "Input" }),
7929
8020
  /* @__PURE__ */ jsx(Dialog, { open: isInputOpen, onOpenChange: setIsInputOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -8065,7 +8156,7 @@ function WorkflowConditionNode({ data }) {
8065
8156
  "pre",
8066
8157
  {
8067
8158
  className: cn(
8068
- "relative font-mono p-3 w-full cursor-pointer rounded-lg text-xs !bg-surface4 overflow-scroll",
8159
+ "relative font-mono p-3 w-full cursor-pointer rounded-lg text-xs !bg-surface4 whitespace-pre-wrap break-words",
8069
8160
  className,
8070
8161
  previousDisplayStatus === "success" && nextStep && "!bg-accent1Dark",
8071
8162
  previousDisplayStatus === "failed" && nextStep && "!bg-accent2Dark",
@@ -8318,172 +8409,29 @@ function WorkflowLoopResultNode({ data }) {
8318
8409
  );
8319
8410
  }
8320
8411
 
8321
- function Spinner({ color = "#fff", className }) {
8322
- return /* @__PURE__ */ jsx(
8323
- "svg",
8324
- {
8325
- className: clsx("animate-spin duration-700", className),
8326
- xmlns: "http://www.w3.org/2000/svg",
8327
- width: "24",
8328
- height: "24",
8329
- viewBox: "0 0 24 24",
8330
- fill: "none",
8331
- stroke: "currentColor",
8332
- strokeWidth: "2",
8333
- strokeLinecap: "round",
8334
- strokeLinejoin: "round",
8335
- children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
8336
- }
8337
- );
8338
- }
8339
-
8340
- const Slider = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
8341
- SliderPrimitive.Root,
8342
- {
8343
- ref,
8344
- className: cn("relative flex w-full touch-none select-none items-center", className),
8345
- ...props,
8346
- children: [
8347
- /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary/50" }) }),
8348
- /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-white shadow transition-colors disabled:pointer-events-none disabled:opacity-50" })
8349
- ]
8350
- }
8351
- ));
8352
- Slider.displayName = SliderPrimitive.Root.displayName;
8353
-
8354
- const ZoomSlider = forwardRef(({ className, ...props }) => {
8355
- const { zoom } = useViewport();
8356
- const { zoomTo, zoomIn, zoomOut, fitView } = useReactFlow();
8357
- return /* @__PURE__ */ jsxs(Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
8358
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" }) }),
8359
- /* @__PURE__ */ jsx(
8360
- Slider,
8361
- {
8362
- className: "w-[140px]",
8363
- value: [zoom],
8364
- min: 0.01,
8365
- max: 1,
8366
- step: 0.01,
8367
- onValueChange: (values) => {
8368
- zoomTo(values[0]);
8369
- }
8370
- }
8371
- ),
8372
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }) }),
8373
- /* @__PURE__ */ jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
8374
- (100 * zoom).toFixed(0),
8375
- "%"
8376
- ] }),
8377
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsx(Maximize, { className: "h-4 w-4" }) })
8378
- ] });
8379
- });
8380
- ZoomSlider.displayName = "ZoomSlider";
8381
-
8382
- function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
8383
- const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
8384
- stepGraph
8385
- });
8386
- const [isMounted, setIsMounted] = useState(false);
8387
- const [nodes, _, onNodesChange] = useNodesState(initialNodes);
8388
- const [edges] = useEdgesState(initialEdges);
8389
- const { steps } = useCurrentRun();
8390
- const nodeTypes = {
8391
- "default-node": (props) => /* @__PURE__ */ jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
8392
- "condition-node": WorkflowConditionNode,
8393
- "after-node": WorkflowAfterNode,
8394
- "loop-result-node": WorkflowLoopResultNode,
8395
- "nested-node": (props) => /* @__PURE__ */ jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
8396
- };
8397
- useEffect(() => {
8398
- if (open) {
8399
- setTimeout(() => {
8400
- setIsMounted(true);
8401
- }, 500);
8402
- }
8403
- }, [open]);
8404
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxs(
8405
- ReactFlow,
8406
- {
8407
- nodes,
8408
- edges: edges.map((e) => ({
8409
- ...e,
8410
- style: {
8411
- ...e.style,
8412
- stroke: steps[`${workflowName}.${e.data?.previousStepId}`]?.status === "success" && steps[`${workflowName}.${e.data?.nextStepId}`] ? "#22c55e" : e.data?.conditionNode && !steps[`${workflowName}.${e.data?.previousStepId}`] && Boolean(steps[`${workflowName}.${e.data?.nextStepId}`]?.status) ? "#22c55e" : void 0
8413
- }
8414
- })),
8415
- fitView: true,
8416
- fitViewOptions: {
8417
- maxZoom: 1
8418
- },
8419
- minZoom: 0.01,
8420
- maxZoom: 1,
8421
- nodeTypes,
8422
- onNodesChange,
8423
- children: [
8424
- /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
8425
- /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
8426
- ]
8427
- }
8428
- ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
8429
- }
8430
-
8431
8412
  const WorkflowNestedGraphContext = createContext(
8432
8413
  {}
8433
8414
  );
8434
8415
  function WorkflowNestedGraphProvider({ children }) {
8435
- const [stepGraph, setStepGraph] = useState(null);
8436
- const [parentStepGraphList, setParentStepGraphList] = useState([]);
8437
- const [openDialog, setOpenDialog] = useState(false);
8438
- const [label, setLabel] = useState("");
8439
- const [fullStep, setFullStep] = useState("");
8440
- const closeNestedGraph = () => {
8441
- if (parentStepGraphList.length) {
8442
- const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
8443
- setStepGraph(lastStepGraph.stepGraph);
8444
- setLabel(lastStepGraph.label);
8445
- setFullStep(lastStepGraph.fullStep);
8446
- setParentStepGraphList(parentStepGraphList.slice(0, -1));
8447
- } else {
8448
- setOpenDialog(false);
8449
- setStepGraph(null);
8450
- setLabel("");
8451
- setFullStep("");
8452
- }
8453
- };
8416
+ const { showNestedGraph: showNestedGraphInPanel, closeStepDetail } = useWorkflowStepDetail();
8454
8417
  const showNestedGraph = ({
8455
- label: newLabel,
8456
- stepGraph: newStepGraph,
8457
- fullStep: newFullStep
8418
+ label,
8419
+ stepGraph,
8420
+ fullStep
8458
8421
  }) => {
8459
- if (stepGraph) {
8460
- setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
8461
- }
8462
- setLabel(newLabel);
8463
- setFullStep(newFullStep);
8464
- setStepGraph(newStepGraph);
8465
- setOpenDialog(true);
8422
+ showNestedGraphInPanel({ label, stepGraph, fullStep });
8466
8423
  };
8467
- return /* @__PURE__ */ jsxs(
8424
+ const closeNestedGraph = () => {
8425
+ closeStepDetail();
8426
+ };
8427
+ return /* @__PURE__ */ jsx(
8468
8428
  WorkflowNestedGraphContext.Provider,
8469
8429
  {
8470
8430
  value: {
8471
8431
  showNestedGraph,
8472
8432
  closeNestedGraph
8473
8433
  },
8474
- children: [
8475
- children,
8476
- /* @__PURE__ */ jsx(Dialog, { open: openDialog, onOpenChange: closeNestedGraph, children: /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[45rem] h-[45rem] max-w-[unset] bg-[#121212] p-[0.5rem]", children: [
8477
- /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
8478
- /* @__PURE__ */ jsx(Workflow, { className: "text-current w-4 h-4" }),
8479
- /* @__PURE__ */ jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
8480
- label,
8481
- " workflow"
8482
- ] })
8483
- ] }),
8484
- /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(WorkflowNestedGraph, { stepGraph, open: openDialog, workflowName: fullStep }) })
8485
- ] }) }) }, `${label}-${fullStep}`)
8486
- ]
8434
+ children
8487
8435
  }
8488
8436
  );
8489
8437
  }
@@ -8582,6 +8530,48 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8582
8530
  ] });
8583
8531
  }
8584
8532
 
8533
+ const Slider = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
8534
+ SliderPrimitive.Root,
8535
+ {
8536
+ ref,
8537
+ className: cn("relative flex w-full touch-none select-none items-center", className),
8538
+ ...props,
8539
+ children: [
8540
+ /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary/50" }) }),
8541
+ /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-white shadow transition-colors disabled:pointer-events-none disabled:opacity-50" })
8542
+ ]
8543
+ }
8544
+ ));
8545
+ Slider.displayName = SliderPrimitive.Root.displayName;
8546
+
8547
+ const ZoomSlider = forwardRef(({ className, ...props }) => {
8548
+ const { zoom } = useViewport();
8549
+ const { zoomTo, zoomIn, zoomOut, fitView } = useReactFlow();
8550
+ return /* @__PURE__ */ jsxs(Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
8551
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" }) }),
8552
+ /* @__PURE__ */ jsx(
8553
+ Slider,
8554
+ {
8555
+ className: "w-[140px]",
8556
+ value: [zoom],
8557
+ min: 0.01,
8558
+ max: 1,
8559
+ step: 0.01,
8560
+ onValueChange: (values) => {
8561
+ zoomTo(values[0]);
8562
+ }
8563
+ }
8564
+ ),
8565
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }) }),
8566
+ /* @__PURE__ */ jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
8567
+ (100 * zoom).toFixed(0),
8568
+ "%"
8569
+ ] }),
8570
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsx(Maximize, { className: "h-4 w-4" }) })
8571
+ ] });
8572
+ });
8573
+ ZoomSlider.displayName = "ZoomSlider";
8574
+
8585
8575
  function WorkflowGraphInner({ workflow }) {
8586
8576
  const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
8587
8577
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
@@ -8790,11 +8780,11 @@ function WorkflowTrigger({
8790
8780
  setIsRunning(true);
8791
8781
  setCancelResponse(null);
8792
8782
  setResult(null);
8793
- const { runId } = await createWorkflowRun({ workflowId });
8794
- setRunId?.(runId);
8795
- setInnerRunId(runId);
8796
- setContextRunId(runId);
8797
- streamWorkflow({ workflowId, runId, inputData: data, requestContext });
8783
+ const run = await createWorkflowRun({ workflowId });
8784
+ setRunId?.(run.runId);
8785
+ setInnerRunId(run.runId);
8786
+ setContextRunId(run.runId);
8787
+ streamWorkflow({ workflowId, runId: run.runId, inputData: data, requestContext });
8798
8788
  } catch (err) {
8799
8789
  setIsRunning(false);
8800
8790
  toast$1.error("Error executing workflow");
@@ -8804,10 +8794,10 @@ function WorkflowTrigger({
8804
8794
  if (!workflow) return;
8805
8795
  setCancelResponse(null);
8806
8796
  const { stepId, runId: prevRunId, resumeData } = step;
8807
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
8797
+ const run = await createWorkflowRun({ workflowId, prevRunId });
8808
8798
  await resumeWorkflow({
8809
8799
  step: stepId,
8810
- runId,
8800
+ runId: run.runId,
8811
8801
  resumeData,
8812
8802
  workflowId,
8813
8803
  requestContext
@@ -8851,7 +8841,7 @@ function WorkflowTrigger({
8851
8841
  const workflowActivePaths = streamResultToUse?.steps ?? {};
8852
8842
  const hasWorkflowActivePaths = Object.values(workflowActivePaths).length > 0;
8853
8843
  const doneStatuses = ["success", "failed", "canceled", "tripwire"];
8854
- return /* @__PURE__ */ jsxs("div", { className: "h-full pt-3 pb-12 overflow-y-auto", children: [
8844
+ return /* @__PURE__ */ jsxs("div", { className: "h-full pt-3 overflow-y-auto", children: [
8855
8845
  /* @__PURE__ */ jsxs("div", { className: "space-y-4 px-5 pb-5 border-b-sm border-border1", children: [
8856
8846
  isSuspendedSteps && isStreamingWorkflow && /* @__PURE__ */ jsxs("div", { className: "py-2 px-5 flex items-center gap-2 bg-surface5 -mx-5 -mt-5 border-b-sm border-border1", children: [
8857
8847
  /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Loader2, { className: "animate-spin text-icon6" }) }),
@@ -8934,12 +8924,16 @@ function WorkflowTrigger({
8934
8924
  const { status } = step;
8935
8925
  let output = void 0;
8936
8926
  let suspendOutput = void 0;
8927
+ let error = void 0;
8937
8928
  if (step.status === "suspended") {
8938
8929
  suspendOutput = step.suspendOutput;
8939
8930
  }
8940
8931
  if (step.status === "success") {
8941
8932
  output = step.output;
8942
8933
  }
8934
+ if (step.status === "failed") {
8935
+ error = step.error;
8936
+ }
8943
8937
  const tripwireInfo = step.status === "failed" && step.tripwire ? step.tripwire : streamResultToUse?.status === "tripwire" ? {
8944
8938
  reason: streamResultToUse?.tripwire?.reason,
8945
8939
  retry: streamResultToUse?.tripwire?.retry,
@@ -8952,7 +8946,7 @@ function WorkflowTrigger({
8952
8946
  {
8953
8947
  stepId,
8954
8948
  status: displayStatus,
8955
- result: output ?? suspendOutput ?? {},
8949
+ result: output ?? suspendOutput ?? error ?? {},
8956
8950
  tripwire: tripwireInfo
8957
8951
  },
8958
8952
  stepId
@@ -9335,18 +9329,17 @@ const columns$4 = [
9335
9329
  }
9336
9330
  ];
9337
9331
 
9338
- const themeClasses = {
9339
- light: "bg-gray-100 border-gray-300 text-gray-700",
9340
- dark: "bg-surface4 border-border1 text-icon6"
9341
- };
9342
- const Kbd = ({ children, theme = "dark" }) => {
9343
- const themeClass = themeClasses[theme];
9344
- return /* @__PURE__ */ jsx("kbd", { className: clsx("border-sm rounded-md px-1 py-0.5 font-mono", themeClass), children });
9345
- };
9346
-
9347
- const Searchbar = ({ onSearch, label, placeholder }) => {
9332
+ const Searchbar = ({ onSearch, label, placeholder, debounceMs = 300 }) => {
9348
9333
  const id = useId();
9349
9334
  const inputRef = useRef(null);
9335
+ const debouncedSearch = useDebouncedCallback((value) => {
9336
+ onSearch(value);
9337
+ }, debounceMs);
9338
+ useEffect(() => {
9339
+ return () => {
9340
+ debouncedSearch.cancel();
9341
+ };
9342
+ }, [debouncedSearch]);
9350
9343
  useEffect(() => {
9351
9344
  const input = inputRef.current;
9352
9345
  if (!input) return;
@@ -9361,37 +9354,27 @@ const Searchbar = ({ onSearch, label, placeholder }) => {
9361
9354
  window.removeEventListener("keydown", handleKeyDown);
9362
9355
  };
9363
9356
  }, []);
9364
- const handleSubmit = (e) => {
9365
- e.preventDefault();
9366
- const formData = new FormData(e.target);
9367
- const search = formData.get(id);
9368
- onSearch(search);
9357
+ const handleChange = (e) => {
9358
+ debouncedSearch(e.target.value);
9369
9359
  };
9370
- return /* @__PURE__ */ jsxs(
9371
- "form",
9372
- {
9373
- onSubmit: handleSubmit,
9374
- className: "focus-within:outline focus-within:outline-accent1 -outline-offset-2 border-sm border-icon-3 flex h-8 w-full items-center gap-2 overflow-hidden rounded-lg pl-2 pr-1",
9375
- children: [
9376
- /* @__PURE__ */ jsx(SearchIcon, { className: "text-icon3 h-4 w-4" }),
9377
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
9378
- /* @__PURE__ */ jsx("label", { htmlFor: id, className: "sr-only", children: label }),
9379
- /* @__PURE__ */ jsx(
9380
- "input",
9381
- {
9382
- id,
9383
- type: "text",
9384
- placeholder,
9385
- className: "bg-surface2 text-ui-md placeholder:text-icon-3 block h-8 w-full px-2 outline-none",
9386
- name: id,
9387
- ref: inputRef
9388
- }
9389
- )
9390
- ] }),
9391
- /* @__PURE__ */ jsx("button", { type: "submit", className: "text-ui-sm text-icon3 flex flex-row items-center gap-1", children: /* @__PURE__ */ jsx(Kbd, { children: "↵ Enter" }) })
9392
- ]
9393
- }
9394
- );
9360
+ return /* @__PURE__ */ jsxs("div", { className: "focus-within:outline focus-within:outline-accent1 -outline-offset-2 border-sm border-icon-3 flex h-8 w-full items-center gap-2 overflow-hidden rounded-lg pl-2 pr-1", children: [
9361
+ /* @__PURE__ */ jsx(SearchIcon, { className: "text-icon3 h-4 w-4" }),
9362
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
9363
+ /* @__PURE__ */ jsx("label", { htmlFor: id, className: "sr-only", children: label }),
9364
+ /* @__PURE__ */ jsx(
9365
+ "input",
9366
+ {
9367
+ id,
9368
+ type: "text",
9369
+ placeholder,
9370
+ className: "bg-surface2 text-ui-md placeholder:text-icon-3 block h-8 w-full px-2 outline-none",
9371
+ name: id,
9372
+ ref: inputRef,
9373
+ onChange: handleChange
9374
+ }
9375
+ )
9376
+ ] })
9377
+ ] });
9395
9378
  };
9396
9379
  const SearchbarWrapper = ({ children }) => {
9397
9380
  return /* @__PURE__ */ jsx("div", { className: "px-4 py-2 border-b-sm border-border1", children });
@@ -9521,14 +9504,28 @@ const PlaygroundTabs = ({
9521
9504
  const TabList$1 = ({ children, className }) => {
9522
9505
  return /* @__PURE__ */ jsx("div", { className: cn("w-full overflow-x-auto", className), children: /* @__PURE__ */ jsx(TabsList, { className: "border-b border-border1 flex min-w-full shrink-0", children }) });
9523
9506
  };
9524
- const Tab$1 = ({ children, value, onClick }) => {
9525
- return /* @__PURE__ */ jsx(
9507
+ const Tab$1 = ({ children, value, onClick, onClose }) => {
9508
+ return /* @__PURE__ */ jsxs(
9526
9509
  TabsTrigger,
9527
9510
  {
9528
9511
  value,
9529
- className: "text-xs p-3 text-mastra-el-3 data-[state=active]:text-mastra-el-5 data-[state=active]:border-b-2 whitespace-nowrap flex-shrink-0",
9512
+ className: "text-xs p-3 text-mastra-el-3 data-[state=active]:text-mastra-el-5 data-[state=active]:border-b-2 whitespace-nowrap flex-shrink-0 flex items-center gap-1.5",
9530
9513
  onClick,
9531
- children
9514
+ children: [
9515
+ children,
9516
+ onClose && /* @__PURE__ */ jsx(
9517
+ "button",
9518
+ {
9519
+ onClick: (e) => {
9520
+ e.stopPropagation();
9521
+ onClose();
9522
+ },
9523
+ className: "p-0.5 hover:bg-surface3 rounded transition-colors",
9524
+ "aria-label": "Close tab",
9525
+ children: /* @__PURE__ */ jsx(X, { className: "w-3 h-3" })
9526
+ }
9527
+ )
9528
+ ]
9532
9529
  }
9533
9530
  );
9534
9531
  };
@@ -9569,7 +9566,114 @@ const TracingRunOptions = () => {
9569
9566
  }
9570
9567
  )
9571
9568
  ] });
9572
- };
9569
+ };
9570
+
9571
+ function Spinner({ color = "#fff", className }) {
9572
+ return /* @__PURE__ */ jsx(
9573
+ "svg",
9574
+ {
9575
+ className: clsx("animate-spin duration-700", className),
9576
+ xmlns: "http://www.w3.org/2000/svg",
9577
+ width: "24",
9578
+ height: "24",
9579
+ viewBox: "0 0 24 24",
9580
+ fill: "none",
9581
+ stroke: "currentColor",
9582
+ strokeWidth: "2",
9583
+ strokeLinecap: "round",
9584
+ strokeLinejoin: "round",
9585
+ children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
9586
+ }
9587
+ );
9588
+ }
9589
+
9590
+ function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
9591
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
9592
+ stepGraph
9593
+ });
9594
+ const [isMounted, setIsMounted] = useState(false);
9595
+ const [nodes, _, onNodesChange] = useNodesState(initialNodes);
9596
+ const [edges] = useEdgesState(initialEdges);
9597
+ const { steps } = useCurrentRun();
9598
+ const nodeTypes = {
9599
+ "default-node": (props) => /* @__PURE__ */ jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
9600
+ "condition-node": WorkflowConditionNode,
9601
+ "after-node": WorkflowAfterNode,
9602
+ "loop-result-node": WorkflowLoopResultNode,
9603
+ "nested-node": (props) => /* @__PURE__ */ jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
9604
+ };
9605
+ useEffect(() => {
9606
+ if (open) {
9607
+ setTimeout(() => {
9608
+ setIsMounted(true);
9609
+ }, 500);
9610
+ }
9611
+ }, [open]);
9612
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxs(
9613
+ ReactFlow,
9614
+ {
9615
+ nodes,
9616
+ edges: edges.map((e) => ({
9617
+ ...e,
9618
+ style: {
9619
+ ...e.style,
9620
+ stroke: steps[`${workflowName}.${e.data?.previousStepId}`]?.status === "success" && steps[`${workflowName}.${e.data?.nextStepId}`] ? "#22c55e" : e.data?.conditionNode && !steps[`${workflowName}.${e.data?.previousStepId}`] && Boolean(steps[`${workflowName}.${e.data?.nextStepId}`]?.status) ? "#22c55e" : void 0
9621
+ }
9622
+ })),
9623
+ fitView: true,
9624
+ fitViewOptions: {
9625
+ maxZoom: 1
9626
+ },
9627
+ minZoom: 0.01,
9628
+ maxZoom: 1,
9629
+ nodeTypes,
9630
+ onNodesChange,
9631
+ children: [
9632
+ /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
9633
+ /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
9634
+ ]
9635
+ }
9636
+ ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
9637
+ }
9638
+
9639
+ function WorkflowStepDetailContent() {
9640
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9641
+ if (!stepDetail) {
9642
+ return null;
9643
+ }
9644
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
9645
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b-sm border-border1 bg-surface1", children: [
9646
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
9647
+ stepDetail.type === "map-config" && /* @__PURE__ */ jsx(List, { className: "w-4 h-4", style: { color: BADGE_COLORS.map } }),
9648
+ stepDetail.type === "nested-graph" && /* @__PURE__ */ jsx(WorkflowIcon, { className: "w-4 h-4", style: { color: BADGE_COLORS.workflow } }),
9649
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
9650
+ /* @__PURE__ */ jsx(Txt, { variant: "ui-md", className: "text-icon6 font-medium", children: stepDetail.type === "map-config" ? `${stepDetail.stepName} Config` : `${stepDetail.stepName} Workflow` }),
9651
+ stepDetail.type === "map-config" && stepDetail.stepId && stepDetail.stepId !== stepDetail.stepName && /* @__PURE__ */ jsx(Txt, { variant: "ui-xs", className: "text-icon3", children: stepDetail.stepId })
9652
+ ] })
9653
+ ] }),
9654
+ /* @__PURE__ */ jsx(
9655
+ "button",
9656
+ {
9657
+ onClick: closeStepDetail,
9658
+ className: "p-1 hover:bg-surface3 rounded transition-colors",
9659
+ "aria-label": "Close",
9660
+ children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-icon3" })
9661
+ }
9662
+ )
9663
+ ] }),
9664
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-auto", children: [
9665
+ stepDetail.type === "map-config" && stepDetail.mapConfig && /* @__PURE__ */ jsx(CodeDialogContent, { data: stepDetail.mapConfig }),
9666
+ stepDetail.type === "nested-graph" && stepDetail.nestedGraph && /* @__PURE__ */ jsx("div", { className: "h-full min-h-[400px]", children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
9667
+ WorkflowNestedGraph,
9668
+ {
9669
+ stepGraph: stepDetail.nestedGraph.stepGraph,
9670
+ open: true,
9671
+ workflowName: stepDetail.nestedGraph.fullStep
9672
+ }
9673
+ ) }) })
9674
+ ] })
9675
+ ] });
9676
+ }
9573
9677
 
9574
9678
  function WorkflowInformation({ workflowId, initialRunId }) {
9575
9679
  const { data: workflow, isLoading, error } = useWorkflow(workflowId);
@@ -9584,10 +9688,21 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9584
9688
  cancelWorkflowRun,
9585
9689
  isCancellingWorkflowRun
9586
9690
  } = useContext(WorkflowRunContext);
9691
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9587
9692
  const [tab, setTab] = useState("current-run");
9588
9693
  const [runId, setRunId] = useState("");
9589
9694
  const { handleCopy } = useCopyToClipboard({ text: workflowId });
9590
9695
  const stepsCount = Object.keys(workflow?.steps ?? {}).length;
9696
+ const nodeDetailTabName = useMemo(() => {
9697
+ if (!stepDetail) return null;
9698
+ if (stepDetail.type === "map-config") {
9699
+ return "Map Config";
9700
+ }
9701
+ if (stepDetail.type === "nested-graph") {
9702
+ return "Nested Workflow";
9703
+ }
9704
+ return "Node";
9705
+ }, [stepDetail]);
9591
9706
  useEffect(() => {
9592
9707
  if (!runId && !initialRunId) {
9593
9708
  closeStreamsAndReset();
@@ -9599,6 +9714,19 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9599
9714
  toast.error(`Error loading workflow: ${errorMessage}`);
9600
9715
  }
9601
9716
  }, [error]);
9717
+ useEffect(() => {
9718
+ if (stepDetail) {
9719
+ setTab("node-details");
9720
+ } else if (tab === "node-details") {
9721
+ setTab("current-run");
9722
+ }
9723
+ }, [stepDetail]);
9724
+ const handleTabChange = (newTab) => {
9725
+ if (tab === "node-details" && newTab !== "node-details") {
9726
+ closeStepDetail();
9727
+ }
9728
+ setTab(newTab);
9729
+ };
9602
9730
  if (error) {
9603
9731
  return null;
9604
9732
  }
@@ -9615,10 +9743,24 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9615
9743
  ] }),
9616
9744
  workflow?.isProcessorWorkflow && /* @__PURE__ */ jsx(Badge, { icon: /* @__PURE__ */ jsx(Cpu, { className: "h-3 w-3" }), className: "bg-violet-500/20 text-violet-400", children: "Processor" })
9617
9745
  ] }) }),
9618
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden border-t-sm border-border1 flex flex-col", children: /* @__PURE__ */ jsxs(PlaygroundTabs, { defaultTab: "current-run", value: tab, onValueChange: setTab, children: [
9746
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto border-t-sm border-border1 flex flex-col", children: /* @__PURE__ */ jsxs(PlaygroundTabs, { defaultTab: "current-run", value: tab, onValueChange: handleTabChange, className: "h-full", children: [
9619
9747
  /* @__PURE__ */ jsxs(TabList$1, { children: [
9620
9748
  /* @__PURE__ */ jsx(Tab$1, { value: "current-run", children: "Current Run" }),
9621
- /* @__PURE__ */ jsx(Tab$1, { value: "run-options", children: "Run options" })
9749
+ /* @__PURE__ */ jsx(Tab$1, { value: "run-options", children: "Run Options" }),
9750
+ stepDetail && nodeDetailTabName && /* @__PURE__ */ jsxs(
9751
+ Tab$1,
9752
+ {
9753
+ value: "node-details",
9754
+ onClose: () => {
9755
+ closeStepDetail();
9756
+ setTab("current-run");
9757
+ },
9758
+ children: [
9759
+ nodeDetailTabName,
9760
+ " Details"
9761
+ ]
9762
+ }
9763
+ )
9622
9764
  ] }),
9623
9765
  /* @__PURE__ */ jsx(TabContent$1, { value: "current-run", children: workflowId ? initialRunId ? /* @__PURE__ */ jsx(
9624
9766
  WorkflowRunDetail,
@@ -9653,7 +9795,8 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9653
9795
  cancelWorkflowRun
9654
9796
  }
9655
9797
  ) : null }),
9656
- /* @__PURE__ */ jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsx(TracingRunOptions, {}) })
9798
+ /* @__PURE__ */ jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsx(TracingRunOptions, {}) }),
9799
+ stepDetail && /* @__PURE__ */ jsx(TabContent$1, { value: "node-details", children: /* @__PURE__ */ jsx(WorkflowStepDetailContent, {}) })
9657
9800
  ] }) })
9658
9801
  ] });
9659
9802
  }
@@ -9885,7 +10028,8 @@ const WorkflowBadge = ({
9885
10028
  isStreaming,
9886
10029
  metadata,
9887
10030
  toolCallId,
9888
- toolApprovalMetadata
10031
+ toolApprovalMetadata,
10032
+ suspendPayload
9889
10033
  }) => {
9890
10034
  const { runId, status } = result || {};
9891
10035
  const { data: workflow, isLoading: isWorkflowLoading } = useWorkflow(workflowId);
@@ -9897,6 +10041,7 @@ const WorkflowBadge = ({
9897
10041
  const snapshot = typeof run?.snapshot === "object" ? run?.snapshot : void 0;
9898
10042
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
9899
10043
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
10044
+ let suspendPayloadSlot = typeof suspendPayload === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: suspendPayload }) : /* @__PURE__ */ jsx(SyntaxHighlighter$1, { data: suspendPayload, "data-testid": "tool-suspend-payload" });
9900
10045
  if (isWorkflowLoading || !workflow) return /* @__PURE__ */ jsx(LoadingBadge, {});
9901
10046
  return /* @__PURE__ */ jsxs(
9902
10047
  BadgeWrapper,
@@ -9913,6 +10058,10 @@ const WorkflowBadge = ({
9913
10058
  }
9914
10059
  ),
9915
10060
  children: [
10061
+ suspendPayloadSlot !== void 0 && suspendPayload && /* @__PURE__ */ jsxs("div", { children: [
10062
+ /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool suspend payload" }),
10063
+ suspendPayloadSlot
10064
+ ] }),
9916
10065
  !isStreaming && !isLoading && /* @__PURE__ */ jsx(WorkflowRunProvider, { snapshot, workflowId, initialRunId: runId, withoutTimeTravel: true, children: /* @__PURE__ */ jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }) }),
9917
10066
  isStreaming && /* @__PURE__ */ jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }),
9918
10067
  /* @__PURE__ */ jsx(ToolApprovalButtons, { toolCalled: !!status, toolCallId, toolApprovalMetadata })
@@ -10048,7 +10197,9 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10048
10197
  const agentToolName = toolName.startsWith("agent-") ? toolName.substring("agent-".length) : toolName;
10049
10198
  const workflowToolName = toolName.startsWith("workflow-") ? toolName.substring("workflow-".length) : toolName;
10050
10199
  const requireApprovalMetadata = metadata?.mode === "stream" && metadata?.requireApprovalMetadata;
10051
- const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolCallId] : void 0;
10200
+ const suspendedTools = metadata?.mode === "stream" && metadata?.suspendedTools;
10201
+ const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolName] ?? requireApprovalMetadata?.[toolCallId] : void 0;
10202
+ const suspendedToolMetadata = suspendedTools ? suspendedTools?.[toolName] : void 0;
10052
10203
  useWorkflowStream(result);
10053
10204
  if (isAgent) {
10054
10205
  return /* @__PURE__ */ jsx(
@@ -10072,7 +10223,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10072
10223
  result,
10073
10224
  metadata,
10074
10225
  toolCallId,
10075
- toolApprovalMetadata
10226
+ toolApprovalMetadata,
10227
+ suspendPayload: suspendedToolMetadata?.suspendPayload
10076
10228
  }
10077
10229
  );
10078
10230
  }
@@ -10085,7 +10237,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10085
10237
  toolOutput: result?.toolOutput || [],
10086
10238
  metadata,
10087
10239
  toolCallId,
10088
- toolApprovalMetadata
10240
+ toolApprovalMetadata,
10241
+ suspendPayload: suspendedToolMetadata?.suspendPayload
10089
10242
  }
10090
10243
  );
10091
10244
  };
@@ -11166,25 +11319,36 @@ const ThreadWelcome = ({ agentName }) => {
11166
11319
  };
11167
11320
  const Composer = ({ hasMemory, agentId }) => {
11168
11321
  const { setThreadInput } = useThreadInput();
11322
+ const textareaRef = useRef(null);
11169
11323
  return /* @__PURE__ */ jsx("div", { className: "mx-4", children: /* @__PURE__ */ jsxs(ComposerPrimitive.Root, { children: [
11170
11324
  /* @__PURE__ */ jsx("div", { className: "max-w-[568px] w-full mx-auto pb-2", children: /* @__PURE__ */ jsx(ComposerAttachments, {}) }),
11171
- /* @__PURE__ */ jsxs("div", { className: "bg-surface3 rounded-lg border-sm border-border1 py-4 mt-auto max-w-[568px] w-full mx-auto px-4 focus-within:outline focus-within:outline-accent1 -outline-offset-2", children: [
11172
- /* @__PURE__ */ jsx(ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsx(
11173
- "textarea",
11174
- {
11175
- className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11176
- autoFocus: document.activeElement === document.body,
11177
- placeholder: "Enter your message...",
11178
- name: "",
11179
- id: "",
11180
- onChange: (e) => setThreadInput?.(e.target.value)
11181
- }
11182
- ) }),
11183
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11184
- /* @__PURE__ */ jsx(SpeechInput, { agentId }),
11185
- /* @__PURE__ */ jsx(ComposerAction, {})
11186
- ] })
11187
- ] })
11325
+ /* @__PURE__ */ jsxs(
11326
+ "div",
11327
+ {
11328
+ className: "bg-surface3 rounded-lg border-sm border-border1 py-4 mt-auto max-w-[568px] w-full mx-auto px-4 focus-within:outline focus-within:outline-accent1 -outline-offset-2",
11329
+ onClick: () => {
11330
+ textareaRef.current?.focus();
11331
+ },
11332
+ children: [
11333
+ /* @__PURE__ */ jsx(ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsx(
11334
+ "textarea",
11335
+ {
11336
+ ref: textareaRef,
11337
+ className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11338
+ autoFocus: document.activeElement === document.body,
11339
+ placeholder: "Enter your message...",
11340
+ name: "",
11341
+ id: "",
11342
+ onChange: (e) => setThreadInput?.(e.target.value)
11343
+ }
11344
+ ) }),
11345
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11346
+ /* @__PURE__ */ jsx(SpeechInput, { agentId }),
11347
+ /* @__PURE__ */ jsx(ComposerAction, {})
11348
+ ] })
11349
+ ]
11350
+ }
11351
+ )
11188
11352
  ] }) });
11189
11353
  };
11190
11354
  const SpeechInput = ({ agentId }) => {
@@ -11522,34 +11686,33 @@ function useAgentSettingsState({ agentId, defaultSettings: defaultSettingsProp }
11522
11686
  useEffect(() => {
11523
11687
  try {
11524
11688
  const stored = localStorage.getItem(LOCAL_STORAGE_KEY);
11525
- if (stored) {
11526
- const parsed = JSON.parse(stored);
11527
- const settings2 = {
11528
- ...parsed,
11529
- modelSettings: {
11530
- ...defaultSettingsProp?.modelSettings ?? {},
11531
- ...parsed?.modelSettings ?? {}
11532
- }
11533
- };
11534
- setSettingsState(settings2 ?? void 0);
11535
- }
11689
+ const parsed = stored ? JSON.parse(stored) : {};
11690
+ const mergedSettings = {
11691
+ ...parsed,
11692
+ modelSettings: {
11693
+ ...defaultSettings.modelSettings,
11694
+ ...parsed?.modelSettings ?? {},
11695
+ ...defaultSettingsProp?.modelSettings ?? {}
11696
+ // Code defaults win
11697
+ }
11698
+ };
11699
+ setSettingsState(mergedSettings);
11536
11700
  } catch (e) {
11537
- console.error(e);
11538
11701
  }
11539
- }, [LOCAL_STORAGE_KEY]);
11702
+ }, [LOCAL_STORAGE_KEY, defaultSettingsProp]);
11540
11703
  const setSettings = (settingsValue) => {
11541
11704
  setSettingsState((prev) => ({ ...prev, ...settingsValue }));
11542
11705
  localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ ...settingsValue, agentId }));
11543
11706
  };
11544
11707
  const resetAll = () => {
11545
- const settings2 = {
11708
+ const resetSettings = {
11546
11709
  modelSettings: {
11547
- ...defaultSettingsProp?.modelSettings ?? {},
11548
- ...defaultSettings.modelSettings
11710
+ ...defaultSettings.modelSettings,
11711
+ ...defaultSettingsProp?.modelSettings ?? {}
11549
11712
  }
11550
11713
  };
11551
- setSettingsState(settings2);
11552
- localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(settings2));
11714
+ setSettingsState(resetSettings);
11715
+ localStorage.removeItem(LOCAL_STORAGE_KEY);
11553
11716
  };
11554
11717
  return {
11555
11718
  settings,
@@ -11700,18 +11863,19 @@ const initializeMessageState = (initialMessages) => {
11700
11863
  };
11701
11864
  } else if (part.toolInvocation.state === "call") {
11702
11865
  const toolCallId = part.toolInvocation.toolCallId;
11866
+ const toolName = part.toolInvocation.toolName;
11703
11867
  const pendingToolApprovals = message.metadata?.pendingToolApprovals;
11704
11868
  const suspensionData = pendingToolApprovals?.[toolCallId];
11705
11869
  if (suspensionData) {
11706
11870
  return {
11707
11871
  type: "tool-call",
11708
11872
  toolCallId,
11709
- toolName: part.toolInvocation.toolName,
11873
+ toolName,
11710
11874
  args: part.toolInvocation.args,
11711
11875
  metadata: {
11712
11876
  mode: "stream",
11713
11877
  requireApprovalMetadata: {
11714
- [toolCallId]: suspensionData
11878
+ [toolName]: suspensionData
11715
11879
  }
11716
11880
  }
11717
11881
  };
@@ -11781,6 +11945,7 @@ function MastraRuntimeProvider({
11781
11945
  temperature,
11782
11946
  topK,
11783
11947
  topP,
11948
+ seed,
11784
11949
  chatWithGenerateLegacy,
11785
11950
  chatWithGenerate,
11786
11951
  chatWithNetwork,
@@ -11799,19 +11964,21 @@ function MastraRuntimeProvider({
11799
11964
  temperature,
11800
11965
  topK,
11801
11966
  topP,
11802
- maxTokens,
11967
+ seed,
11968
+ maxOutputTokens: maxTokens,
11969
+ // AI SDK v5 uses maxOutputTokens
11803
11970
  instructions,
11804
11971
  providerOptions,
11805
11972
  maxSteps,
11806
11973
  requireToolApproval
11807
11974
  };
11808
11975
  const baseClient = useMastraClient();
11809
- const isVNext = modelVersion === "v2";
11976
+ const isSupportedModel = modelVersion === "v2" || modelVersion === "v3";
11810
11977
  const onNew = async (message) => {
11811
11978
  if (message.content[0]?.type !== "text") throw new Error("Only text messages are supported");
11812
11979
  const attachments = await convertToAIAttachments(message.attachments);
11813
11980
  const input = message.content[0].text;
11814
- if (!isVNext) {
11981
+ if (!isSupportedModel) {
11815
11982
  setLegacyMessages((s) => [...s, { role: "user", content: input, attachments: message.attachments }]);
11816
11983
  }
11817
11984
  const controller = new AbortController();
@@ -11822,7 +11989,7 @@ function MastraRuntimeProvider({
11822
11989
  });
11823
11990
  const agent = clientWithAbort.getAgent(agentId);
11824
11991
  try {
11825
- if (isVNext) {
11992
+ if (isSupportedModel) {
11826
11993
  if (chatWithNetwork) {
11827
11994
  await sendMessage({
11828
11995
  message: input,
@@ -11898,6 +12065,7 @@ function MastraRuntimeProvider({
11898
12065
  temperature,
11899
12066
  topK,
11900
12067
  topP,
12068
+ seed,
11901
12069
  instructions,
11902
12070
  requestContext: requestContextInstance,
11903
12071
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -12014,6 +12182,7 @@ function MastraRuntimeProvider({
12014
12182
  temperature,
12015
12183
  topK,
12016
12184
  topP,
12185
+ seed,
12017
12186
  instructions,
12018
12187
  requestContext: requestContextInstance,
12019
12188
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -12163,7 +12332,7 @@ function MastraRuntimeProvider({
12163
12332
  if (error.name === "AbortError") {
12164
12333
  return;
12165
12334
  }
12166
- if (isVNext) {
12335
+ if (isSupportedModel) {
12167
12336
  setMessages((currentConversation) => [
12168
12337
  ...currentConversation,
12169
12338
  { role: "assistant", parts: [{ type: "text", text: `${error}` }] }
@@ -12190,7 +12359,7 @@ function MastraRuntimeProvider({
12190
12359
  const vnextmessages = messages.map(toAssistantUIMessage);
12191
12360
  const runtime = useExternalStoreRuntime({
12192
12361
  isRunning: isLegacyRunning || isRunningStream,
12193
- messages: isVNext ? vnextmessages : legacyMessages,
12362
+ messages: isSupportedModel ? vnextmessages : legacyMessages,
12194
12363
  convertMessage: (x) => x,
12195
12364
  onNew,
12196
12365
  onCancel,
@@ -12334,54 +12503,60 @@ const AgentAdvancedSettings = () => {
12334
12503
  ] }),
12335
12504
  /* @__PURE__ */ jsxs(CollapsibleContent, { className: collapsibleContentClassName, children: [
12336
12505
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
12337
- /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12506
+ /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12338
12507
  /* @__PURE__ */ jsx(
12339
12508
  Input,
12340
12509
  {
12341
- id: "top-k",
12510
+ id: "frequency-penalty",
12342
12511
  type: "number",
12343
- value: settings?.modelSettings?.topK || "",
12512
+ step: "0.1",
12513
+ min: "-1",
12514
+ max: "1",
12515
+ value: settings?.modelSettings?.frequencyPenalty ?? "",
12344
12516
  onChange: (e) => setSettings({
12345
12517
  ...settings,
12346
12518
  modelSettings: {
12347
12519
  ...settings?.modelSettings,
12348
- topK: e.target.value ? Number(e.target.value) : void 0
12520
+ frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12349
12521
  }
12350
12522
  })
12351
12523
  }
12352
12524
  )
12353
12525
  ] }),
12354
12526
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
12355
- /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12527
+ /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12356
12528
  /* @__PURE__ */ jsx(
12357
12529
  Input,
12358
12530
  {
12359
- id: "frequency-penalty",
12531
+ id: "presence-penalty",
12360
12532
  type: "number",
12361
- value: settings?.modelSettings?.frequencyPenalty || "",
12533
+ step: "0.1",
12534
+ min: "-1",
12535
+ max: "1",
12536
+ value: settings?.modelSettings?.presencePenalty ?? "",
12362
12537
  onChange: (e) => setSettings({
12363
12538
  ...settings,
12364
12539
  modelSettings: {
12365
12540
  ...settings?.modelSettings,
12366
- frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12541
+ presencePenalty: e.target.value ? Number(e.target.value) : void 0
12367
12542
  }
12368
12543
  })
12369
12544
  }
12370
12545
  )
12371
12546
  ] }),
12372
12547
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
12373
- /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12548
+ /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12374
12549
  /* @__PURE__ */ jsx(
12375
12550
  Input,
12376
12551
  {
12377
- id: "presence-penalty",
12552
+ id: "top-k",
12378
12553
  type: "number",
12379
- value: settings?.modelSettings?.presencePenalty || "",
12554
+ value: settings?.modelSettings?.topK || "",
12380
12555
  onChange: (e) => setSettings({
12381
12556
  ...settings,
12382
12557
  modelSettings: {
12383
12558
  ...settings?.modelSettings,
12384
- presencePenalty: e.target.value ? Number(e.target.value) : void 0
12559
+ topK: e.target.value ? Number(e.target.value) : void 0
12385
12560
  }
12386
12561
  })
12387
12562
  }
@@ -12441,6 +12616,24 @@ const AgentAdvancedSettings = () => {
12441
12616
  }
12442
12617
  )
12443
12618
  ] }),
12619
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
12620
+ /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "seed", children: "Seed" }),
12621
+ /* @__PURE__ */ jsx(
12622
+ Input,
12623
+ {
12624
+ id: "seed",
12625
+ type: "number",
12626
+ value: settings?.modelSettings?.seed || "",
12627
+ onChange: (e) => setSettings({
12628
+ ...settings,
12629
+ modelSettings: {
12630
+ ...settings?.modelSettings,
12631
+ seed: e.target.value ? Number(e.target.value) : void 0
12632
+ }
12633
+ })
12634
+ }
12635
+ )
12636
+ ] }),
12444
12637
  /* @__PURE__ */ jsxs("div", { className: "space-y-1 col-span-2", children: [
12445
12638
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
12446
12639
  /* @__PURE__ */ jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "provider-options", children: "Provider Options" }),
@@ -12616,8 +12809,9 @@ const AgentSettings = ({ agentId }) => {
12616
12809
  const hasMemory = Boolean(memory?.result);
12617
12810
  const hasSubAgents = Boolean(Object.keys(agent.agents || {}).length > 0);
12618
12811
  const modelVersion = agent.modelVersion;
12812
+ const isSupportedModel = modelVersion === "v2" || modelVersion === "v3";
12619
12813
  let radioValue;
12620
- if (modelVersion === "v2") {
12814
+ if (isSupportedModel) {
12621
12815
  if (settings?.modelSettings?.chatWithNetwork) {
12622
12816
  radioValue = "network";
12623
12817
  } else {
@@ -12644,23 +12838,23 @@ const AgentSettings = ({ agentId }) => {
12644
12838
  }),
12645
12839
  className: "flex flex-row gap-4",
12646
12840
  children: [
12647
- modelVersion !== "v2" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12841
+ !isSupportedModel && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12648
12842
  /* @__PURE__ */ jsx(RadioGroupItem, { value: "generateLegacy", id: "generateLegacy", className: "text-icon6" }),
12649
12843
  /* @__PURE__ */ jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "generateLegacy", children: "Generate (Legacy)" })
12650
12844
  ] }),
12651
- modelVersion === "v2" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12845
+ isSupportedModel && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12652
12846
  /* @__PURE__ */ jsx(RadioGroupItem, { value: "generate", id: "generate", className: "text-icon6" }),
12653
12847
  /* @__PURE__ */ jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "generate", children: "Generate" })
12654
12848
  ] }),
12655
- modelVersion !== "v2" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12849
+ !isSupportedModel && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12656
12850
  /* @__PURE__ */ jsx(RadioGroupItem, { value: "streamLegacy", id: "streamLegacy", className: "text-icon6" }),
12657
12851
  /* @__PURE__ */ jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "streamLegacy", children: "Stream (Legacy)" })
12658
12852
  ] }),
12659
- modelVersion === "v2" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12853
+ isSupportedModel && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12660
12854
  /* @__PURE__ */ jsx(RadioGroupItem, { value: "stream", id: "stream", className: "text-icon6" }),
12661
12855
  /* @__PURE__ */ jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "stream", children: "Stream" })
12662
12856
  ] }),
12663
- modelVersion === "v2" && /* @__PURE__ */ jsx(NetworkCheckbox, { hasMemory, hasSubAgents })
12857
+ isSupportedModel && /* @__PURE__ */ jsx(NetworkCheckbox, { hasMemory, hasSubAgents })
12664
12858
  ]
12665
12859
  }
12666
12860
  ) }),
@@ -15452,6 +15646,7 @@ const AgentMetadataModelList = ({
15452
15646
  }) => {
15453
15647
  const [modelConfigs, setModelConfigs] = useState(() => modelList);
15454
15648
  const hasMultipleModels = modelConfigs.length > 1;
15649
+ const enabledCount = modelConfigs.filter((m) => m.enabled !== false).length;
15455
15650
  const handleDragEnd = (result) => {
15456
15651
  if (!result.destination) {
15457
15652
  return;
@@ -15486,7 +15681,8 @@ const AgentMetadataModelList = ({
15486
15681
  modelConfig,
15487
15682
  updateModelInModelList: updateModel,
15488
15683
  showDragHandle: hasMultipleModels,
15489
- dragHandleProps: provided2.dragHandleProps
15684
+ dragHandleProps: provided2.dragHandleProps,
15685
+ isLastEnabled: modelConfig.enabled !== false && enabledCount === 1
15490
15686
  }
15491
15687
  ) }) }, modelConfig.id)),
15492
15688
  provided.placeholder
@@ -15496,7 +15692,8 @@ const AgentMetadataModelListItem = ({
15496
15692
  modelConfig,
15497
15693
  updateModelInModelList,
15498
15694
  showDragHandle,
15499
- dragHandleProps
15695
+ dragHandleProps,
15696
+ isLastEnabled
15500
15697
  }) => {
15501
15698
  const [enabled, setEnabled] = useState(() => modelConfig.enabled);
15502
15699
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-background hover:bg-muted/50 transition-colors", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2", children: [
@@ -15510,7 +15707,10 @@ const AgentMetadataModelListItem = ({
15510
15707
  autoSave: true
15511
15708
  }
15512
15709
  ) }),
15513
- /* @__PURE__ */ jsx(
15710
+ isLastEnabled ? /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
15711
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx(Switch, { checked: enabled, disabled: true, className: "pointer-events-none" }) }) }),
15712
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: "At least one model must be enabled" }) })
15713
+ ] }) }) : /* @__PURE__ */ jsx(
15514
15714
  Switch,
15515
15715
  {
15516
15716
  checked: enabled,
@@ -15528,7 +15728,14 @@ function usePromptEnhancer({ agentId }) {
15528
15728
  const client = useMastraClient();
15529
15729
  return useMutation({
15530
15730
  mutationFn: async ({ instructions, userComment }) => {
15531
- return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15731
+ try {
15732
+ return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15733
+ } catch (error) {
15734
+ const errorMessage = error instanceof Error ? error.message : "Error enhancing prompt";
15735
+ toast.error(errorMessage);
15736
+ console.error("Error enhancing prompt:", error);
15737
+ throw error;
15738
+ }
15532
15739
  }
15533
15740
  });
15534
15741
  }
@@ -15571,21 +15778,53 @@ const PromptEnhancer = ({ agentId }) => {
15571
15778
  const PromptEnhancerTextarea = ({ agentId }) => {
15572
15779
  const { prompt, setPrompt } = useAgentPromptExperiment();
15573
15780
  const { mutateAsync: enhancePrompt, isPending } = usePromptEnhancer({ agentId });
15781
+ const { data: agent, isLoading: isAgentLoading, isError: isAgentError } = useAgent(agentId);
15782
+ const { data: providersData, isLoading: isProvidersLoading } = useAgentsModelProviders();
15783
+ const providers = providersData?.providers || [];
15784
+ const isProviderConnected = (providerId) => {
15785
+ const cleanId = cleanProviderId(providerId);
15786
+ const provider = providers.find((p) => cleanProviderId(p.id) === cleanId);
15787
+ return provider?.connected === true;
15788
+ };
15789
+ const hasConnectedModel = () => {
15790
+ if (agent?.modelList && agent.modelList.length > 0) {
15791
+ return agent.modelList.some((m) => m.enabled !== false && isProviderConnected(m.model.provider));
15792
+ }
15793
+ return agent?.provider ? isProviderConnected(agent.provider) : false;
15794
+ };
15795
+ const isDataLoading = isAgentLoading || isProvidersLoading;
15796
+ const hasValidModel = !isDataLoading && !isAgentError && hasConnectedModel();
15574
15797
  const handleSubmit = async (e) => {
15575
15798
  e.preventDefault();
15576
15799
  const form = e.target;
15577
15800
  const formData = new FormData(form);
15578
15801
  const userComment = formData.get("userComment");
15579
- const result = await enhancePrompt({ instructions: prompt, userComment });
15580
- form.reset();
15581
- setPrompt(result.new_prompt);
15802
+ try {
15803
+ const result = await enhancePrompt({ instructions: prompt, userComment });
15804
+ form.reset();
15805
+ setPrompt(result.new_prompt);
15806
+ } catch {
15807
+ }
15582
15808
  };
15809
+ const isDisabled = isPending || !hasValidModel;
15810
+ const showWarning = !isDataLoading && !hasValidModel;
15583
15811
  return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
15584
- /* @__PURE__ */ jsx(Input, { name: "userComment", placeholder: "Enter your comment here...", className: "resize-none", disabled: isPending }),
15585
- /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(Button$1, { variant: "light", type: "submit", disabled: isPending, children: [
15586
- /* @__PURE__ */ jsx(Icon, { children: isPending ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsx(RefreshCcwIcon, {}) }),
15587
- "Enhance prompt"
15588
- ] }) })
15812
+ /* @__PURE__ */ jsx(
15813
+ Input,
15814
+ {
15815
+ name: "userComment",
15816
+ placeholder: "Enter your comment here...",
15817
+ className: "resize-none",
15818
+ disabled: isDisabled
15819
+ }
15820
+ ),
15821
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end items-center gap-2", children: [
15822
+ showWarning && /* @__PURE__ */ jsx("span", { className: "text-xs text-yellow-200", children: "No model with a configured API key found." }),
15823
+ /* @__PURE__ */ jsxs(Button$1, { variant: "light", type: "submit", disabled: isDisabled, children: [
15824
+ /* @__PURE__ */ jsx(Icon, { children: isPending ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsx(RefreshCcwIcon, {}) }),
15825
+ "Enhance prompt"
15826
+ ] })
15827
+ ] })
15589
15828
  ] });
15590
15829
  };
15591
15830
 
@@ -15690,7 +15929,7 @@ const AgentMetadata = ({ agentId }) => {
15690
15929
  AgentMetadataSection,
15691
15930
  {
15692
15931
  title: "Model",
15693
- hint: agent.modelVersion === "v2" ? void 0 : {
15932
+ hint: agent.modelVersion === "v2" || agent.modelVersion === "v3" ? void 0 : {
15694
15933
  link: "https://mastra.ai/guides/migrations/vnext-to-standard-apis",
15695
15934
  title: "You are using a legacy v1 model",
15696
15935
  icon: /* @__PURE__ */ jsx(AlertTriangleIcon, { fontSize: 14, className: "mb-0.5" })
@@ -16359,13 +16598,16 @@ const AgentWorkingMemory = ({ agentId }) => {
16359
16598
  placeholder: "Enter working memory content..."
16360
16599
  }
16361
16600
  ),
16362
- /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
16601
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsx(Fragment, { children: !threadExists ? /* @__PURE__ */ jsxs(Tooltip, { children: [
16602
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { tabIndex: 0, children: /* @__PURE__ */ jsx(Button$2, { variant: "secondary", size: "sm", disabled: true, className: "text-xs pointer-events-none", children: "Edit Working Memory" }) }) }),
16603
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: "Working memory will be available after the agent calls updateWorkingMemory" }) })
16604
+ ] }) : /* @__PURE__ */ jsx(
16363
16605
  Button$2,
16364
16606
  {
16365
16607
  variant: "secondary",
16366
16608
  size: "sm",
16367
16609
  onClick: () => setIsEditing(true),
16368
- disabled: !threadExists || isUpdating,
16610
+ disabled: isUpdating,
16369
16611
  className: "text-xs",
16370
16612
  children: "Edit Working Memory"
16371
16613
  }
@@ -16462,22 +16704,6 @@ const AgentMemoryConfig = ({ agentId }) => {
16462
16704
  ]
16463
16705
  });
16464
16706
  }
16465
- if (config.workingMemory) {
16466
- sections.push({
16467
- title: "Working Memory",
16468
- items: [
16469
- {
16470
- label: "Enabled",
16471
- value: config.workingMemory.enabled,
16472
- badge: config.workingMemory.enabled ? "success" : void 0
16473
- },
16474
- ...config.workingMemory.enabled ? [
16475
- { label: "Scope", value: config.workingMemory.scope || "resource" },
16476
- { label: "Template", value: config.workingMemory.template || "default" }
16477
- ] : []
16478
- ]
16479
- });
16480
- }
16481
16707
  return sections;
16482
16708
  }, [config]);
16483
16709
  const toggleSection = (title) => {
@@ -16537,7 +16763,7 @@ const AgentMemoryConfig = ({ agentId }) => {
16537
16763
  ),
16538
16764
  expandedSections.has(section.title) && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2 space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-1", children: [
16539
16765
  /* @__PURE__ */ jsx("span", { className: "text-xs text-icon3", children: item.label }),
16540
- renderValue(item.value || "", item.badge)
16766
+ renderValue(item.value ?? "", item.badge)
16541
16767
  ] }, `${section.title}-${item.label}`)) })
16542
16768
  ] }, section.title)) })
16543
16769
  ] });
@@ -18668,6 +18894,17 @@ const Tabs = Object.assign(TabsRoot, {
18668
18894
  Content: TabContent
18669
18895
  });
18670
18896
 
18897
+ function isTokenDetailsObject(value) {
18898
+ return typeof value === "object" && value !== null;
18899
+ }
18900
+ const detailKeyLabels = {
18901
+ text: "Text",
18902
+ cacheRead: "Cache Read",
18903
+ cacheWrite: "Cache Write",
18904
+ audio: "Audio",
18905
+ image: "Image",
18906
+ reasoning: "Reasoning"
18907
+ };
18671
18908
  function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18672
18909
  if (!traceUsage && !spanUsage) {
18673
18910
  console.warn("No usage data available");
@@ -18772,6 +19009,14 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18772
19009
  cachedInputTokens: {
18773
19010
  label: "Cached Input Tokens",
18774
19011
  icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {})
19012
+ },
19013
+ inputDetails: {
19014
+ label: "Input Details",
19015
+ icon: /* @__PURE__ */ jsx(ArrowRightIcon, {})
19016
+ },
19017
+ outputDetails: {
19018
+ label: "Output Details",
19019
+ icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {})
18775
19020
  }
18776
19021
  };
18777
19022
  const commonTokenPresentations = {
@@ -18787,47 +19032,79 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18787
19032
  };
18788
19033
  let usageKeyOrder = [];
18789
19034
  if (hasV5Format) {
18790
- usageKeyOrder = ["totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cachedInputTokens"];
19035
+ usageKeyOrder = [
19036
+ "totalTokens",
19037
+ "inputTokens",
19038
+ "outputTokens",
19039
+ "reasoningTokens",
19040
+ "cachedInputTokens",
19041
+ "inputDetails",
19042
+ "outputDetails"
19043
+ ];
18791
19044
  } else {
18792
19045
  usageKeyOrder = ["totalTokens", "promptTokens", "completionTokens"];
18793
19046
  }
18794
- const usageAsArray = Object.entries(traceUsage || spanUsage || {}).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
18795
- return /* @__PURE__ */ jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => /* @__PURE__ */ jsxs(
18796
- "div",
18797
- {
18798
- className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
18799
- "min-h-[5.5rem]": traceUsage
18800
- }),
18801
- children: [
18802
- /* @__PURE__ */ jsxs(
18803
- "div",
18804
- {
18805
- className: cn(
18806
- "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
18807
- "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
18808
- ),
18809
- children: [
18810
- tokenPresentations?.[key]?.icon,
18811
- /* @__PURE__ */ jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
18812
- /* @__PURE__ */ jsx("b", { className: "text-[1rem]", children: value })
18813
- ]
18814
- }
18815
- ),
18816
- tokensByProviderValid && /* @__PURE__ */ jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => /* @__PURE__ */ jsxs(
18817
- "dl",
18818
- {
18819
- className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
18820
- children: [
18821
- /* @__PURE__ */ jsx("dt", { children: provider }),
18822
- /* @__PURE__ */ jsx("dd", { children: providerTokens?.[key] })
18823
- ]
18824
- },
18825
- provider
18826
- )) })
18827
- ]
18828
- },
18829
- key
18830
- )) });
19047
+ const usageAsArray = Object.entries(traceUsage || spanUsage || {}).filter((entry) => {
19048
+ const value = entry[1];
19049
+ return typeof value === "number" || isTokenDetailsObject(value);
19050
+ }).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
19051
+ return /* @__PURE__ */ jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => {
19052
+ const isObject = isTokenDetailsObject(value);
19053
+ return /* @__PURE__ */ jsxs(
19054
+ "div",
19055
+ {
19056
+ className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
19057
+ "min-h-[5.5rem]": traceUsage
19058
+ }),
19059
+ children: [
19060
+ /* @__PURE__ */ jsxs(
19061
+ "div",
19062
+ {
19063
+ className: cn(
19064
+ "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
19065
+ "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
19066
+ ),
19067
+ children: [
19068
+ tokenPresentations?.[key]?.icon,
19069
+ /* @__PURE__ */ jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
19070
+ !isObject && /* @__PURE__ */ jsx("b", { className: "text-[1rem]", children: value })
19071
+ ]
19072
+ }
19073
+ ),
19074
+ isObject && /* @__PURE__ */ jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(value).map(([detailKey, detailValue]) => {
19075
+ if (typeof detailValue !== "number") return null;
19076
+ return /* @__PURE__ */ jsxs(
19077
+ "dl",
19078
+ {
19079
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19080
+ children: [
19081
+ /* @__PURE__ */ jsx("dt", { children: detailKeyLabels[detailKey] || detailKey }),
19082
+ /* @__PURE__ */ jsx("dd", { children: detailValue })
19083
+ ]
19084
+ },
19085
+ detailKey
19086
+ );
19087
+ }) }),
19088
+ !isObject && tokensByProviderValid && /* @__PURE__ */ jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => {
19089
+ const tokenValue = providerTokens?.[key];
19090
+ if (typeof tokenValue !== "number") return null;
19091
+ return /* @__PURE__ */ jsxs(
19092
+ "dl",
19093
+ {
19094
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19095
+ children: [
19096
+ /* @__PURE__ */ jsx("dt", { children: provider }),
19097
+ /* @__PURE__ */ jsx("dd", { children: tokenValue })
19098
+ ]
19099
+ },
19100
+ provider
19101
+ );
19102
+ }) })
19103
+ ]
19104
+ },
19105
+ key
19106
+ );
19107
+ }) });
18831
19108
  }
18832
19109
 
18833
19110
  function isTokenLimitExceeded(span) {
@@ -18940,7 +19217,7 @@ function SpanTabs({
18940
19217
  SpanScoring,
18941
19218
  {
18942
19219
  traceId: trace?.traceId,
18943
- isTopLevelSpan: span?.parentSpanId === null,
19220
+ isTopLevelSpan: !Boolean(span?.parentSpanId),
18944
19221
  spanId: span?.spanId,
18945
19222
  entityType,
18946
19223
  scorers,
@@ -19799,6 +20076,15 @@ const PlaygroundQueryClient = ({ children, options }) => {
19799
20076
  return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });
19800
20077
  };
19801
20078
 
20079
+ const themeClasses = {
20080
+ light: "bg-gray-100 border-gray-300 text-gray-700",
20081
+ dark: "bg-surface4 border-border1 text-icon6"
20082
+ };
20083
+ const Kbd = ({ children, theme = "dark" }) => {
20084
+ const themeClass = themeClasses[theme];
20085
+ return /* @__PURE__ */ jsx("kbd", { className: clsx("border-sm rounded-md px-1 py-0.5 font-mono", themeClass), children });
20086
+ };
20087
+
19802
20088
  const errorFallback = "Something went wrong while fetching the data.";
19803
20089
  const parseError = (error) => {
19804
20090
  try {
@@ -20100,14 +20386,6 @@ const MCPToolPanel = ({ toolId, serverId }) => {
20100
20386
  );
20101
20387
  };
20102
20388
 
20103
- const CodeMirrorBlock = (props) => {
20104
- const theme = useCodemirrorTheme$1();
20105
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4 relative", children: [
20106
- /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-4 z-10", children: /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy code", content: props.value || "No content" }) }),
20107
- /* @__PURE__ */ jsx(CodeMirror, { extensions: [json()], theme, ...props })
20108
- ] });
20109
- };
20110
-
20111
20389
  const MCPDetail = ({ isLoading, server }) => {
20112
20390
  const [{ sseUrl, httpStreamUrl }, setUrls] = useState({
20113
20391
  sseUrl: "",
@@ -20129,112 +20407,45 @@ const MCPDetail = ({ isLoading, server }) => {
20129
20407
  if (isLoading) return null;
20130
20408
  if (!server)
20131
20409
  return /* @__PURE__ */ jsx(MainContentContent, { children: /* @__PURE__ */ jsx(Txt, { as: "h1", variant: "header-md", className: "text-icon3 font-medium py-20 text-center", children: "Server not found" }) });
20410
+ const commandLineConfig = `npx -y mcp-remote ${sseUrl}`;
20132
20411
  return /* @__PURE__ */ jsxs(MainContentContent, { isDivided: true, children: [
20133
- /* @__PURE__ */ jsxs("div", { className: "px-8 py-20 mx-auto max-w-[604px] w-full", children: [
20412
+ /* @__PURE__ */ jsxs("div", { className: "px-8 py-12 mx-auto max-w-2xl w-full", children: [
20134
20413
  /* @__PURE__ */ jsx(Txt, { as: "h1", variant: "header-md", className: "text-icon6 font-medium pb-4", children: server.name }),
20135
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
20136
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
20137
- /* @__PURE__ */ jsx(
20138
- Badge,
20139
- {
20140
- icon: /* @__PURE__ */ jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "SSE" }),
20141
- className: "!text-icon4",
20142
- children: sseUrl
20143
- }
20144
- ),
20145
- /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" })
20146
- ] }),
20147
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
20148
- /* @__PURE__ */ jsx(
20149
- Badge,
20150
- {
20151
- icon: /* @__PURE__ */ jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "HTTP" }),
20152
- className: "!text-icon4",
20153
- children: httpStreamUrl
20154
- }
20155
- ),
20156
- /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" })
20157
- ] })
20158
- ] }),
20159
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 pt-3 pb-9", children: [
20414
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 pb-6", children: [
20160
20415
  /* @__PURE__ */ jsx(Badge, { icon: /* @__PURE__ */ jsx(FolderIcon, { className: "text-icon6" }), className: "rounded-r-sm !text-icon4", children: "Version" }),
20161
20416
  /* @__PURE__ */ jsx(Badge, { className: "rounded-l-sm !text-icon4", children: server.version_detail.version })
20162
20417
  ] }),
20163
- /* @__PURE__ */ jsx(McpSetupTabs, { sseUrl, serverName: server.name })
20418
+ /* @__PURE__ */ jsx(Txt, { className: "text-icon3 pb-4", children: "This MCP server can be accessed through multiple transport methods. Choose the one that best fits your use case." }),
20419
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
20420
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20421
+ /* @__PURE__ */ jsx(Badge, { icon: /* @__PURE__ */ jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "HTTP" }), children: "Regular HTTP Endpoint" }),
20422
+ /* @__PURE__ */ jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for stateless HTTP transport with streamable responses." }),
20423
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
20424
+ /* @__PURE__ */ jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: httpStreamUrl }),
20425
+ /* @__PURE__ */ jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" }) })
20426
+ ] })
20427
+ ] }),
20428
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20429
+ /* @__PURE__ */ jsx(Badge, { icon: /* @__PURE__ */ jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "SSE" }), children: "Server-Sent Events" }),
20430
+ /* @__PURE__ */ jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for real-time communication via SSE." }),
20431
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
20432
+ /* @__PURE__ */ jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: sseUrl }),
20433
+ /* @__PURE__ */ jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" }) })
20434
+ ] })
20435
+ ] }),
20436
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20437
+ /* @__PURE__ */ jsx(Badge, { icon: /* @__PURE__ */ jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "CLI" }), children: "Command Line" }),
20438
+ /* @__PURE__ */ jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for local command-line access via npx and mcp-remote." }),
20439
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
20440
+ /* @__PURE__ */ jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: commandLineConfig }),
20441
+ /* @__PURE__ */ jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsx(CopyButton, { tooltip: "Copy Command Line Config", content: commandLineConfig, iconSize: "sm" }) })
20442
+ ] })
20443
+ ] })
20444
+ ] })
20164
20445
  ] }),
20165
20446
  /* @__PURE__ */ jsx("div", { className: "h-full overflow-y-scroll border-l-sm border-border1", children: /* @__PURE__ */ jsx(McpToolList, { server }) })
20166
20447
  ] });
20167
20448
  };
20168
- const McpSetupTabs = ({ sseUrl, serverName }) => {
20169
- const { Link } = useLinkComponent();
20170
- return /* @__PURE__ */ jsxs(PlaygroundTabs, { defaultTab: "cursor", children: [
20171
- /* @__PURE__ */ jsxs(TabList$1, { children: [
20172
- /* @__PURE__ */ jsx(Tab$1, { value: "cursor", children: "Cursor" }),
20173
- /* @__PURE__ */ jsx(Tab$1, { value: "windsurf", children: "Windsurf" })
20174
- ] }),
20175
- /* @__PURE__ */ jsxs(TabContent$1, { value: "cursor", children: [
20176
- /* @__PURE__ */ jsxs(Txt, { className: "text-icon3 pb-4", children: [
20177
- "Cursor comes with built-in MCP Support.",
20178
- " ",
20179
- /* @__PURE__ */ jsx(
20180
- Link,
20181
- {
20182
- href: "https://docs.cursor.com/context/model-context-protocol",
20183
- target: "_blank",
20184
- rel: "noopener noreferrer",
20185
- className: "underline hover:text-icon6",
20186
- children: "Following the documentation"
20187
- }
20188
- ),
20189
- ", you can register an MCP server using SSE with the following configuration."
20190
- ] }),
20191
- /* @__PURE__ */ jsx(
20192
- CodeMirrorBlock,
20193
- {
20194
- editable: false,
20195
- value: `{
20196
- "mcpServers": {
20197
- "${serverName}": {
20198
- "url": "${sseUrl}"
20199
- }
20200
- }
20201
- }`
20202
- }
20203
- )
20204
- ] }),
20205
- /* @__PURE__ */ jsxs(TabContent$1, { value: "windsurf", children: [
20206
- /* @__PURE__ */ jsxs(Txt, { className: "text-icon3 pb-4", children: [
20207
- "Windsurf comes with built-in MCP Support.",
20208
- " ",
20209
- /* @__PURE__ */ jsx(
20210
- Link,
20211
- {
20212
- href: "https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json",
20213
- target: "_blank",
20214
- rel: "noopener noreferrer",
20215
- className: "underline hover:text-icon6",
20216
- children: "Following the documentation"
20217
- }
20218
- ),
20219
- ", you can register an MCP server using SSE with the following configuration."
20220
- ] }),
20221
- /* @__PURE__ */ jsx(
20222
- CodeMirrorBlock,
20223
- {
20224
- editable: false,
20225
- value: `{
20226
- "mcpServers": {
20227
- "${serverName}": {
20228
- "command": "npx",
20229
- "args": ["-y", "mcp-remote", "${sseUrl}"]
20230
- }
20231
- }
20232
- }`
20233
- }
20234
- )
20235
- ] })
20236
- ] });
20237
- };
20238
20449
  const McpToolList = ({ server }) => {
20239
20450
  const { data: tools = {}, isLoading } = useMCPServerTools(server);
20240
20451
  if (isLoading) return null;
@@ -20481,5 +20692,5 @@ const PlaygroundConfigGuard = () => {
20481
20692
  ] }) });
20482
20693
  };
20483
20694
 
20484
- export { AgentChat, AgentCoinIcon, AgentCombobox, AgentEntityHeader, AgentIcon, AgentInformation, AgentInformationLayout, AgentInformationTabLayout, AgentMemory, AgentMetadata, AgentMetadataList, AgentMetadataListEmpty, AgentMetadataListItem, AgentMetadataNetworkList, AgentMetadataScorerList, AgentMetadataSection, AgentMetadataToolList, AgentMetadataWorkflowList, AgentMetadataWrapper, AgentNetworkCoinIcon, AgentPromptExperimentProvider, AgentSettings, AgentSettingsContext, AgentSettingsProvider, AgentToolPanel, AgentsTable, AiIcon, Alert$1 as Alert, AlertDescription$1 as AlertDescription, AlertDialog, AlertTitle$1 as AlertTitle, ApiIcon, Badge, BranchIcon, Breadcrumb, Button$1 as Button, ButtonsGroup, Cell, ChatThreads, CheckIcon, ChevronIcon, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, CommitIcon, CrossIcon, Crumb, DateTimeCell, DateTimePicker, DateTimePickerContent, DbIcon, DebugIcon, DefaultTrigger, DeploymentIcon, DividerIcon, DocsIcon, DynamicForm, EmptyState, Entity, EntityContent, EntityDescription, EntityHeader, EntityIcon, EntityName, Entry, EntryCell, EntryList, EntryListSkeleton, EnvIcon, FiltersIcon, FolderIcon, GithubCoinIcon, GithubIcon, GoogleIcon, Header, HeaderAction, HeaderGroup, HeaderTitle, HomeIcon, Icon, InfoIcon, InputField, JudgeIcon, Kbd, KeyValueList, LatencyIcon, LinkComponentProvider, LogoWithoutText, LogsIcon, MCPDetail, MCPServerCombobox, MCPTable, MCPToolPanel, MainContentContent, MainContentLayout, MainSidebar, MainSidebarProvider, McpCoinIcon, McpServerIcon, MemoryIcon, MemorySearch, Notification, OpenAIIcon, PageHeader, PlaygroundConfigGuard, PlaygroundQueryClient, PlaygroundTabs, PromptIcon, RadioGroup, RadioGroupItem, RepoIcon, RequestContext, RequestContextWrapper, Row, ScoreDialog, ScorerCombobox, ScorersTable, ScoresList, ScoresTools, SearchField, Searchbar, SearchbarWrapper, Section, Sections, SelectField, SettingsIcon, SideDialog, Skeleton, SlashIcon, SpanScoreList, SpanScoring, SpanTabs, StudioConfigContext, StudioConfigForm, StudioConfigProvider, Tab$1 as Tab, TabContent$1 as TabContent, TabList$1 as TabList, Table, Tbody, TemplateFailure, TemplateForm, TemplateInfo, TemplateInstallation, TemplateSuccess, TemplatesList, TemplatesTools, TextAndIcon, Th, Thead, ThreadDeleteButton, ThreadInputProvider, ThreadItem, ThreadLink, ThreadList, Threads, ToolCoinIcon, ToolCombobox, ToolFallback, ToolIconMap, ToolInformation, ToolPanel, ToolTable, ToolsIcon, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TraceDialog, TraceIcon, TraceTimeline, TraceTimelineSpan, TraceTimelineTools, TracesList, TracesTools, TracingSettingsContext, TracingSettingsProvider, TsIcon, Txt, TxtCell, VariablesIcon, WorkflowCoinIcon, WorkflowCombobox, WorkflowGraph, WorkflowIcon, WorkflowInformation, WorkflowRunContext, WorkflowRunDetail, WorkflowRunList, WorkflowRunProvider, WorkflowTable, WorkflowTrigger, WorkingMemoryContext, WorkingMemoryProvider, convertWorkflowRunStateToStreamResult, extractPrompt, formatHierarchicalSpans, getColumnTemplate, getShortId, getSpanTypeUi, getToNextEntryFn, getToPreviousEntryFn, parseError, providerMapToIcon, scoresListColumns, spanTypePrefixes, toast, traceScoresListColumns, tracesListColumns, useAgent, useAgentInformationSettings, useAgentInformationTab, useAgentPromptExperiment, useAgentSettings, useAgents, useCancelWorkflowRun, useCurrentRun, useDeleteThread, useDeleteWorkflowRun, useExecuteAgentTool, useExecuteMCPTool, useExecuteTool, useExecuteWorkflow, useInView, useLinkComponent, useMCPServerTool, useMCPServerTools, useMCPServers, useMainSidebar, useMemory, useMemoryConfig, useMemorySearch, usePlaygroundStore, useReorderModelList, useResetAgentModel, useScorer, useScorers, useScoresByScorerId, useSpeechRecognition, useStreamWorkflow, useStudioConfig, useThreadInput, useThreads, useTool, useTools, useTraceSpanScores, useTracingSettings, useUpdateAgentModel, useUpdateModelInModelList, useWorkflow, useWorkflowRunExecutionResult, useWorkflowRuns, useWorkflows, useWorkingMemory };
20695
+ export { AgentChat, AgentCoinIcon, AgentCombobox, AgentEntityHeader, AgentIcon, AgentInformation, AgentInformationLayout, AgentInformationTabLayout, AgentMemory, AgentMetadata, AgentMetadataList, AgentMetadataListEmpty, AgentMetadataListItem, AgentMetadataNetworkList, AgentMetadataScorerList, AgentMetadataSection, AgentMetadataToolList, AgentMetadataWorkflowList, AgentMetadataWrapper, AgentNetworkCoinIcon, AgentPromptExperimentProvider, AgentSettings, AgentSettingsContext, AgentSettingsProvider, AgentToolPanel, AgentsTable, AiIcon, Alert$1 as Alert, AlertDescription$1 as AlertDescription, AlertDialog, AlertTitle$1 as AlertTitle, ApiIcon, Badge, BranchIcon, Breadcrumb, Button$1 as Button, ButtonsGroup, Cell, ChatThreads, CheckIcon, ChevronIcon, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, CommitIcon, CrossIcon, Crumb, DateTimeCell, DateTimePicker, DateTimePickerContent, DbIcon, DebugIcon, DefaultTrigger, DeploymentIcon, DividerIcon, DocsIcon, DynamicForm, EmptyState, Entity, EntityContent, EntityDescription, EntityHeader, EntityIcon, EntityName, Entry, EntryCell, EntryList, EntryListSkeleton, EnvIcon, FiltersIcon, FolderIcon, GithubCoinIcon, GithubIcon, GoogleIcon, Header, HeaderAction, HeaderGroup, HeaderTitle, HomeIcon, Icon, InfoIcon, InputField, JudgeIcon, Kbd, KeyValueList, LatencyIcon, LinkComponentProvider, LogoWithoutText, LogsIcon, MCPDetail, MCPServerCombobox, MCPTable, MCPToolPanel, MainContentContent, MainContentLayout, MainSidebar, MainSidebarProvider, McpCoinIcon, McpServerIcon, MemoryIcon, MemorySearch, Notification, OpenAIIcon, PageHeader, PlaygroundConfigGuard, PlaygroundQueryClient, PlaygroundTabs, PromptIcon, RadioGroup, RadioGroupItem, RepoIcon, RequestContext, RequestContextWrapper, Row, ScoreDialog, ScorerCombobox, ScorersTable, ScoresList, ScoresTools, SearchField, Searchbar, SearchbarWrapper, Section, Sections, SelectField, SettingsIcon, SideDialog, Skeleton, SlashIcon, SpanScoreList, SpanScoring, SpanTabs, StudioConfigContext, StudioConfigForm, StudioConfigProvider, Tab$1 as Tab, TabContent$1 as TabContent, TabList$1 as TabList, Table, Tbody, TemplateFailure, TemplateForm, TemplateInfo, TemplateInstallation, TemplateSuccess, TemplatesList, TemplatesTools, TextAndIcon, Th, Thead, ThreadDeleteButton, ThreadInputProvider, ThreadItem, ThreadLink, ThreadList, Threads, ToolCoinIcon, ToolCombobox, ToolFallback, ToolIconMap, ToolInformation, ToolPanel, ToolTable, ToolsIcon, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TraceDialog, TraceIcon, TraceTimeline, TraceTimelineSpan, TraceTimelineTools, TracesList, TracesTools, TracingSettingsContext, TracingSettingsProvider, TsIcon, Txt, TxtCell, VariablesIcon, WorkflowCoinIcon, WorkflowCombobox, WorkflowGraph, WorkflowIcon, WorkflowInformation, WorkflowRunContext, WorkflowRunDetail, WorkflowRunList, WorkflowRunProvider, WorkflowStepDetailContext, WorkflowStepDetailProvider, WorkflowTable, WorkflowTrigger, WorkingMemoryContext, WorkingMemoryProvider, convertWorkflowRunStateToStreamResult, extractPrompt, formatHierarchicalSpans, getColumnTemplate, getShortId, getSpanTypeUi, getToNextEntryFn, getToPreviousEntryFn, parseError, providerMapToIcon, scoresListColumns, spanTypePrefixes, toast, traceScoresListColumns, tracesListColumns, useAgent, useAgentInformationSettings, useAgentInformationTab, useAgentPromptExperiment, useAgentSettings, useAgents, useCancelWorkflowRun, useCurrentRun, useDeleteThread, useDeleteWorkflowRun, useExecuteAgentTool, useExecuteMCPTool, useExecuteTool, useExecuteWorkflow, useInView, useLinkComponent, useMCPServerTool, useMCPServerTools, useMCPServers, useMainSidebar, useMemory, useMemoryConfig, useMemorySearch, usePlaygroundStore, useReorderModelList, useResetAgentModel, useScorer, useScorers, useScoresByScorerId, useSpeechRecognition, useStreamWorkflow, useStudioConfig, useThreadInput, useThreads, useTool, useTools, useTraceSpanScores, useTracingSettings, useUpdateAgentModel, useUpdateModelInModelList, useWorkflow, useWorkflowRunExecutionResult, useWorkflowRuns, useWorkflowStepDetail, useWorkflows, useWorkingMemory };
20485
20696
  //# sourceMappingURL=index.es.js.map