@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.cjs.js CHANGED
@@ -32,6 +32,7 @@ const prismReactRenderer = require('prism-react-renderer');
32
32
  const CollapsiblePrimitive = require('@radix-ui/react-collapsible');
33
33
  const ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
34
34
  const view = require('@codemirror/view');
35
+ const langJavascript = require('@codemirror/lang-javascript');
35
36
  const CheckboxPrimitive = require('@radix-ui/react-checkbox');
36
37
  const dateFns = require('date-fns');
37
38
  const useDebounce = require('use-debounce');
@@ -4679,7 +4680,8 @@ const ToolBadge = ({
4679
4680
  metadata,
4680
4681
  toolOutput,
4681
4682
  toolCallId,
4682
- toolApprovalMetadata
4683
+ toolApprovalMetadata,
4684
+ suspendPayload
4683
4685
  }) => {
4684
4686
  let argSlot = null;
4685
4687
  try {
@@ -4689,6 +4691,7 @@ const ToolBadge = ({
4689
4691
  argSlot = /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: args });
4690
4692
  }
4691
4693
  let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: result }) : /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlighter$2, { data: result, "data-testid": "tool-result" });
4694
+ let suspendPayloadSlot = typeof suspendPayload === "string" ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: suspendPayload }) : /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlighter$2, { data: suspendPayload, "data-testid": "tool-suspend-payload" });
4692
4695
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
4693
4696
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
4694
4697
  const toolCalled = result || toolOutput.length > 0;
@@ -4705,12 +4708,16 @@ const ToolBadge = ({
4705
4708
  input: agentNetworkInput
4706
4709
  }
4707
4710
  ),
4708
- initialCollapsed: !!!toolApprovalMetadata,
4711
+ initialCollapsed: !!!(toolApprovalMetadata ?? suspendPayload),
4709
4712
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4710
4713
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4711
4714
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool arguments" }),
4712
4715
  argSlot
4713
4716
  ] }),
4717
+ suspendPayloadSlot !== void 0 && suspendPayload && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4718
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool suspend payload" }),
4719
+ suspendPayloadSlot
4720
+ ] }),
4714
4721
  resultSlot !== void 0 && result && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4715
4722
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool result" }),
4716
4723
  resultSlot
@@ -5027,7 +5034,8 @@ const useExecuteWorkflow = () => {
5027
5034
  requestContext$1.set(key, value);
5028
5035
  });
5029
5036
  const workflow = client.getWorkflow(workflowId);
5030
- await workflow.start({ runId, inputData: input || {}, requestContext: requestContext$1 });
5037
+ const run = await workflow.createRun({ runId });
5038
+ await run.start({ inputData: input || {}, requestContext: requestContext$1 });
5031
5039
  } catch (error) {
5032
5040
  console.error("Error starting workflow run:", error);
5033
5041
  throw error;
@@ -5047,7 +5055,8 @@ const useExecuteWorkflow = () => {
5047
5055
  requestContext$1.set(key, value);
5048
5056
  });
5049
5057
  const workflow = client.getWorkflow(workflowId);
5050
- const result = await workflow.startAsync({ runId, inputData: input || {}, requestContext: requestContext$1 });
5058
+ const run = await workflow.createRun({ runId });
5059
+ const result = await run.startAsync({ inputData: input || {}, requestContext: requestContext$1 });
5051
5060
  return result;
5052
5061
  } catch (error) {
5053
5062
  console.error("Error starting workflow run:", error);
@@ -5140,8 +5149,8 @@ const useStreamWorkflow = () => {
5140
5149
  requestContext$1.set(key, value);
5141
5150
  });
5142
5151
  const workflow = client.getWorkflow(workflowId);
5143
- const stream = await workflow.streamVNext({
5144
- runId,
5152
+ const run = await workflow.createRun({ runId });
5153
+ const stream = await run.streamVNext({
5145
5154
  inputData,
5146
5155
  requestContext: requestContext$1,
5147
5156
  closeOnSuspend: true,
@@ -5203,7 +5212,8 @@ const useStreamWorkflow = () => {
5203
5212
  return;
5204
5213
  }
5205
5214
  const workflow = client.getWorkflow(workflowId);
5206
- const stream = await workflow.observeStreamVNext({ runId });
5215
+ const run = await workflow.createRun({ runId });
5216
+ const stream = await run.observeStreamVNext();
5207
5217
  if (!stream) {
5208
5218
  return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
5209
5219
  }
@@ -5261,8 +5271,8 @@ const useStreamWorkflow = () => {
5261
5271
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5262
5272
  requestContext$1.set(key, value);
5263
5273
  });
5264
- const stream = await workflow.resumeStreamVNext({
5265
- runId,
5274
+ const run = await workflow.createRun({ runId });
5275
+ const stream = await run.resumeStreamVNext({
5266
5276
  step,
5267
5277
  resumeData,
5268
5278
  requestContext: requestContext$1,
@@ -5311,6 +5321,7 @@ const useStreamWorkflow = () => {
5311
5321
  mutationFn: async ({
5312
5322
  workflowId,
5313
5323
  requestContext: playgroundRequestContext,
5324
+ runId,
5314
5325
  ...params
5315
5326
  }) => {
5316
5327
  if (timeTravelStreamRef.current) {
@@ -5323,7 +5334,8 @@ const useStreamWorkflow = () => {
5323
5334
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5324
5335
  requestContext$1.set(key, value);
5325
5336
  });
5326
- const stream = await workflow.timeTravelStream({
5337
+ const run = await workflow.createRun({ runId });
5338
+ const stream = await run.timeTravelStream({
5327
5339
  ...params,
5328
5340
  requestContext: requestContext$1,
5329
5341
  tracingOptions: settings?.tracingOptions
@@ -5414,7 +5426,9 @@ const useCancelWorkflowRun = () => {
5414
5426
  const cancelWorkflowRun = reactQuery.useMutation({
5415
5427
  mutationFn: async ({ workflowId, runId }) => {
5416
5428
  try {
5417
- const response = await client.getWorkflow(workflowId).cancelRun(runId);
5429
+ const workflow = client.getWorkflow(workflowId);
5430
+ const run = await workflow.createRun({ runId });
5431
+ const response = await run.cancelRun();
5418
5432
  return response;
5419
5433
  } catch (error) {
5420
5434
  console.error("Error canceling workflow run:", error);
@@ -5508,6 +5522,58 @@ const useDeleteWorkflowRun = (workflowId) => {
5508
5522
  });
5509
5523
  };
5510
5524
 
5525
+ const WorkflowStepDetailContext = React.createContext(null);
5526
+ function useWorkflowStepDetail() {
5527
+ const context = React.useContext(WorkflowStepDetailContext);
5528
+ if (!context) {
5529
+ throw new Error("useWorkflowStepDetail must be used within WorkflowStepDetailProvider");
5530
+ }
5531
+ return context;
5532
+ }
5533
+ function WorkflowStepDetailProvider({ children }) {
5534
+ const [stepDetail, setStepDetail] = React.useState(null);
5535
+ const showMapConfig = React.useCallback(
5536
+ ({ stepName, stepId, mapConfig }) => {
5537
+ setStepDetail({
5538
+ type: "map-config",
5539
+ stepName,
5540
+ stepId,
5541
+ mapConfig
5542
+ });
5543
+ },
5544
+ []
5545
+ );
5546
+ const showNestedGraph = React.useCallback(
5547
+ ({ label, stepGraph, fullStep }) => {
5548
+ setStepDetail({
5549
+ type: "nested-graph",
5550
+ stepName: label,
5551
+ nestedGraph: {
5552
+ label,
5553
+ stepGraph,
5554
+ fullStep
5555
+ }
5556
+ });
5557
+ },
5558
+ []
5559
+ );
5560
+ const closeStepDetail = React.useCallback(() => {
5561
+ setStepDetail(null);
5562
+ }, []);
5563
+ return /* @__PURE__ */ jsxRuntime.jsx(
5564
+ WorkflowStepDetailContext.Provider,
5565
+ {
5566
+ value: {
5567
+ stepDetail,
5568
+ showMapConfig,
5569
+ showNestedGraph,
5570
+ closeStepDetail
5571
+ },
5572
+ children
5573
+ }
5574
+ );
5575
+ }
5576
+
5511
5577
  const WorkflowRunContext = React.createContext({});
5512
5578
  function WorkflowRunProvider({
5513
5579
  children,
@@ -5609,7 +5675,7 @@ function WorkflowRunProvider({
5609
5675
  isLoadingRunExecutionResult,
5610
5676
  withoutTimeTravel
5611
5677
  },
5612
- children
5678
+ children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowStepDetailProvider, { children })
5613
5679
  }
5614
5680
  );
5615
5681
  }
@@ -6268,26 +6334,46 @@ const SyntaxHighlighter$1 = ({ data }) => {
6268
6334
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md bg-[#1a1a1a] p-1 font-mono", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: formattedCode, theme, extensions: [langJson.jsonLanguage] }) });
6269
6335
  };
6270
6336
 
6271
- const CodeDialogContent = ({ data }) => {
6337
+ const CodeDialogContent = ({
6338
+ data,
6339
+ language = "auto"
6340
+ }) => {
6272
6341
  const theme = useCodemirrorTheme$1();
6342
+ const getExtensions = (content) => {
6343
+ if (language === "javascript") {
6344
+ return [langJavascript.javascript(), view.EditorView.lineWrapping];
6345
+ }
6346
+ if (language === "json") {
6347
+ return [langJson.jsonLanguage, view.EditorView.lineWrapping];
6348
+ }
6349
+ try {
6350
+ JSON.parse(content);
6351
+ return [langJson.jsonLanguage, view.EditorView.lineWrapping];
6352
+ } catch {
6353
+ if (content.includes("=>") || content.includes("function") || content.includes("const ") || content.includes("return ")) {
6354
+ return [langJavascript.javascript(), view.EditorView.lineWrapping];
6355
+ }
6356
+ return [view.EditorView.lineWrapping];
6357
+ }
6358
+ };
6273
6359
  if (typeof data !== "string") {
6360
+ const content = JSON.stringify(data, null, 2);
6274
6361
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6275
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: JSON.stringify(data, null, 2) }) }),
6276
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: JSON.stringify(data, null, 2), theme, extensions: [langJson.jsonLanguage] }) })
6362
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content }) }),
6363
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: content, theme, extensions: [langJson.jsonLanguage, view.EditorView.lineWrapping] }) })
6277
6364
  ] });
6278
6365
  }
6366
+ const extensions = getExtensions(data);
6367
+ let displayContent = data;
6279
6368
  try {
6280
6369
  const json = JSON.parse(data);
6281
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6282
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: data }) }),
6283
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: JSON.stringify(json, null, 2), theme, extensions: [langJson.jsonLanguage] }) })
6284
- ] });
6285
- } catch (error) {
6286
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6287
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: data }) }),
6288
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: data, theme, extensions: [] }) })
6289
- ] });
6370
+ displayContent = JSON.stringify(json, null, 2);
6371
+ } catch {
6290
6372
  }
6373
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6374
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: data }) }),
6375
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: displayContent, theme, extensions }) })
6376
+ ] });
6291
6377
  };
6292
6378
 
6293
6379
  const Form = React.forwardRef(({ children, ...props }, ref) => {
@@ -7801,9 +7887,9 @@ const WorkflowTimeTravelForm = ({ stepKey, closeModal }) => {
7801
7887
  const parsedResume = resumeData.trim() ? JSON.parse(resumeData) : {};
7802
7888
  const parsedContext = contextValue.trim() ? JSON.parse(contextValue) : {};
7803
7889
  const parsedNestedContext = nestedContextValue.trim() ? JSON.parse(nestedContextValue) : {};
7804
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
7890
+ const run = await createWorkflowRun({ workflowId, prevRunId });
7805
7891
  const payload = {
7806
- runId,
7892
+ runId: run.runId,
7807
7893
  workflowId,
7808
7894
  step: stepKey,
7809
7895
  inputData: data,
@@ -7915,12 +8001,29 @@ const WorkflowStepActionBar = ({
7915
8001
  const [isResumeDataOpen, setIsResumeDataOpen] = React.useState(false);
7916
8002
  const [isErrorOpen, setIsErrorOpen] = React.useState(false);
7917
8003
  const [isTripwireOpen, setIsTripwireOpen] = React.useState(false);
7918
- const [isMapConfigOpen, setIsMapConfigOpen] = React.useState(false);
7919
8004
  const [isTimeTravelOpen, setIsTimeTravelOpen] = React.useState(false);
7920
8005
  const { withoutTimeTravel } = React.useContext(WorkflowRunContext);
8006
+ const { showMapConfig, stepDetail, closeStepDetail } = useWorkflowStepDetail();
7921
8007
  const dialogContentClass = "bg-surface2 rounded-lg border-sm border-border1 max-w-4xl w-full px-0";
7922
8008
  const dialogTitleClass = "border-b-sm border-border1 pb-4 px-6";
7923
8009
  const showTimeTravel = !withoutTimeTravel && stepKey && !mapConfig;
8010
+ const isMapConfigOpen = stepDetail?.type === "map-config" && stepDetail?.stepName === stepName;
8011
+ const isNestedGraphOpen = stepDetail?.type === "nested-graph" && stepDetail?.stepName === stepName;
8012
+ const activeButtonClass = "ring-2 ring-accent1 ring-offset-1 ring-offset-transparent";
8013
+ const handleMapConfigClick = () => {
8014
+ if (isMapConfigOpen) {
8015
+ closeStepDetail();
8016
+ } else {
8017
+ showMapConfig({ stepName, stepId, mapConfig });
8018
+ }
8019
+ };
8020
+ const handleNestedGraphClick = () => {
8021
+ if (isNestedGraphOpen) {
8022
+ closeStepDetail();
8023
+ } else {
8024
+ onShowNestedGraph?.();
8025
+ }
8026
+ };
7924
8027
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (input || output || error || tripwire || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxRuntime.jsxs(
7925
8028
  "div",
7926
8029
  {
@@ -7934,7 +8037,7 @@ const WorkflowStepActionBar = ({
7934
8037
  status === "running" && "bg-accent6Dark"
7935
8038
  ),
7936
8039
  children: [
7937
- onShowNestedGraph && /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: onShowNestedGraph, children: "View nested graph" }),
8040
+ onShowNestedGraph && /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: handleNestedGraphClick, className: cn(isNestedGraphOpen && activeButtonClass), children: "View nested graph" }),
7938
8041
  showTimeTravel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7939
8042
  /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsTimeTravelOpen(true), children: "Time travel" }),
7940
8043
  /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isTimeTravelOpen, onOpenChange: setIsTimeTravelOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -7945,19 +8048,7 @@ const WorkflowStepActionBar = ({
7945
8048
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-scroll max-h-[600px]", children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowTimeTravelForm, { stepKey, closeModal: () => setIsTimeTravelOpen(false) }) })
7946
8049
  ] }) })
7947
8050
  ] }),
7948
- mapConfig && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7949
- /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsMapConfigOpen(true), children: "Map config" }),
7950
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isMapConfigOpen, onOpenChange: setIsMapConfigOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
7951
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: dialogTitleClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
7952
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7953
- stepName,
7954
- " Map Config"
7955
- ] }),
7956
- stepId && stepId !== stepName && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-icon3 font-normal", children: stepId })
7957
- ] }) }),
7958
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: mapConfig }) })
7959
- ] }) })
7960
- ] }),
8051
+ mapConfig && /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: handleMapConfigClick, className: cn(isMapConfigOpen && activeButtonClass), children: "Map config" }),
7961
8052
  input && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7962
8053
  /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsInputOpen(true), children: "Input" }),
7963
8054
  /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isInputOpen, onOpenChange: setIsInputOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -8099,7 +8190,7 @@ function WorkflowConditionNode({ data }) {
8099
8190
  "pre",
8100
8191
  {
8101
8192
  className: cn(
8102
- "relative font-mono p-3 w-full cursor-pointer rounded-lg text-xs !bg-surface4 overflow-scroll",
8193
+ "relative font-mono p-3 w-full cursor-pointer rounded-lg text-xs !bg-surface4 whitespace-pre-wrap break-words",
8103
8194
  className,
8104
8195
  previousDisplayStatus === "success" && nextStep && "!bg-accent1Dark",
8105
8196
  previousDisplayStatus === "failed" && nextStep && "!bg-accent2Dark",
@@ -8352,172 +8443,29 @@ function WorkflowLoopResultNode({ data }) {
8352
8443
  );
8353
8444
  }
8354
8445
 
8355
- function Spinner({ color = "#fff", className }) {
8356
- return /* @__PURE__ */ jsxRuntime.jsx(
8357
- "svg",
8358
- {
8359
- className: clsx("animate-spin duration-700", className),
8360
- xmlns: "http://www.w3.org/2000/svg",
8361
- width: "24",
8362
- height: "24",
8363
- viewBox: "0 0 24 24",
8364
- fill: "none",
8365
- stroke: "currentColor",
8366
- strokeWidth: "2",
8367
- strokeLinecap: "round",
8368
- strokeLinejoin: "round",
8369
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
8370
- }
8371
- );
8372
- }
8373
-
8374
- const Slider = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
8375
- SliderPrimitive__namespace.Root,
8376
- {
8377
- ref,
8378
- className: cn("relative flex w-full touch-none select-none items-center", className),
8379
- ...props,
8380
- children: [
8381
- /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Range, { className: "absolute h-full bg-primary/50" }) }),
8382
- /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.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" })
8383
- ]
8384
- }
8385
- ));
8386
- Slider.displayName = SliderPrimitive__namespace.Root.displayName;
8387
-
8388
- const ZoomSlider = React.forwardRef(({ className, ...props }) => {
8389
- const { zoom } = react$2.useViewport();
8390
- const { zoomTo, zoomIn, zoomOut, fitView } = react$2.useReactFlow();
8391
- return /* @__PURE__ */ jsxRuntime.jsxs(react$2.Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
8392
- /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "h-4 w-4" }) }),
8393
- /* @__PURE__ */ jsxRuntime.jsx(
8394
- Slider,
8395
- {
8396
- className: "w-[140px]",
8397
- value: [zoom],
8398
- min: 0.01,
8399
- max: 1,
8400
- step: 0.01,
8401
- onValueChange: (values) => {
8402
- zoomTo(values[0]);
8403
- }
8404
- }
8405
- ),
8406
- /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }) }),
8407
- /* @__PURE__ */ jsxRuntime.jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
8408
- (100 * zoom).toFixed(0),
8409
- "%"
8410
- ] }),
8411
- /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { className: "h-4 w-4" }) })
8412
- ] });
8413
- });
8414
- ZoomSlider.displayName = "ZoomSlider";
8415
-
8416
- function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
8417
- const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
8418
- stepGraph
8419
- });
8420
- const [isMounted, setIsMounted] = React.useState(false);
8421
- const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
8422
- const [edges] = react$2.useEdgesState(initialEdges);
8423
- const { steps } = useCurrentRun();
8424
- const nodeTypes = {
8425
- "default-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
8426
- "condition-node": WorkflowConditionNode,
8427
- "after-node": WorkflowAfterNode,
8428
- "loop-result-node": WorkflowLoopResultNode,
8429
- "nested-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
8430
- };
8431
- React.useEffect(() => {
8432
- if (open) {
8433
- setTimeout(() => {
8434
- setIsMounted(true);
8435
- }, 500);
8436
- }
8437
- }, [open]);
8438
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxRuntime.jsxs(
8439
- react$2.ReactFlow,
8440
- {
8441
- nodes,
8442
- edges: edges.map((e) => ({
8443
- ...e,
8444
- style: {
8445
- ...e.style,
8446
- 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
8447
- }
8448
- })),
8449
- fitView: true,
8450
- fitViewOptions: {
8451
- maxZoom: 1
8452
- },
8453
- minZoom: 0.01,
8454
- maxZoom: 1,
8455
- nodeTypes,
8456
- onNodesChange,
8457
- children: [
8458
- /* @__PURE__ */ jsxRuntime.jsx(ZoomSlider, { position: "bottom-left" }),
8459
- /* @__PURE__ */ jsxRuntime.jsx(react$2.Background, { variant: react$2.BackgroundVariant.Lines, gap: 12, size: 0.5 })
8460
- ]
8461
- }
8462
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) });
8463
- }
8464
-
8465
8446
  const WorkflowNestedGraphContext = React.createContext(
8466
8447
  {}
8467
8448
  );
8468
8449
  function WorkflowNestedGraphProvider({ children }) {
8469
- const [stepGraph, setStepGraph] = React.useState(null);
8470
- const [parentStepGraphList, setParentStepGraphList] = React.useState([]);
8471
- const [openDialog, setOpenDialog] = React.useState(false);
8472
- const [label, setLabel] = React.useState("");
8473
- const [fullStep, setFullStep] = React.useState("");
8474
- const closeNestedGraph = () => {
8475
- if (parentStepGraphList.length) {
8476
- const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
8477
- setStepGraph(lastStepGraph.stepGraph);
8478
- setLabel(lastStepGraph.label);
8479
- setFullStep(lastStepGraph.fullStep);
8480
- setParentStepGraphList(parentStepGraphList.slice(0, -1));
8481
- } else {
8482
- setOpenDialog(false);
8483
- setStepGraph(null);
8484
- setLabel("");
8485
- setFullStep("");
8486
- }
8487
- };
8450
+ const { showNestedGraph: showNestedGraphInPanel, closeStepDetail } = useWorkflowStepDetail();
8488
8451
  const showNestedGraph = ({
8489
- label: newLabel,
8490
- stepGraph: newStepGraph,
8491
- fullStep: newFullStep
8452
+ label,
8453
+ stepGraph,
8454
+ fullStep
8492
8455
  }) => {
8493
- if (stepGraph) {
8494
- setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
8495
- }
8496
- setLabel(newLabel);
8497
- setFullStep(newFullStep);
8498
- setStepGraph(newStepGraph);
8499
- setOpenDialog(true);
8456
+ showNestedGraphInPanel({ label, stepGraph, fullStep });
8500
8457
  };
8501
- return /* @__PURE__ */ jsxRuntime.jsxs(
8458
+ const closeNestedGraph = () => {
8459
+ closeStepDetail();
8460
+ };
8461
+ return /* @__PURE__ */ jsxRuntime.jsx(
8502
8462
  WorkflowNestedGraphContext.Provider,
8503
8463
  {
8504
8464
  value: {
8505
8465
  showNestedGraph,
8506
8466
  closeNestedGraph
8507
8467
  },
8508
- children: [
8509
- children,
8510
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: openDialog, onOpenChange: closeNestedGraph, children: /* @__PURE__ */ jsxRuntime.jsx(DialogPortal, { children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "w-[45rem] h-[45rem] max-w-[unset] bg-[#121212] p-[0.5rem]", children: [
8511
- /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
8512
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "text-current w-4 h-4" }),
8513
- /* @__PURE__ */ jsxRuntime.jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
8514
- label,
8515
- " workflow"
8516
- ] })
8517
- ] }),
8518
- /* @__PURE__ */ jsxRuntime.jsx(react$2.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedGraph, { stepGraph, open: openDialog, workflowName: fullStep }) })
8519
- ] }) }) }, `${label}-${fullStep}`)
8520
- ]
8468
+ children
8521
8469
  }
8522
8470
  );
8523
8471
  }
@@ -8616,6 +8564,48 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8616
8564
  ] });
8617
8565
  }
8618
8566
 
8567
+ const Slider = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
8568
+ SliderPrimitive__namespace.Root,
8569
+ {
8570
+ ref,
8571
+ className: cn("relative flex w-full touch-none select-none items-center", className),
8572
+ ...props,
8573
+ children: [
8574
+ /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Range, { className: "absolute h-full bg-primary/50" }) }),
8575
+ /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.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" })
8576
+ ]
8577
+ }
8578
+ ));
8579
+ Slider.displayName = SliderPrimitive__namespace.Root.displayName;
8580
+
8581
+ const ZoomSlider = React.forwardRef(({ className, ...props }) => {
8582
+ const { zoom } = react$2.useViewport();
8583
+ const { zoomTo, zoomIn, zoomOut, fitView } = react$2.useReactFlow();
8584
+ return /* @__PURE__ */ jsxRuntime.jsxs(react$2.Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
8585
+ /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "h-4 w-4" }) }),
8586
+ /* @__PURE__ */ jsxRuntime.jsx(
8587
+ Slider,
8588
+ {
8589
+ className: "w-[140px]",
8590
+ value: [zoom],
8591
+ min: 0.01,
8592
+ max: 1,
8593
+ step: 0.01,
8594
+ onValueChange: (values) => {
8595
+ zoomTo(values[0]);
8596
+ }
8597
+ }
8598
+ ),
8599
+ /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }) }),
8600
+ /* @__PURE__ */ jsxRuntime.jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
8601
+ (100 * zoom).toFixed(0),
8602
+ "%"
8603
+ ] }),
8604
+ /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { className: "h-4 w-4" }) })
8605
+ ] });
8606
+ });
8607
+ ZoomSlider.displayName = "ZoomSlider";
8608
+
8619
8609
  function WorkflowGraphInner({ workflow }) {
8620
8610
  const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
8621
8611
  const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
@@ -8824,11 +8814,11 @@ function WorkflowTrigger({
8824
8814
  setIsRunning(true);
8825
8815
  setCancelResponse(null);
8826
8816
  setResult(null);
8827
- const { runId } = await createWorkflowRun({ workflowId });
8828
- setRunId?.(runId);
8829
- setInnerRunId(runId);
8830
- setContextRunId(runId);
8831
- streamWorkflow({ workflowId, runId, inputData: data, requestContext });
8817
+ const run = await createWorkflowRun({ workflowId });
8818
+ setRunId?.(run.runId);
8819
+ setInnerRunId(run.runId);
8820
+ setContextRunId(run.runId);
8821
+ streamWorkflow({ workflowId, runId: run.runId, inputData: data, requestContext });
8832
8822
  } catch (err) {
8833
8823
  setIsRunning(false);
8834
8824
  sonner.toast.error("Error executing workflow");
@@ -8838,10 +8828,10 @@ function WorkflowTrigger({
8838
8828
  if (!workflow) return;
8839
8829
  setCancelResponse(null);
8840
8830
  const { stepId, runId: prevRunId, resumeData } = step;
8841
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
8831
+ const run = await createWorkflowRun({ workflowId, prevRunId });
8842
8832
  await resumeWorkflow({
8843
8833
  step: stepId,
8844
- runId,
8834
+ runId: run.runId,
8845
8835
  resumeData,
8846
8836
  workflowId,
8847
8837
  requestContext
@@ -8885,7 +8875,7 @@ function WorkflowTrigger({
8885
8875
  const workflowActivePaths = streamResultToUse?.steps ?? {};
8886
8876
  const hasWorkflowActivePaths = Object.values(workflowActivePaths).length > 0;
8887
8877
  const doneStatuses = ["success", "failed", "canceled", "tripwire"];
8888
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full pt-3 pb-12 overflow-y-auto", children: [
8878
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full pt-3 overflow-y-auto", children: [
8889
8879
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 px-5 pb-5 border-b-sm border-border1", children: [
8890
8880
  isSuspendedSteps && isStreamingWorkflow && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2 px-5 flex items-center gap-2 bg-surface5 -mx-5 -mt-5 border-b-sm border-border1", children: [
8891
8881
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin text-icon6" }) }),
@@ -8968,12 +8958,16 @@ function WorkflowTrigger({
8968
8958
  const { status } = step;
8969
8959
  let output = void 0;
8970
8960
  let suspendOutput = void 0;
8961
+ let error = void 0;
8971
8962
  if (step.status === "suspended") {
8972
8963
  suspendOutput = step.suspendOutput;
8973
8964
  }
8974
8965
  if (step.status === "success") {
8975
8966
  output = step.output;
8976
8967
  }
8968
+ if (step.status === "failed") {
8969
+ error = step.error;
8970
+ }
8977
8971
  const tripwireInfo = step.status === "failed" && step.tripwire ? step.tripwire : streamResultToUse?.status === "tripwire" ? {
8978
8972
  reason: streamResultToUse?.tripwire?.reason,
8979
8973
  retry: streamResultToUse?.tripwire?.retry,
@@ -8986,7 +8980,7 @@ function WorkflowTrigger({
8986
8980
  {
8987
8981
  stepId,
8988
8982
  status: displayStatus,
8989
- result: output ?? suspendOutput ?? {},
8983
+ result: output ?? suspendOutput ?? error ?? {},
8990
8984
  tripwire: tripwireInfo
8991
8985
  },
8992
8986
  stepId
@@ -9369,18 +9363,17 @@ const columns$4 = [
9369
9363
  }
9370
9364
  ];
9371
9365
 
9372
- const themeClasses = {
9373
- light: "bg-gray-100 border-gray-300 text-gray-700",
9374
- dark: "bg-surface4 border-border1 text-icon6"
9375
- };
9376
- const Kbd = ({ children, theme = "dark" }) => {
9377
- const themeClass = themeClasses[theme];
9378
- return /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: clsx("border-sm rounded-md px-1 py-0.5 font-mono", themeClass), children });
9379
- };
9380
-
9381
- const Searchbar = ({ onSearch, label, placeholder }) => {
9366
+ const Searchbar = ({ onSearch, label, placeholder, debounceMs = 300 }) => {
9382
9367
  const id = React.useId();
9383
9368
  const inputRef = React.useRef(null);
9369
+ const debouncedSearch = useDebounce.useDebouncedCallback((value) => {
9370
+ onSearch(value);
9371
+ }, debounceMs);
9372
+ React.useEffect(() => {
9373
+ return () => {
9374
+ debouncedSearch.cancel();
9375
+ };
9376
+ }, [debouncedSearch]);
9384
9377
  React.useEffect(() => {
9385
9378
  const input = inputRef.current;
9386
9379
  if (!input) return;
@@ -9395,37 +9388,27 @@ const Searchbar = ({ onSearch, label, placeholder }) => {
9395
9388
  window.removeEventListener("keydown", handleKeyDown);
9396
9389
  };
9397
9390
  }, []);
9398
- const handleSubmit = (e) => {
9399
- e.preventDefault();
9400
- const formData = new FormData(e.target);
9401
- const search = formData.get(id);
9402
- onSearch(search);
9391
+ const handleChange = (e) => {
9392
+ debouncedSearch(e.target.value);
9403
9393
  };
9404
- return /* @__PURE__ */ jsxRuntime.jsxs(
9405
- "form",
9406
- {
9407
- onSubmit: handleSubmit,
9408
- 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",
9409
- children: [
9410
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "text-icon3 h-4 w-4" }),
9411
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
9412
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "sr-only", children: label }),
9413
- /* @__PURE__ */ jsxRuntime.jsx(
9414
- "input",
9415
- {
9416
- id,
9417
- type: "text",
9418
- placeholder,
9419
- className: "bg-surface2 text-ui-md placeholder:text-icon-3 block h-8 w-full px-2 outline-none",
9420
- name: id,
9421
- ref: inputRef
9422
- }
9423
- )
9424
- ] }),
9425
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "text-ui-sm text-icon3 flex flex-row items-center gap-1", children: /* @__PURE__ */ jsxRuntime.jsx(Kbd, { children: "↵ Enter" }) })
9426
- ]
9427
- }
9428
- );
9394
+ return /* @__PURE__ */ jsxRuntime.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: [
9395
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "text-icon3 h-4 w-4" }),
9396
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
9397
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "sr-only", children: label }),
9398
+ /* @__PURE__ */ jsxRuntime.jsx(
9399
+ "input",
9400
+ {
9401
+ id,
9402
+ type: "text",
9403
+ placeholder,
9404
+ className: "bg-surface2 text-ui-md placeholder:text-icon-3 block h-8 w-full px-2 outline-none",
9405
+ name: id,
9406
+ ref: inputRef,
9407
+ onChange: handleChange
9408
+ }
9409
+ )
9410
+ ] })
9411
+ ] });
9429
9412
  };
9430
9413
  const SearchbarWrapper = ({ children }) => {
9431
9414
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 border-b-sm border-border1", children });
@@ -9555,14 +9538,28 @@ const PlaygroundTabs = ({
9555
9538
  const TabList$1 = ({ children, className }) => {
9556
9539
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-x-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(TabsList, { className: "border-b border-border1 flex min-w-full shrink-0", children }) });
9557
9540
  };
9558
- const Tab$1 = ({ children, value, onClick }) => {
9559
- return /* @__PURE__ */ jsxRuntime.jsx(
9541
+ const Tab$1 = ({ children, value, onClick, onClose }) => {
9542
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9560
9543
  TabsTrigger,
9561
9544
  {
9562
9545
  value,
9563
- 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",
9546
+ 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",
9564
9547
  onClick,
9565
- children
9548
+ children: [
9549
+ children,
9550
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(
9551
+ "button",
9552
+ {
9553
+ onClick: (e) => {
9554
+ e.stopPropagation();
9555
+ onClose();
9556
+ },
9557
+ className: "p-0.5 hover:bg-surface3 rounded transition-colors",
9558
+ "aria-label": "Close tab",
9559
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
9560
+ }
9561
+ )
9562
+ ]
9566
9563
  }
9567
9564
  );
9568
9565
  };
@@ -9603,7 +9600,114 @@ const TracingRunOptions = () => {
9603
9600
  }
9604
9601
  )
9605
9602
  ] });
9606
- };
9603
+ };
9604
+
9605
+ function Spinner({ color = "#fff", className }) {
9606
+ return /* @__PURE__ */ jsxRuntime.jsx(
9607
+ "svg",
9608
+ {
9609
+ className: clsx("animate-spin duration-700", className),
9610
+ xmlns: "http://www.w3.org/2000/svg",
9611
+ width: "24",
9612
+ height: "24",
9613
+ viewBox: "0 0 24 24",
9614
+ fill: "none",
9615
+ stroke: "currentColor",
9616
+ strokeWidth: "2",
9617
+ strokeLinecap: "round",
9618
+ strokeLinejoin: "round",
9619
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
9620
+ }
9621
+ );
9622
+ }
9623
+
9624
+ function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
9625
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
9626
+ stepGraph
9627
+ });
9628
+ const [isMounted, setIsMounted] = React.useState(false);
9629
+ const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
9630
+ const [edges] = react$2.useEdgesState(initialEdges);
9631
+ const { steps } = useCurrentRun();
9632
+ const nodeTypes = {
9633
+ "default-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
9634
+ "condition-node": WorkflowConditionNode,
9635
+ "after-node": WorkflowAfterNode,
9636
+ "loop-result-node": WorkflowLoopResultNode,
9637
+ "nested-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
9638
+ };
9639
+ React.useEffect(() => {
9640
+ if (open) {
9641
+ setTimeout(() => {
9642
+ setIsMounted(true);
9643
+ }, 500);
9644
+ }
9645
+ }, [open]);
9646
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxRuntime.jsxs(
9647
+ react$2.ReactFlow,
9648
+ {
9649
+ nodes,
9650
+ edges: edges.map((e) => ({
9651
+ ...e,
9652
+ style: {
9653
+ ...e.style,
9654
+ 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
9655
+ }
9656
+ })),
9657
+ fitView: true,
9658
+ fitViewOptions: {
9659
+ maxZoom: 1
9660
+ },
9661
+ minZoom: 0.01,
9662
+ maxZoom: 1,
9663
+ nodeTypes,
9664
+ onNodesChange,
9665
+ children: [
9666
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomSlider, { position: "bottom-left" }),
9667
+ /* @__PURE__ */ jsxRuntime.jsx(react$2.Background, { variant: react$2.BackgroundVariant.Lines, gap: 12, size: 0.5 })
9668
+ ]
9669
+ }
9670
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) });
9671
+ }
9672
+
9673
+ function WorkflowStepDetailContent() {
9674
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9675
+ if (!stepDetail) {
9676
+ return null;
9677
+ }
9678
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
9679
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b-sm border-border1 bg-surface1", children: [
9680
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9681
+ stepDetail.type === "map-config" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "w-4 h-4", style: { color: BADGE_COLORS.map } }),
9682
+ stepDetail.type === "nested-graph" && /* @__PURE__ */ jsxRuntime.jsx(WorkflowIcon, { className: "w-4 h-4", style: { color: BADGE_COLORS.workflow } }),
9683
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
9684
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-md", className: "text-icon6 font-medium", children: stepDetail.type === "map-config" ? `${stepDetail.stepName} Config` : `${stepDetail.stepName} Workflow` }),
9685
+ stepDetail.type === "map-config" && stepDetail.stepId && stepDetail.stepId !== stepDetail.stepName && /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-icon3", children: stepDetail.stepId })
9686
+ ] })
9687
+ ] }),
9688
+ /* @__PURE__ */ jsxRuntime.jsx(
9689
+ "button",
9690
+ {
9691
+ onClick: closeStepDetail,
9692
+ className: "p-1 hover:bg-surface3 rounded transition-colors",
9693
+ "aria-label": "Close",
9694
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4 text-icon3" })
9695
+ }
9696
+ )
9697
+ ] }),
9698
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto", children: [
9699
+ stepDetail.type === "map-config" && stepDetail.mapConfig && /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: stepDetail.mapConfig }),
9700
+ stepDetail.type === "nested-graph" && stepDetail.nestedGraph && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[400px]", children: /* @__PURE__ */ jsxRuntime.jsx(react$2.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
9701
+ WorkflowNestedGraph,
9702
+ {
9703
+ stepGraph: stepDetail.nestedGraph.stepGraph,
9704
+ open: true,
9705
+ workflowName: stepDetail.nestedGraph.fullStep
9706
+ }
9707
+ ) }) })
9708
+ ] })
9709
+ ] });
9710
+ }
9607
9711
 
9608
9712
  function WorkflowInformation({ workflowId, initialRunId }) {
9609
9713
  const { data: workflow, isLoading, error } = useWorkflow(workflowId);
@@ -9618,10 +9722,21 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9618
9722
  cancelWorkflowRun,
9619
9723
  isCancellingWorkflowRun
9620
9724
  } = React.useContext(WorkflowRunContext);
9725
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9621
9726
  const [tab, setTab] = React.useState("current-run");
9622
9727
  const [runId, setRunId] = React.useState("");
9623
9728
  const { handleCopy } = useCopyToClipboard({ text: workflowId });
9624
9729
  const stepsCount = Object.keys(workflow?.steps ?? {}).length;
9730
+ const nodeDetailTabName = React.useMemo(() => {
9731
+ if (!stepDetail) return null;
9732
+ if (stepDetail.type === "map-config") {
9733
+ return "Map Config";
9734
+ }
9735
+ if (stepDetail.type === "nested-graph") {
9736
+ return "Nested Workflow";
9737
+ }
9738
+ return "Node";
9739
+ }, [stepDetail]);
9625
9740
  React.useEffect(() => {
9626
9741
  if (!runId && !initialRunId) {
9627
9742
  closeStreamsAndReset();
@@ -9633,6 +9748,19 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9633
9748
  toast.error(`Error loading workflow: ${errorMessage}`);
9634
9749
  }
9635
9750
  }, [error]);
9751
+ React.useEffect(() => {
9752
+ if (stepDetail) {
9753
+ setTab("node-details");
9754
+ } else if (tab === "node-details") {
9755
+ setTab("current-run");
9756
+ }
9757
+ }, [stepDetail]);
9758
+ const handleTabChange = (newTab) => {
9759
+ if (tab === "node-details" && newTab !== "node-details") {
9760
+ closeStepDetail();
9761
+ }
9762
+ setTab(newTab);
9763
+ };
9636
9764
  if (error) {
9637
9765
  return null;
9638
9766
  }
@@ -9649,10 +9777,24 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9649
9777
  ] }),
9650
9778
  workflow?.isProcessorWorkflow && /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cpu, { className: "h-3 w-3" }), className: "bg-violet-500/20 text-violet-400", children: "Processor" })
9651
9779
  ] }) }),
9652
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden border-t-sm border-border1 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs(PlaygroundTabs, { defaultTab: "current-run", value: tab, onValueChange: setTab, children: [
9780
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto border-t-sm border-border1 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs(PlaygroundTabs, { defaultTab: "current-run", value: tab, onValueChange: handleTabChange, className: "h-full", children: [
9653
9781
  /* @__PURE__ */ jsxRuntime.jsxs(TabList$1, { children: [
9654
9782
  /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "current-run", children: "Current Run" }),
9655
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "run-options", children: "Run options" })
9783
+ /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "run-options", children: "Run Options" }),
9784
+ stepDetail && nodeDetailTabName && /* @__PURE__ */ jsxRuntime.jsxs(
9785
+ Tab$1,
9786
+ {
9787
+ value: "node-details",
9788
+ onClose: () => {
9789
+ closeStepDetail();
9790
+ setTab("current-run");
9791
+ },
9792
+ children: [
9793
+ nodeDetailTabName,
9794
+ " Details"
9795
+ ]
9796
+ }
9797
+ )
9656
9798
  ] }),
9657
9799
  /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "current-run", children: workflowId ? initialRunId ? /* @__PURE__ */ jsxRuntime.jsx(
9658
9800
  WorkflowRunDetail,
@@ -9687,7 +9829,8 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9687
9829
  cancelWorkflowRun
9688
9830
  }
9689
9831
  ) : null }),
9690
- /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsxRuntime.jsx(TracingRunOptions, {}) })
9832
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsxRuntime.jsx(TracingRunOptions, {}) }),
9833
+ stepDetail && /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "node-details", children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowStepDetailContent, {}) })
9691
9834
  ] }) })
9692
9835
  ] });
9693
9836
  }
@@ -9919,7 +10062,8 @@ const WorkflowBadge = ({
9919
10062
  isStreaming,
9920
10063
  metadata,
9921
10064
  toolCallId,
9922
- toolApprovalMetadata
10065
+ toolApprovalMetadata,
10066
+ suspendPayload
9923
10067
  }) => {
9924
10068
  const { runId, status } = result || {};
9925
10069
  const { data: workflow, isLoading: isWorkflowLoading } = useWorkflow(workflowId);
@@ -9931,6 +10075,7 @@ const WorkflowBadge = ({
9931
10075
  const snapshot = typeof run?.snapshot === "object" ? run?.snapshot : void 0;
9932
10076
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
9933
10077
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
10078
+ let suspendPayloadSlot = typeof suspendPayload === "string" ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: suspendPayload }) : /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlighter$1, { data: suspendPayload, "data-testid": "tool-suspend-payload" });
9934
10079
  if (isWorkflowLoading || !workflow) return /* @__PURE__ */ jsxRuntime.jsx(LoadingBadge, {});
9935
10080
  return /* @__PURE__ */ jsxRuntime.jsxs(
9936
10081
  BadgeWrapper,
@@ -9947,6 +10092,10 @@ const WorkflowBadge = ({
9947
10092
  }
9948
10093
  ),
9949
10094
  children: [
10095
+ suspendPayloadSlot !== void 0 && suspendPayload && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10096
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool suspend payload" }),
10097
+ suspendPayloadSlot
10098
+ ] }),
9950
10099
  !isStreaming && !isLoading && /* @__PURE__ */ jsxRuntime.jsx(WorkflowRunProvider, { snapshot, workflowId, initialRunId: runId, withoutTimeTravel: true, children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }) }),
9951
10100
  isStreaming && /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }),
9952
10101
  /* @__PURE__ */ jsxRuntime.jsx(ToolApprovalButtons, { toolCalled: !!status, toolCallId, toolApprovalMetadata })
@@ -10082,7 +10231,9 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10082
10231
  const agentToolName = toolName.startsWith("agent-") ? toolName.substring("agent-".length) : toolName;
10083
10232
  const workflowToolName = toolName.startsWith("workflow-") ? toolName.substring("workflow-".length) : toolName;
10084
10233
  const requireApprovalMetadata = metadata?.mode === "stream" && metadata?.requireApprovalMetadata;
10085
- const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolCallId] : void 0;
10234
+ const suspendedTools = metadata?.mode === "stream" && metadata?.suspendedTools;
10235
+ const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolName] ?? requireApprovalMetadata?.[toolCallId] : void 0;
10236
+ const suspendedToolMetadata = suspendedTools ? suspendedTools?.[toolName] : void 0;
10086
10237
  useWorkflowStream(result);
10087
10238
  if (isAgent) {
10088
10239
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -10106,7 +10257,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10106
10257
  result,
10107
10258
  metadata,
10108
10259
  toolCallId,
10109
- toolApprovalMetadata
10260
+ toolApprovalMetadata,
10261
+ suspendPayload: suspendedToolMetadata?.suspendPayload
10110
10262
  }
10111
10263
  );
10112
10264
  }
@@ -10119,7 +10271,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
10119
10271
  toolOutput: result?.toolOutput || [],
10120
10272
  metadata,
10121
10273
  toolCallId,
10122
- toolApprovalMetadata
10274
+ toolApprovalMetadata,
10275
+ suspendPayload: suspendedToolMetadata?.suspendPayload
10123
10276
  }
10124
10277
  );
10125
10278
  };
@@ -11200,25 +11353,36 @@ const ThreadWelcome = ({ agentName }) => {
11200
11353
  };
11201
11354
  const Composer = ({ hasMemory, agentId }) => {
11202
11355
  const { setThreadInput } = useThreadInput();
11356
+ const textareaRef = React.useRef(null);
11203
11357
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-4", children: /* @__PURE__ */ jsxRuntime.jsxs(react.ComposerPrimitive.Root, { children: [
11204
11358
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[568px] w-full mx-auto pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(ComposerAttachments, {}) }),
11205
- /* @__PURE__ */ jsxRuntime.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: [
11206
- /* @__PURE__ */ jsxRuntime.jsx(react.ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
11207
- "textarea",
11208
- {
11209
- className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11210
- autoFocus: document.activeElement === document.body,
11211
- placeholder: "Enter your message...",
11212
- name: "",
11213
- id: "",
11214
- onChange: (e) => setThreadInput?.(e.target.value)
11215
- }
11216
- ) }),
11217
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11218
- /* @__PURE__ */ jsxRuntime.jsx(SpeechInput, { agentId }),
11219
- /* @__PURE__ */ jsxRuntime.jsx(ComposerAction, {})
11220
- ] })
11221
- ] })
11359
+ /* @__PURE__ */ jsxRuntime.jsxs(
11360
+ "div",
11361
+ {
11362
+ 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",
11363
+ onClick: () => {
11364
+ textareaRef.current?.focus();
11365
+ },
11366
+ children: [
11367
+ /* @__PURE__ */ jsxRuntime.jsx(react.ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
11368
+ "textarea",
11369
+ {
11370
+ ref: textareaRef,
11371
+ className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11372
+ autoFocus: document.activeElement === document.body,
11373
+ placeholder: "Enter your message...",
11374
+ name: "",
11375
+ id: "",
11376
+ onChange: (e) => setThreadInput?.(e.target.value)
11377
+ }
11378
+ ) }),
11379
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11380
+ /* @__PURE__ */ jsxRuntime.jsx(SpeechInput, { agentId }),
11381
+ /* @__PURE__ */ jsxRuntime.jsx(ComposerAction, {})
11382
+ ] })
11383
+ ]
11384
+ }
11385
+ )
11222
11386
  ] }) });
11223
11387
  };
11224
11388
  const SpeechInput = ({ agentId }) => {
@@ -11556,34 +11720,33 @@ function useAgentSettingsState({ agentId, defaultSettings: defaultSettingsProp }
11556
11720
  React.useEffect(() => {
11557
11721
  try {
11558
11722
  const stored = localStorage.getItem(LOCAL_STORAGE_KEY);
11559
- if (stored) {
11560
- const parsed = JSON.parse(stored);
11561
- const settings2 = {
11562
- ...parsed,
11563
- modelSettings: {
11564
- ...defaultSettingsProp?.modelSettings ?? {},
11565
- ...parsed?.modelSettings ?? {}
11566
- }
11567
- };
11568
- setSettingsState(settings2 ?? void 0);
11569
- }
11723
+ const parsed = stored ? JSON.parse(stored) : {};
11724
+ const mergedSettings = {
11725
+ ...parsed,
11726
+ modelSettings: {
11727
+ ...defaultSettings.modelSettings,
11728
+ ...parsed?.modelSettings ?? {},
11729
+ ...defaultSettingsProp?.modelSettings ?? {}
11730
+ // Code defaults win
11731
+ }
11732
+ };
11733
+ setSettingsState(mergedSettings);
11570
11734
  } catch (e) {
11571
- console.error(e);
11572
11735
  }
11573
- }, [LOCAL_STORAGE_KEY]);
11736
+ }, [LOCAL_STORAGE_KEY, defaultSettingsProp]);
11574
11737
  const setSettings = (settingsValue) => {
11575
11738
  setSettingsState((prev) => ({ ...prev, ...settingsValue }));
11576
11739
  localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ ...settingsValue, agentId }));
11577
11740
  };
11578
11741
  const resetAll = () => {
11579
- const settings2 = {
11742
+ const resetSettings = {
11580
11743
  modelSettings: {
11581
- ...defaultSettingsProp?.modelSettings ?? {},
11582
- ...defaultSettings.modelSettings
11744
+ ...defaultSettings.modelSettings,
11745
+ ...defaultSettingsProp?.modelSettings ?? {}
11583
11746
  }
11584
11747
  };
11585
- setSettingsState(settings2);
11586
- localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(settings2));
11748
+ setSettingsState(resetSettings);
11749
+ localStorage.removeItem(LOCAL_STORAGE_KEY);
11587
11750
  };
11588
11751
  return {
11589
11752
  settings,
@@ -11734,18 +11897,19 @@ const initializeMessageState = (initialMessages) => {
11734
11897
  };
11735
11898
  } else if (part.toolInvocation.state === "call") {
11736
11899
  const toolCallId = part.toolInvocation.toolCallId;
11900
+ const toolName = part.toolInvocation.toolName;
11737
11901
  const pendingToolApprovals = message.metadata?.pendingToolApprovals;
11738
11902
  const suspensionData = pendingToolApprovals?.[toolCallId];
11739
11903
  if (suspensionData) {
11740
11904
  return {
11741
11905
  type: "tool-call",
11742
11906
  toolCallId,
11743
- toolName: part.toolInvocation.toolName,
11907
+ toolName,
11744
11908
  args: part.toolInvocation.args,
11745
11909
  metadata: {
11746
11910
  mode: "stream",
11747
11911
  requireApprovalMetadata: {
11748
- [toolCallId]: suspensionData
11912
+ [toolName]: suspensionData
11749
11913
  }
11750
11914
  }
11751
11915
  };
@@ -11815,6 +11979,7 @@ function MastraRuntimeProvider({
11815
11979
  temperature,
11816
11980
  topK,
11817
11981
  topP,
11982
+ seed,
11818
11983
  chatWithGenerateLegacy,
11819
11984
  chatWithGenerate,
11820
11985
  chatWithNetwork,
@@ -11833,19 +11998,21 @@ function MastraRuntimeProvider({
11833
11998
  temperature,
11834
11999
  topK,
11835
12000
  topP,
11836
- maxTokens,
12001
+ seed,
12002
+ maxOutputTokens: maxTokens,
12003
+ // AI SDK v5 uses maxOutputTokens
11837
12004
  instructions,
11838
12005
  providerOptions,
11839
12006
  maxSteps,
11840
12007
  requireToolApproval
11841
12008
  };
11842
12009
  const baseClient = react$1.useMastraClient();
11843
- const isVNext = modelVersion === "v2";
12010
+ const isSupportedModel = modelVersion === "v2" || modelVersion === "v3";
11844
12011
  const onNew = async (message) => {
11845
12012
  if (message.content[0]?.type !== "text") throw new Error("Only text messages are supported");
11846
12013
  const attachments = await convertToAIAttachments(message.attachments);
11847
12014
  const input = message.content[0].text;
11848
- if (!isVNext) {
12015
+ if (!isSupportedModel) {
11849
12016
  setLegacyMessages((s) => [...s, { role: "user", content: input, attachments: message.attachments }]);
11850
12017
  }
11851
12018
  const controller = new AbortController();
@@ -11856,7 +12023,7 @@ function MastraRuntimeProvider({
11856
12023
  });
11857
12024
  const agent = clientWithAbort.getAgent(agentId);
11858
12025
  try {
11859
- if (isVNext) {
12026
+ if (isSupportedModel) {
11860
12027
  if (chatWithNetwork) {
11861
12028
  await sendMessage({
11862
12029
  message: input,
@@ -11932,6 +12099,7 @@ function MastraRuntimeProvider({
11932
12099
  temperature,
11933
12100
  topK,
11934
12101
  topP,
12102
+ seed,
11935
12103
  instructions,
11936
12104
  requestContext: requestContextInstance,
11937
12105
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -12048,6 +12216,7 @@ function MastraRuntimeProvider({
12048
12216
  temperature,
12049
12217
  topK,
12050
12218
  topP,
12219
+ seed,
12051
12220
  instructions,
12052
12221
  requestContext: requestContextInstance,
12053
12222
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -12197,7 +12366,7 @@ function MastraRuntimeProvider({
12197
12366
  if (error.name === "AbortError") {
12198
12367
  return;
12199
12368
  }
12200
- if (isVNext) {
12369
+ if (isSupportedModel) {
12201
12370
  setMessages((currentConversation) => [
12202
12371
  ...currentConversation,
12203
12372
  { role: "assistant", parts: [{ type: "text", text: `${error}` }] }
@@ -12224,7 +12393,7 @@ function MastraRuntimeProvider({
12224
12393
  const vnextmessages = messages.map(react$1.toAssistantUIMessage);
12225
12394
  const runtime = react.useExternalStoreRuntime({
12226
12395
  isRunning: isLegacyRunning || isRunningStream,
12227
- messages: isVNext ? vnextmessages : legacyMessages,
12396
+ messages: isSupportedModel ? vnextmessages : legacyMessages,
12228
12397
  convertMessage: (x) => x,
12229
12398
  onNew,
12230
12399
  onCancel,
@@ -12368,54 +12537,60 @@ const AgentAdvancedSettings = () => {
12368
12537
  ] }),
12369
12538
  /* @__PURE__ */ jsxRuntime.jsxs(CollapsibleContent, { className: collapsibleContentClassName, children: [
12370
12539
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12371
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12540
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12372
12541
  /* @__PURE__ */ jsxRuntime.jsx(
12373
12542
  Input,
12374
12543
  {
12375
- id: "top-k",
12544
+ id: "frequency-penalty",
12376
12545
  type: "number",
12377
- value: settings?.modelSettings?.topK || "",
12546
+ step: "0.1",
12547
+ min: "-1",
12548
+ max: "1",
12549
+ value: settings?.modelSettings?.frequencyPenalty ?? "",
12378
12550
  onChange: (e) => setSettings({
12379
12551
  ...settings,
12380
12552
  modelSettings: {
12381
12553
  ...settings?.modelSettings,
12382
- topK: e.target.value ? Number(e.target.value) : void 0
12554
+ frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12383
12555
  }
12384
12556
  })
12385
12557
  }
12386
12558
  )
12387
12559
  ] }),
12388
12560
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12389
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12561
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12390
12562
  /* @__PURE__ */ jsxRuntime.jsx(
12391
12563
  Input,
12392
12564
  {
12393
- id: "frequency-penalty",
12565
+ id: "presence-penalty",
12394
12566
  type: "number",
12395
- value: settings?.modelSettings?.frequencyPenalty || "",
12567
+ step: "0.1",
12568
+ min: "-1",
12569
+ max: "1",
12570
+ value: settings?.modelSettings?.presencePenalty ?? "",
12396
12571
  onChange: (e) => setSettings({
12397
12572
  ...settings,
12398
12573
  modelSettings: {
12399
12574
  ...settings?.modelSettings,
12400
- frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12575
+ presencePenalty: e.target.value ? Number(e.target.value) : void 0
12401
12576
  }
12402
12577
  })
12403
12578
  }
12404
12579
  )
12405
12580
  ] }),
12406
12581
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12407
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12582
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12408
12583
  /* @__PURE__ */ jsxRuntime.jsx(
12409
12584
  Input,
12410
12585
  {
12411
- id: "presence-penalty",
12586
+ id: "top-k",
12412
12587
  type: "number",
12413
- value: settings?.modelSettings?.presencePenalty || "",
12588
+ value: settings?.modelSettings?.topK || "",
12414
12589
  onChange: (e) => setSettings({
12415
12590
  ...settings,
12416
12591
  modelSettings: {
12417
12592
  ...settings?.modelSettings,
12418
- presencePenalty: e.target.value ? Number(e.target.value) : void 0
12593
+ topK: e.target.value ? Number(e.target.value) : void 0
12419
12594
  }
12420
12595
  })
12421
12596
  }
@@ -12475,6 +12650,24 @@ const AgentAdvancedSettings = () => {
12475
12650
  }
12476
12651
  )
12477
12652
  ] }),
12653
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12654
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "seed", children: "Seed" }),
12655
+ /* @__PURE__ */ jsxRuntime.jsx(
12656
+ Input,
12657
+ {
12658
+ id: "seed",
12659
+ type: "number",
12660
+ value: settings?.modelSettings?.seed || "",
12661
+ onChange: (e) => setSettings({
12662
+ ...settings,
12663
+ modelSettings: {
12664
+ ...settings?.modelSettings,
12665
+ seed: e.target.value ? Number(e.target.value) : void 0
12666
+ }
12667
+ })
12668
+ }
12669
+ )
12670
+ ] }),
12478
12671
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 col-span-2", children: [
12479
12672
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
12480
12673
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "provider-options", children: "Provider Options" }),
@@ -12650,8 +12843,9 @@ const AgentSettings = ({ agentId }) => {
12650
12843
  const hasMemory = Boolean(memory?.result);
12651
12844
  const hasSubAgents = Boolean(Object.keys(agent.agents || {}).length > 0);
12652
12845
  const modelVersion = agent.modelVersion;
12846
+ const isSupportedModel = modelVersion === "v2" || modelVersion === "v3";
12653
12847
  let radioValue;
12654
- if (modelVersion === "v2") {
12848
+ if (isSupportedModel) {
12655
12849
  if (settings?.modelSettings?.chatWithNetwork) {
12656
12850
  radioValue = "network";
12657
12851
  } else {
@@ -12678,23 +12872,23 @@ const AgentSettings = ({ agentId }) => {
12678
12872
  }),
12679
12873
  className: "flex flex-row gap-4",
12680
12874
  children: [
12681
- modelVersion !== "v2" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12875
+ !isSupportedModel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12682
12876
  /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: "generateLegacy", id: "generateLegacy", className: "text-icon6" }),
12683
12877
  /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "generateLegacy", children: "Generate (Legacy)" })
12684
12878
  ] }),
12685
- modelVersion === "v2" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12879
+ isSupportedModel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12686
12880
  /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: "generate", id: "generate", className: "text-icon6" }),
12687
12881
  /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "generate", children: "Generate" })
12688
12882
  ] }),
12689
- modelVersion !== "v2" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12883
+ !isSupportedModel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12690
12884
  /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: "streamLegacy", id: "streamLegacy", className: "text-icon6" }),
12691
12885
  /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "streamLegacy", children: "Stream (Legacy)" })
12692
12886
  ] }),
12693
- modelVersion === "v2" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12887
+ isSupportedModel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12694
12888
  /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: "stream", id: "stream", className: "text-icon6" }),
12695
12889
  /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-icon6 text-ui-md", htmlFor: "stream", children: "Stream" })
12696
12890
  ] }),
12697
- modelVersion === "v2" && /* @__PURE__ */ jsxRuntime.jsx(NetworkCheckbox, { hasMemory, hasSubAgents })
12891
+ isSupportedModel && /* @__PURE__ */ jsxRuntime.jsx(NetworkCheckbox, { hasMemory, hasSubAgents })
12698
12892
  ]
12699
12893
  }
12700
12894
  ) }),
@@ -15486,6 +15680,7 @@ const AgentMetadataModelList = ({
15486
15680
  }) => {
15487
15681
  const [modelConfigs, setModelConfigs] = React.useState(() => modelList);
15488
15682
  const hasMultipleModels = modelConfigs.length > 1;
15683
+ const enabledCount = modelConfigs.filter((m) => m.enabled !== false).length;
15489
15684
  const handleDragEnd = (result) => {
15490
15685
  if (!result.destination) {
15491
15686
  return;
@@ -15520,7 +15715,8 @@ const AgentMetadataModelList = ({
15520
15715
  modelConfig,
15521
15716
  updateModelInModelList: updateModel,
15522
15717
  showDragHandle: hasMultipleModels,
15523
- dragHandleProps: provided2.dragHandleProps
15718
+ dragHandleProps: provided2.dragHandleProps,
15719
+ isLastEnabled: modelConfig.enabled !== false && enabledCount === 1
15524
15720
  }
15525
15721
  ) }) }, modelConfig.id)),
15526
15722
  provided.placeholder
@@ -15530,7 +15726,8 @@ const AgentMetadataModelListItem = ({
15530
15726
  modelConfig,
15531
15727
  updateModelInModelList,
15532
15728
  showDragHandle,
15533
- dragHandleProps
15729
+ dragHandleProps,
15730
+ isLastEnabled
15534
15731
  }) => {
15535
15732
  const [enabled, setEnabled] = React.useState(() => modelConfig.enabled);
15536
15733
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-background hover:bg-muted/50 transition-colors", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2", children: [
@@ -15544,7 +15741,10 @@ const AgentMetadataModelListItem = ({
15544
15741
  autoSave: true
15545
15742
  }
15546
15743
  ) }),
15547
- /* @__PURE__ */ jsxRuntime.jsx(
15744
+ isLastEnabled ? /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
15745
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Switch, { checked: enabled, disabled: true, className: "pointer-events-none" }) }) }),
15746
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "At least one model must be enabled" }) })
15747
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(
15548
15748
  Switch,
15549
15749
  {
15550
15750
  checked: enabled,
@@ -15562,7 +15762,14 @@ function usePromptEnhancer({ agentId }) {
15562
15762
  const client = react$1.useMastraClient();
15563
15763
  return reactQuery.useMutation({
15564
15764
  mutationFn: async ({ instructions, userComment }) => {
15565
- return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15765
+ try {
15766
+ return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15767
+ } catch (error) {
15768
+ const errorMessage = error instanceof Error ? error.message : "Error enhancing prompt";
15769
+ toast.error(errorMessage);
15770
+ console.error("Error enhancing prompt:", error);
15771
+ throw error;
15772
+ }
15566
15773
  }
15567
15774
  });
15568
15775
  }
@@ -15605,21 +15812,53 @@ const PromptEnhancer = ({ agentId }) => {
15605
15812
  const PromptEnhancerTextarea = ({ agentId }) => {
15606
15813
  const { prompt, setPrompt } = useAgentPromptExperiment();
15607
15814
  const { mutateAsync: enhancePrompt, isPending } = usePromptEnhancer({ agentId });
15815
+ const { data: agent, isLoading: isAgentLoading, isError: isAgentError } = useAgent(agentId);
15816
+ const { data: providersData, isLoading: isProvidersLoading } = useAgentsModelProviders();
15817
+ const providers = providersData?.providers || [];
15818
+ const isProviderConnected = (providerId) => {
15819
+ const cleanId = cleanProviderId(providerId);
15820
+ const provider = providers.find((p) => cleanProviderId(p.id) === cleanId);
15821
+ return provider?.connected === true;
15822
+ };
15823
+ const hasConnectedModel = () => {
15824
+ if (agent?.modelList && agent.modelList.length > 0) {
15825
+ return agent.modelList.some((m) => m.enabled !== false && isProviderConnected(m.model.provider));
15826
+ }
15827
+ return agent?.provider ? isProviderConnected(agent.provider) : false;
15828
+ };
15829
+ const isDataLoading = isAgentLoading || isProvidersLoading;
15830
+ const hasValidModel = !isDataLoading && !isAgentError && hasConnectedModel();
15608
15831
  const handleSubmit = async (e) => {
15609
15832
  e.preventDefault();
15610
15833
  const form = e.target;
15611
15834
  const formData = new FormData(form);
15612
15835
  const userComment = formData.get("userComment");
15613
- const result = await enhancePrompt({ instructions: prompt, userComment });
15614
- form.reset();
15615
- setPrompt(result.new_prompt);
15836
+ try {
15837
+ const result = await enhancePrompt({ instructions: prompt, userComment });
15838
+ form.reset();
15839
+ setPrompt(result.new_prompt);
15840
+ } catch {
15841
+ }
15616
15842
  };
15843
+ const isDisabled = isPending || !hasValidModel;
15844
+ const showWarning = !isDataLoading && !hasValidModel;
15617
15845
  return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
15618
- /* @__PURE__ */ jsxRuntime.jsx(Input, { name: "userComment", placeholder: "Enter your comment here...", className: "resize-none", disabled: isPending }),
15619
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(Button$1, { variant: "light", type: "submit", disabled: isPending, children: [
15620
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcwIcon, {}) }),
15621
- "Enhance prompt"
15622
- ] }) })
15846
+ /* @__PURE__ */ jsxRuntime.jsx(
15847
+ Input,
15848
+ {
15849
+ name: "userComment",
15850
+ placeholder: "Enter your comment here...",
15851
+ className: "resize-none",
15852
+ disabled: isDisabled
15853
+ }
15854
+ ),
15855
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end items-center gap-2", children: [
15856
+ showWarning && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-yellow-200", children: "No model with a configured API key found." }),
15857
+ /* @__PURE__ */ jsxRuntime.jsxs(Button$1, { variant: "light", type: "submit", disabled: isDisabled, children: [
15858
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcwIcon, {}) }),
15859
+ "Enhance prompt"
15860
+ ] })
15861
+ ] })
15623
15862
  ] });
15624
15863
  };
15625
15864
 
@@ -15724,7 +15963,7 @@ const AgentMetadata = ({ agentId }) => {
15724
15963
  AgentMetadataSection,
15725
15964
  {
15726
15965
  title: "Model",
15727
- hint: agent.modelVersion === "v2" ? void 0 : {
15966
+ hint: agent.modelVersion === "v2" || agent.modelVersion === "v3" ? void 0 : {
15728
15967
  link: "https://mastra.ai/guides/migrations/vnext-to-standard-apis",
15729
15968
  title: "You are using a legacy v1 model",
15730
15969
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangleIcon, { fontSize: 14, className: "mb-0.5" })
@@ -16393,13 +16632,16 @@ const AgentWorkingMemory = ({ agentId }) => {
16393
16632
  placeholder: "Enter working memory content..."
16394
16633
  }
16395
16634
  ),
16396
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
16635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: !threadExists ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
16636
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { tabIndex: 0, children: /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "secondary", size: "sm", disabled: true, className: "text-xs pointer-events-none", children: "Edit Working Memory" }) }) }),
16637
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Working memory will be available after the agent calls updateWorkingMemory" }) })
16638
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
16397
16639
  Button$2,
16398
16640
  {
16399
16641
  variant: "secondary",
16400
16642
  size: "sm",
16401
16643
  onClick: () => setIsEditing(true),
16402
- disabled: !threadExists || isUpdating,
16644
+ disabled: isUpdating,
16403
16645
  className: "text-xs",
16404
16646
  children: "Edit Working Memory"
16405
16647
  }
@@ -16496,22 +16738,6 @@ const AgentMemoryConfig = ({ agentId }) => {
16496
16738
  ]
16497
16739
  });
16498
16740
  }
16499
- if (config.workingMemory) {
16500
- sections.push({
16501
- title: "Working Memory",
16502
- items: [
16503
- {
16504
- label: "Enabled",
16505
- value: config.workingMemory.enabled,
16506
- badge: config.workingMemory.enabled ? "success" : void 0
16507
- },
16508
- ...config.workingMemory.enabled ? [
16509
- { label: "Scope", value: config.workingMemory.scope || "resource" },
16510
- { label: "Template", value: config.workingMemory.template || "default" }
16511
- ] : []
16512
- ]
16513
- });
16514
- }
16515
16741
  return sections;
16516
16742
  }, [config]);
16517
16743
  const toggleSection = (title) => {
@@ -16571,7 +16797,7 @@ const AgentMemoryConfig = ({ agentId }) => {
16571
16797
  ),
16572
16798
  expandedSections.has(section.title) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-2 space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between py-1", children: [
16573
16799
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-icon3", children: item.label }),
16574
- renderValue(item.value || "", item.badge)
16800
+ renderValue(item.value ?? "", item.badge)
16575
16801
  ] }, `${section.title}-${item.label}`)) })
16576
16802
  ] }, section.title)) })
16577
16803
  ] });
@@ -18702,6 +18928,17 @@ const Tabs = Object.assign(TabsRoot, {
18702
18928
  Content: TabContent
18703
18929
  });
18704
18930
 
18931
+ function isTokenDetailsObject(value) {
18932
+ return typeof value === "object" && value !== null;
18933
+ }
18934
+ const detailKeyLabels = {
18935
+ text: "Text",
18936
+ cacheRead: "Cache Read",
18937
+ cacheWrite: "Cache Write",
18938
+ audio: "Audio",
18939
+ image: "Image",
18940
+ reasoning: "Reasoning"
18941
+ };
18705
18942
  function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18706
18943
  if (!traceUsage && !spanUsage) {
18707
18944
  console.warn("No usage data available");
@@ -18806,6 +19043,14 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18806
19043
  cachedInputTokens: {
18807
19044
  label: "Cached Input Tokens",
18808
19045
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {})
19046
+ },
19047
+ inputDetails: {
19048
+ label: "Input Details",
19049
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {})
19050
+ },
19051
+ outputDetails: {
19052
+ label: "Output Details",
19053
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {})
18809
19054
  }
18810
19055
  };
18811
19056
  const commonTokenPresentations = {
@@ -18821,47 +19066,79 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18821
19066
  };
18822
19067
  let usageKeyOrder = [];
18823
19068
  if (hasV5Format) {
18824
- usageKeyOrder = ["totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cachedInputTokens"];
19069
+ usageKeyOrder = [
19070
+ "totalTokens",
19071
+ "inputTokens",
19072
+ "outputTokens",
19073
+ "reasoningTokens",
19074
+ "cachedInputTokens",
19075
+ "inputDetails",
19076
+ "outputDetails"
19077
+ ];
18825
19078
  } else {
18826
19079
  usageKeyOrder = ["totalTokens", "promptTokens", "completionTokens"];
18827
19080
  }
18828
- const usageAsArray = Object.entries(traceUsage || spanUsage || {}).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
18829
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => /* @__PURE__ */ jsxRuntime.jsxs(
18830
- "div",
18831
- {
18832
- className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
18833
- "min-h-[5.5rem]": traceUsage
18834
- }),
18835
- children: [
18836
- /* @__PURE__ */ jsxRuntime.jsxs(
18837
- "div",
18838
- {
18839
- className: cn(
18840
- "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
18841
- "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
18842
- ),
18843
- children: [
18844
- tokenPresentations?.[key]?.icon,
18845
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
18846
- /* @__PURE__ */ jsxRuntime.jsx("b", { className: "text-[1rem]", children: value })
18847
- ]
18848
- }
18849
- ),
18850
- tokensByProviderValid && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => /* @__PURE__ */ jsxRuntime.jsxs(
18851
- "dl",
18852
- {
18853
- className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
18854
- children: [
18855
- /* @__PURE__ */ jsxRuntime.jsx("dt", { children: provider }),
18856
- /* @__PURE__ */ jsxRuntime.jsx("dd", { children: providerTokens?.[key] })
18857
- ]
18858
- },
18859
- provider
18860
- )) })
18861
- ]
18862
- },
18863
- key
18864
- )) });
19081
+ const usageAsArray = Object.entries(traceUsage || spanUsage || {}).filter((entry) => {
19082
+ const value = entry[1];
19083
+ return typeof value === "number" || isTokenDetailsObject(value);
19084
+ }).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
19085
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => {
19086
+ const isObject = isTokenDetailsObject(value);
19087
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19088
+ "div",
19089
+ {
19090
+ className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
19091
+ "min-h-[5.5rem]": traceUsage
19092
+ }),
19093
+ children: [
19094
+ /* @__PURE__ */ jsxRuntime.jsxs(
19095
+ "div",
19096
+ {
19097
+ className: cn(
19098
+ "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
19099
+ "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
19100
+ ),
19101
+ children: [
19102
+ tokenPresentations?.[key]?.icon,
19103
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
19104
+ !isObject && /* @__PURE__ */ jsxRuntime.jsx("b", { className: "text-[1rem]", children: value })
19105
+ ]
19106
+ }
19107
+ ),
19108
+ isObject && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(value).map(([detailKey, detailValue]) => {
19109
+ if (typeof detailValue !== "number") return null;
19110
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19111
+ "dl",
19112
+ {
19113
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19114
+ children: [
19115
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: detailKeyLabels[detailKey] || detailKey }),
19116
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: detailValue })
19117
+ ]
19118
+ },
19119
+ detailKey
19120
+ );
19121
+ }) }),
19122
+ !isObject && tokensByProviderValid && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => {
19123
+ const tokenValue = providerTokens?.[key];
19124
+ if (typeof tokenValue !== "number") return null;
19125
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19126
+ "dl",
19127
+ {
19128
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19129
+ children: [
19130
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: provider }),
19131
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: tokenValue })
19132
+ ]
19133
+ },
19134
+ provider
19135
+ );
19136
+ }) })
19137
+ ]
19138
+ },
19139
+ key
19140
+ );
19141
+ }) });
18865
19142
  }
18866
19143
 
18867
19144
  function isTokenLimitExceeded(span) {
@@ -18974,7 +19251,7 @@ function SpanTabs({
18974
19251
  SpanScoring,
18975
19252
  {
18976
19253
  traceId: trace?.traceId,
18977
- isTopLevelSpan: span?.parentSpanId === null,
19254
+ isTopLevelSpan: !Boolean(span?.parentSpanId),
18978
19255
  spanId: span?.spanId,
18979
19256
  entityType,
18980
19257
  scorers,
@@ -19833,6 +20110,15 @@ const PlaygroundQueryClient = ({ children, options }) => {
19833
20110
  return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children });
19834
20111
  };
19835
20112
 
20113
+ const themeClasses = {
20114
+ light: "bg-gray-100 border-gray-300 text-gray-700",
20115
+ dark: "bg-surface4 border-border1 text-icon6"
20116
+ };
20117
+ const Kbd = ({ children, theme = "dark" }) => {
20118
+ const themeClass = themeClasses[theme];
20119
+ return /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: clsx("border-sm rounded-md px-1 py-0.5 font-mono", themeClass), children });
20120
+ };
20121
+
19836
20122
  const errorFallback = "Something went wrong while fetching the data.";
19837
20123
  const parseError = (error) => {
19838
20124
  try {
@@ -20134,14 +20420,6 @@ const MCPToolPanel = ({ toolId, serverId }) => {
20134
20420
  );
20135
20421
  };
20136
20422
 
20137
- const CodeMirrorBlock = (props) => {
20138
- const theme = useCodemirrorTheme$1();
20139
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4 relative", children: [
20140
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 right-4 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy code", content: props.value || "No content" }) }),
20141
- /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { extensions: [langJson.json()], theme, ...props })
20142
- ] });
20143
- };
20144
-
20145
20423
  const MCPDetail = ({ isLoading, server }) => {
20146
20424
  const [{ sseUrl, httpStreamUrl }, setUrls] = React.useState({
20147
20425
  sseUrl: "",
@@ -20163,112 +20441,45 @@ const MCPDetail = ({ isLoading, server }) => {
20163
20441
  if (isLoading) return null;
20164
20442
  if (!server)
20165
20443
  return /* @__PURE__ */ jsxRuntime.jsx(MainContentContent, { children: /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "h1", variant: "header-md", className: "text-icon3 font-medium py-20 text-center", children: "Server not found" }) });
20444
+ const commandLineConfig = `npx -y mcp-remote ${sseUrl}`;
20166
20445
  return /* @__PURE__ */ jsxRuntime.jsxs(MainContentContent, { isDivided: true, children: [
20167
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-8 py-20 mx-auto max-w-[604px] w-full", children: [
20446
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-8 py-12 mx-auto max-w-2xl w-full", children: [
20168
20447
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "h1", variant: "header-md", className: "text-icon6 font-medium pb-4", children: server.name }),
20169
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
20170
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
20171
- /* @__PURE__ */ jsxRuntime.jsx(
20172
- Badge,
20173
- {
20174
- icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "SSE" }),
20175
- className: "!text-icon4",
20176
- children: sseUrl
20177
- }
20178
- ),
20179
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" })
20180
- ] }),
20181
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
20182
- /* @__PURE__ */ jsxRuntime.jsx(
20183
- Badge,
20184
- {
20185
- icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "HTTP" }),
20186
- className: "!text-icon4",
20187
- children: httpStreamUrl
20188
- }
20189
- ),
20190
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" })
20191
- ] })
20192
- ] }),
20193
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 pt-3 pb-9", children: [
20448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 pb-6", children: [
20194
20449
  /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx(FolderIcon, { className: "text-icon6" }), className: "rounded-r-sm !text-icon4", children: "Version" }),
20195
20450
  /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "rounded-l-sm !text-icon4", children: server.version_detail.version })
20196
20451
  ] }),
20197
- /* @__PURE__ */ jsxRuntime.jsx(McpSetupTabs, { sseUrl, serverName: server.name })
20452
+ /* @__PURE__ */ jsxRuntime.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." }),
20453
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
20454
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20455
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "HTTP" }), children: "Regular HTTP Endpoint" }),
20456
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for stateless HTTP transport with streamable responses." }),
20457
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20458
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: httpStreamUrl }),
20459
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" }) })
20460
+ ] })
20461
+ ] }),
20462
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20463
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "SSE" }), children: "Server-Sent Events" }),
20464
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for real-time communication via SSE." }),
20465
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20466
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: sseUrl }),
20467
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" }) })
20468
+ ] })
20469
+ ] }),
20470
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20471
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 font-medium mr-1", children: "CLI" }), children: "Command Line" }),
20472
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for local command-line access via npx and mcp-remote." }),
20473
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20474
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: commandLineConfig }),
20475
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy Command Line Config", content: commandLineConfig, iconSize: "sm" }) })
20476
+ ] })
20477
+ ] })
20478
+ ] })
20198
20479
  ] }),
20199
20480
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full overflow-y-scroll border-l-sm border-border1", children: /* @__PURE__ */ jsxRuntime.jsx(McpToolList, { server }) })
20200
20481
  ] });
20201
20482
  };
20202
- const McpSetupTabs = ({ sseUrl, serverName }) => {
20203
- const { Link } = useLinkComponent();
20204
- return /* @__PURE__ */ jsxRuntime.jsxs(PlaygroundTabs, { defaultTab: "cursor", children: [
20205
- /* @__PURE__ */ jsxRuntime.jsxs(TabList$1, { children: [
20206
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "cursor", children: "Cursor" }),
20207
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "windsurf", children: "Windsurf" })
20208
- ] }),
20209
- /* @__PURE__ */ jsxRuntime.jsxs(TabContent$1, { value: "cursor", children: [
20210
- /* @__PURE__ */ jsxRuntime.jsxs(Txt, { className: "text-icon3 pb-4", children: [
20211
- "Cursor comes with built-in MCP Support.",
20212
- " ",
20213
- /* @__PURE__ */ jsxRuntime.jsx(
20214
- Link,
20215
- {
20216
- href: "https://docs.cursor.com/context/model-context-protocol",
20217
- target: "_blank",
20218
- rel: "noopener noreferrer",
20219
- className: "underline hover:text-icon6",
20220
- children: "Following the documentation"
20221
- }
20222
- ),
20223
- ", you can register an MCP server using SSE with the following configuration."
20224
- ] }),
20225
- /* @__PURE__ */ jsxRuntime.jsx(
20226
- CodeMirrorBlock,
20227
- {
20228
- editable: false,
20229
- value: `{
20230
- "mcpServers": {
20231
- "${serverName}": {
20232
- "url": "${sseUrl}"
20233
- }
20234
- }
20235
- }`
20236
- }
20237
- )
20238
- ] }),
20239
- /* @__PURE__ */ jsxRuntime.jsxs(TabContent$1, { value: "windsurf", children: [
20240
- /* @__PURE__ */ jsxRuntime.jsxs(Txt, { className: "text-icon3 pb-4", children: [
20241
- "Windsurf comes with built-in MCP Support.",
20242
- " ",
20243
- /* @__PURE__ */ jsxRuntime.jsx(
20244
- Link,
20245
- {
20246
- href: "https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json",
20247
- target: "_blank",
20248
- rel: "noopener noreferrer",
20249
- className: "underline hover:text-icon6",
20250
- children: "Following the documentation"
20251
- }
20252
- ),
20253
- ", you can register an MCP server using SSE with the following configuration."
20254
- ] }),
20255
- /* @__PURE__ */ jsxRuntime.jsx(
20256
- CodeMirrorBlock,
20257
- {
20258
- editable: false,
20259
- value: `{
20260
- "mcpServers": {
20261
- "${serverName}": {
20262
- "command": "npx",
20263
- "args": ["-y", "mcp-remote", "${sseUrl}"]
20264
- }
20265
- }
20266
- }`
20267
- }
20268
- )
20269
- ] })
20270
- ] });
20271
- };
20272
20483
  const McpToolList = ({ server }) => {
20273
20484
  const { data: tools = {}, isLoading } = useMCPServerTools(server);
20274
20485
  if (isLoading) return null;
@@ -20710,6 +20921,8 @@ exports.WorkflowRunContext = WorkflowRunContext;
20710
20921
  exports.WorkflowRunDetail = WorkflowRunDetail;
20711
20922
  exports.WorkflowRunList = WorkflowRunList;
20712
20923
  exports.WorkflowRunProvider = WorkflowRunProvider;
20924
+ exports.WorkflowStepDetailContext = WorkflowStepDetailContext;
20925
+ exports.WorkflowStepDetailProvider = WorkflowStepDetailProvider;
20713
20926
  exports.WorkflowTable = WorkflowTable;
20714
20927
  exports.WorkflowTrigger = WorkflowTrigger;
20715
20928
  exports.WorkingMemoryContext = WorkingMemoryContext;
@@ -20772,6 +20985,7 @@ exports.useUpdateModelInModelList = useUpdateModelInModelList;
20772
20985
  exports.useWorkflow = useWorkflow;
20773
20986
  exports.useWorkflowRunExecutionResult = useWorkflowRunExecutionResult;
20774
20987
  exports.useWorkflowRuns = useWorkflowRuns;
20988
+ exports.useWorkflowStepDetail = useWorkflowStepDetail;
20775
20989
  exports.useWorkflows = useWorkflows;
20776
20990
  exports.useWorkingMemory = useWorkingMemory;
20777
20991
  Object.keys(reactQuery).forEach(k => {