@mastra/playground-ui 7.0.0-beta.10 → 7.0.0-beta.13

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');
@@ -3464,6 +3465,55 @@ const defaultComponents = reactMarkdown.unstable_memoizeMarkdownComponents({
3464
3465
  img: ImageWithFallback
3465
3466
  });
3466
3467
 
3468
+ const TripwireNotice = ({ reason, tripwire }) => {
3469
+ const [isExpanded, setIsExpanded] = React.useState(false);
3470
+ const hasMetadata = tripwire && (tripwire.retry !== void 0 || tripwire.tripwirePayload || tripwire.processorId);
3471
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-amber-500/30 bg-amber-950/20 overflow-hidden", children: [
3472
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4", children: [
3473
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "w-5 h-5 text-amber-400 mt-0.5 flex-shrink-0" }),
3474
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
3475
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-200 mb-1", children: "Content Blocked" }),
3476
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-amber-300/90", children: reason })
3477
+ ] })
3478
+ ] }),
3479
+ hasMetadata && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3480
+ /* @__PURE__ */ jsxRuntime.jsxs(
3481
+ "button",
3482
+ {
3483
+ onClick: () => setIsExpanded(!isExpanded),
3484
+ className: "w-full flex items-center gap-2 px-4 py-2 text-xs text-amber-400/70 hover:text-amber-400 hover:bg-amber-900/20 transition-colors border-t border-amber-500/20",
3485
+ children: [
3486
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3.5 h-3.5" }),
3487
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Details" })
3488
+ ]
3489
+ }
3490
+ ),
3491
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-4 space-y-3 border-t border-amber-500/20 bg-amber-950/10", children: [
3492
+ tripwire.retry !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-3", children: [
3493
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-3.5 h-3.5 text-amber-400/60" }),
3494
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
3495
+ "Retry:",
3496
+ " ",
3497
+ tripwire.retry ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-green-400", children: "Allowed" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-400", children: "Not allowed" })
3498
+ ] })
3499
+ ] }),
3500
+ tripwire.processorId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3501
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-3.5 h-3.5 text-amber-400/60" }),
3502
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
3503
+ "Processor:",
3504
+ " ",
3505
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded bg-amber-900/30 text-amber-200 font-mono", children: tripwire.processorId })
3506
+ ] })
3507
+ ] }),
3508
+ tripwire.tripwirePayload !== void 0 && tripwire.tripwirePayload !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-1", children: [
3509
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-400/60 mb-1.5", children: "Metadata:" }),
3510
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-amber-200/80 bg-amber-900/30 rounded p-2 overflow-x-auto font-mono", children: String(JSON.stringify(tripwire.tripwirePayload, null, 2)) })
3511
+ ] })
3512
+ ] })
3513
+ ] })
3514
+ ] });
3515
+ };
3516
+
3467
3517
  const AgentIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "17", height: "16", viewBox: "0 0 17 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
3468
3518
  /* @__PURE__ */ jsxRuntime.jsx(
3469
3519
  "path",
@@ -4254,6 +4304,9 @@ const ErrorAwareText = () => {
4254
4304
  const part = react.useAssistantState(({ part: part2 }) => part2);
4255
4305
  const text = part.text || "";
4256
4306
  const metadata = part.metadata || {};
4307
+ if (metadata?.status === "tripwire") {
4308
+ return /* @__PURE__ */ jsxRuntime.jsx(TripwireNotice, { reason: text, tripwire: metadata.tripwire });
4309
+ }
4257
4310
  if (metadata?.status === "warning") {
4258
4311
  return /* @__PURE__ */ jsxRuntime.jsxs(Alert$1, { variant: "warning", children: [
4259
4312
  /* @__PURE__ */ jsxRuntime.jsx(AlertTitle$1, { as: "h5", children: "Warning" }),
@@ -4627,7 +4680,8 @@ const ToolBadge = ({
4627
4680
  metadata,
4628
4681
  toolOutput,
4629
4682
  toolCallId,
4630
- toolApprovalMetadata
4683
+ toolApprovalMetadata,
4684
+ suspendPayload
4631
4685
  }) => {
4632
4686
  let argSlot = null;
4633
4687
  try {
@@ -4637,6 +4691,7 @@ const ToolBadge = ({
4637
4691
  argSlot = /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: args });
4638
4692
  }
4639
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" });
4640
4695
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
4641
4696
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
4642
4697
  const toolCalled = result || toolOutput.length > 0;
@@ -4653,12 +4708,16 @@ const ToolBadge = ({
4653
4708
  input: agentNetworkInput
4654
4709
  }
4655
4710
  ),
4656
- initialCollapsed: !!!toolApprovalMetadata,
4711
+ initialCollapsed: !!!(toolApprovalMetadata ?? suspendPayload),
4657
4712
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4658
4713
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4659
4714
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool arguments" }),
4660
4715
  argSlot
4661
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
+ ] }),
4662
4721
  resultSlot !== void 0 && result && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4663
4722
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool result" }),
4664
4723
  resultSlot
@@ -4686,6 +4745,7 @@ function convertWorkflowRunStateToStreamResult(runState) {
4686
4745
  Object.entries(context).forEach(([stepId, stepResult]) => {
4687
4746
  if (stepId !== "input" && "status" in stepResult) {
4688
4747
  const result = stepResult;
4748
+ const hasTripwire = result.status === "failed" && result.tripwire !== void 0;
4689
4749
  steps[stepId] = {
4690
4750
  status: result.status,
4691
4751
  output: "output" in result ? result.output : void 0,
@@ -4693,7 +4753,9 @@ function convertWorkflowRunStateToStreamResult(runState) {
4693
4753
  suspendPayload: "suspendPayload" in result ? result.suspendPayload : void 0,
4694
4754
  suspendOutput: "suspendOutput" in result ? result.suspendOutput : void 0,
4695
4755
  resumePayload: "resumePayload" in result ? result.resumePayload : void 0,
4696
- error: "error" in result ? result.error : void 0,
4756
+ // Don't include error when tripwire is present - tripwire takes precedence
4757
+ error: hasTripwire ? void 0 : "error" in result ? result.error : void 0,
4758
+ tripwire: hasTripwire ? result.tripwire : void 0,
4697
4759
  startedAt: "startedAt" in result ? result.startedAt : Date.now(),
4698
4760
  endedAt: "endedAt" in result ? result.endedAt : void 0,
4699
4761
  suspendedAt: "suspendedAt" in result ? result.suspendedAt : void 0,
@@ -4718,7 +4780,15 @@ function convertWorkflowRunStateToStreamResult(runState) {
4718
4780
  status: runState.status,
4719
4781
  ...runState.status === "success" ? { result: runState.result } : {},
4720
4782
  ...runState.status === "failed" ? { error: runState.error } : {},
4721
- ...runState.status === "suspended" ? { suspended: suspendedStepIds, suspendPayload } : {}
4783
+ ...runState.status === "suspended" ? { suspended: suspendedStepIds, suspendPayload } : {},
4784
+ ...runState.status === "tripwire" && runState.tripwire ? {
4785
+ tripwire: {
4786
+ reason: runState.tripwire.reason,
4787
+ retry: runState.tripwire.retry,
4788
+ metadata: runState.tripwire.metadata,
4789
+ processorId: runState.tripwire.processorId
4790
+ }
4791
+ } : {}
4722
4792
  };
4723
4793
  }
4724
4794
 
@@ -4964,7 +5034,8 @@ const useExecuteWorkflow = () => {
4964
5034
  requestContext$1.set(key, value);
4965
5035
  });
4966
5036
  const workflow = client.getWorkflow(workflowId);
4967
- 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 });
4968
5039
  } catch (error) {
4969
5040
  console.error("Error starting workflow run:", error);
4970
5041
  throw error;
@@ -4984,7 +5055,8 @@ const useExecuteWorkflow = () => {
4984
5055
  requestContext$1.set(key, value);
4985
5056
  });
4986
5057
  const workflow = client.getWorkflow(workflowId);
4987
- 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 });
4988
5060
  return result;
4989
5061
  } catch (error) {
4990
5062
  console.error("Error starting workflow run:", error);
@@ -5077,8 +5149,8 @@ const useStreamWorkflow = () => {
5077
5149
  requestContext$1.set(key, value);
5078
5150
  });
5079
5151
  const workflow = client.getWorkflow(workflowId);
5080
- const stream = await workflow.streamVNext({
5081
- runId,
5152
+ const run = await workflow.createRun({ runId });
5153
+ const stream = await run.streamVNext({
5082
5154
  inputData,
5083
5155
  requestContext: requestContext$1,
5084
5156
  closeOnSuspend: true,
@@ -5140,7 +5212,8 @@ const useStreamWorkflow = () => {
5140
5212
  return;
5141
5213
  }
5142
5214
  const workflow = client.getWorkflow(workflowId);
5143
- const stream = await workflow.observeStreamVNext({ runId });
5215
+ const run = await workflow.createRun({ runId });
5216
+ const stream = await run.observeStreamVNext();
5144
5217
  if (!stream) {
5145
5218
  return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
5146
5219
  }
@@ -5198,8 +5271,8 @@ const useStreamWorkflow = () => {
5198
5271
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5199
5272
  requestContext$1.set(key, value);
5200
5273
  });
5201
- const stream = await workflow.resumeStreamVNext({
5202
- runId,
5274
+ const run = await workflow.createRun({ runId });
5275
+ const stream = await run.resumeStreamVNext({
5203
5276
  step,
5204
5277
  resumeData,
5205
5278
  requestContext: requestContext$1,
@@ -5248,6 +5321,7 @@ const useStreamWorkflow = () => {
5248
5321
  mutationFn: async ({
5249
5322
  workflowId,
5250
5323
  requestContext: playgroundRequestContext,
5324
+ runId,
5251
5325
  ...params
5252
5326
  }) => {
5253
5327
  if (timeTravelStreamRef.current) {
@@ -5260,7 +5334,8 @@ const useStreamWorkflow = () => {
5260
5334
  Object.entries(playgroundRequestContext).forEach(([key, value]) => {
5261
5335
  requestContext$1.set(key, value);
5262
5336
  });
5263
- const stream = await workflow.timeTravelStream({
5337
+ const run = await workflow.createRun({ runId });
5338
+ const stream = await run.timeTravelStream({
5264
5339
  ...params,
5265
5340
  requestContext: requestContext$1,
5266
5341
  tracingOptions: settings?.tracingOptions
@@ -5351,7 +5426,9 @@ const useCancelWorkflowRun = () => {
5351
5426
  const cancelWorkflowRun = reactQuery.useMutation({
5352
5427
  mutationFn: async ({ workflowId, runId }) => {
5353
5428
  try {
5354
- 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();
5355
5432
  return response;
5356
5433
  } catch (error) {
5357
5434
  console.error("Error canceling workflow run:", error);
@@ -5445,6 +5522,58 @@ const useDeleteWorkflowRun = (workflowId) => {
5445
5522
  });
5446
5523
  };
5447
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
+
5448
5577
  const WorkflowRunContext = React.createContext({});
5449
5578
  function WorkflowRunProvider({
5450
5579
  children,
@@ -5546,7 +5675,7 @@ function WorkflowRunProvider({
5546
5675
  isLoadingRunExecutionResult,
5547
5676
  withoutTimeTravel
5548
5677
  },
5549
- children
5678
+ children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowStepDetailProvider, { children })
5550
5679
  }
5551
5680
  );
5552
5681
  }
@@ -6151,10 +6280,13 @@ const useCurrentRun = () => {
6151
6280
  const context = React.useContext(WorkflowRunContext);
6152
6281
  const workflowCurrentSteps = context.result?.steps ?? {};
6153
6282
  const steps = Object.entries(workflowCurrentSteps).reduce((acc, [key, value]) => {
6283
+ const hasTripwire = "tripwire" in value && value.tripwire;
6154
6284
  return {
6155
6285
  ...acc,
6156
6286
  [key]: {
6157
- error: "error" in value ? value.error : void 0,
6287
+ // Don't include error when tripwire is present - tripwire takes precedence
6288
+ error: hasTripwire ? void 0 : "error" in value ? value.error : void 0,
6289
+ tripwire: hasTripwire ? value.tripwire : void 0,
6158
6290
  startedAt: value.startedAt,
6159
6291
  endedAt: "endedAt" in value ? value.endedAt : void 0,
6160
6292
  status: value.status,
@@ -6202,26 +6334,46 @@ const SyntaxHighlighter$1 = ({ data }) => {
6202
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] }) });
6203
6335
  };
6204
6336
 
6205
- const CodeDialogContent = ({ data }) => {
6337
+ const CodeDialogContent = ({
6338
+ data,
6339
+ language = "auto"
6340
+ }) => {
6206
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
+ };
6207
6359
  if (typeof data !== "string") {
6360
+ const content = JSON.stringify(data, null, 2);
6208
6361
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6209
- /* @__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) }) }),
6210
- /* @__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] }) })
6211
6364
  ] });
6212
6365
  }
6366
+ const extensions = getExtensions(data);
6367
+ let displayContent = data;
6213
6368
  try {
6214
6369
  const json = JSON.parse(data);
6215
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6216
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: data }) }),
6217
- /* @__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] }) })
6218
- ] });
6219
- } catch (error) {
6220
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[500px] overflow-auto relative p-4", children: [
6221
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-2 top-2 bg-surface4 rounded-full z-10", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: data }) }),
6222
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface4 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { value: data, theme, extensions: [] }) })
6223
- ] });
6370
+ displayContent = JSON.stringify(json, null, 2);
6371
+ } catch {
6224
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
+ ] });
6225
6377
  };
6226
6378
 
6227
6379
  const Form = React.forwardRef(({ children, ...props }, ref) => {
@@ -7203,12 +7355,23 @@ function inferFieldType(schema, fieldConfig) {
7203
7355
  if (schema instanceof z.z.ZodDiscriminatedUnion) {
7204
7356
  return "discriminated-union";
7205
7357
  }
7358
+ if (schema instanceof z.z.ZodLiteral) {
7359
+ const v4Values = schema._zod?.def?.values;
7360
+ const v3Value = schema._def?.value;
7361
+ const literalValue = v4Values !== void 0 ? Array.isArray(v4Values) ? v4Values[0] : v4Values : v3Value;
7362
+ if (typeof literalValue === "number") return "number";
7363
+ if (typeof literalValue === "boolean") return "boolean";
7364
+ return "string";
7365
+ }
7206
7366
  return "string";
7207
7367
  }
7208
7368
 
7209
7369
  function getDefaultValueInZodStack(schema) {
7210
7370
  if (schema instanceof z$1.core.$ZodDefault) {
7211
7371
  return schema._zod.def.defaultValue;
7372
+ } else if (schema instanceof z$1.core.$ZodLiteral) {
7373
+ const values = schema._zod.def.values;
7374
+ return Array.isArray(values) ? values[0] : values;
7212
7375
  } else if ("innerType" in schema._zod.def) {
7213
7376
  return getDefaultValueInZodStack(schema._zod.def.innerType);
7214
7377
  } else if ("shape" in schema._zod.def) {
@@ -7724,9 +7887,9 @@ const WorkflowTimeTravelForm = ({ stepKey, closeModal }) => {
7724
7887
  const parsedResume = resumeData.trim() ? JSON.parse(resumeData) : {};
7725
7888
  const parsedContext = contextValue.trim() ? JSON.parse(contextValue) : {};
7726
7889
  const parsedNestedContext = nestedContextValue.trim() ? JSON.parse(nestedContextValue) : {};
7727
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
7890
+ const run = await createWorkflowRun({ workflowId, prevRunId });
7728
7891
  const payload = {
7729
- runId,
7892
+ runId: run.runId,
7730
7893
  workflowId,
7731
7894
  step: stepKey,
7732
7895
  inputData: data,
@@ -7825,6 +7988,7 @@ const WorkflowStepActionBar = ({
7825
7988
  resumeData,
7826
7989
  suspendOutput,
7827
7990
  error,
7991
+ tripwire,
7828
7992
  mapConfig,
7829
7993
  stepName,
7830
7994
  stepId,
@@ -7836,25 +8000,44 @@ const WorkflowStepActionBar = ({
7836
8000
  const [isOutputOpen, setIsOutputOpen] = React.useState(false);
7837
8001
  const [isResumeDataOpen, setIsResumeDataOpen] = React.useState(false);
7838
8002
  const [isErrorOpen, setIsErrorOpen] = React.useState(false);
7839
- const [isMapConfigOpen, setIsMapConfigOpen] = React.useState(false);
8003
+ const [isTripwireOpen, setIsTripwireOpen] = React.useState(false);
7840
8004
  const [isTimeTravelOpen, setIsTimeTravelOpen] = React.useState(false);
7841
8005
  const { withoutTimeTravel } = React.useContext(WorkflowRunContext);
8006
+ const { showMapConfig, stepDetail, closeStepDetail } = useWorkflowStepDetail();
7842
8007
  const dialogContentClass = "bg-surface2 rounded-lg border-sm border-border1 max-w-4xl w-full px-0";
7843
8008
  const dialogTitleClass = "border-b-sm border-border1 pb-4 px-6";
7844
8009
  const showTimeTravel = !withoutTimeTravel && stepKey && !mapConfig;
7845
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (input || output || error || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxRuntime.jsxs(
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
+ };
8027
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (input || output || error || tripwire || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxRuntime.jsxs(
7846
8028
  "div",
7847
8029
  {
7848
8030
  className: cn(
7849
8031
  "flex flex-wrap items-center bg-surface4 border-t-sm border-border1 px-2 py-1 gap-2 rounded-b-lg",
7850
8032
  status === "success" && "bg-accent1Dark",
7851
8033
  status === "failed" && "bg-accent2Dark",
8034
+ status === "tripwire" && "bg-amber-900/40 border-amber-500/20",
7852
8035
  status === "suspended" && "bg-accent3Dark",
7853
8036
  status === "waiting" && "bg-accent5Dark",
7854
8037
  status === "running" && "bg-accent6Dark"
7855
8038
  ),
7856
8039
  children: [
7857
- 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" }),
7858
8041
  showTimeTravel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7859
8042
  /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsTimeTravelOpen(true), children: "Time travel" }),
7860
8043
  /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isTimeTravelOpen, onOpenChange: setIsTimeTravelOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -7865,19 +8048,7 @@ const WorkflowStepActionBar = ({
7865
8048
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-scroll max-h-[600px]", children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowTimeTravelForm, { stepKey, closeModal: () => setIsTimeTravelOpen(false) }) })
7866
8049
  ] }) })
7867
8050
  ] }),
7868
- mapConfig && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7869
- /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsMapConfigOpen(true), children: "Map config" }),
7870
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isMapConfigOpen, onOpenChange: setIsMapConfigOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
7871
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: dialogTitleClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
7872
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7873
- stepName,
7874
- " Map Config"
7875
- ] }),
7876
- stepId && stepId !== stepName && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-icon3 font-normal", children: stepId })
7877
- ] }) }),
7878
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: mapConfig }) })
7879
- ] }) })
7880
- ] }),
8051
+ mapConfig && /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: handleMapConfigClick, className: cn(isMapConfigOpen && activeButtonClass), children: "Map config" }),
7881
8052
  input && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7882
8053
  /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsInputOpen(true), children: "Input" }),
7883
8054
  /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isInputOpen, onOpenChange: setIsInputOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
@@ -7917,6 +8088,26 @@ const WorkflowStepActionBar = ({
7917
8088
  ] }),
7918
8089
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: error }) })
7919
8090
  ] }) })
8091
+ ] }),
8092
+ tripwire && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8093
+ /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsTripwireOpen(true), className: "text-amber-400 hover:text-amber-300", children: "Tripwire" }),
8094
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isTripwireOpen, onOpenChange: setIsTripwireOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
8095
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: dialogTitleClass, children: [
8096
+ stepName,
8097
+ " tripwire"
8098
+ ] }),
8099
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
8100
+ CodeDialogContent,
8101
+ {
8102
+ data: {
8103
+ reason: tripwire.reason,
8104
+ retry: tripwire.retry,
8105
+ metadata: tripwire.metadata,
8106
+ processorId: tripwire.processorId
8107
+ }
8108
+ }
8109
+ ) })
8110
+ ] }) })
7920
8111
  ] })
7921
8112
  ]
7922
8113
  }
@@ -7932,6 +8123,8 @@ function WorkflowConditionNode({ data }) {
7932
8123
  const { steps } = useCurrentRun();
7933
8124
  const previousStep = steps[previousStepId];
7934
8125
  const nextStep = steps[nextStepId];
8126
+ const isPreviousTripwire = previousStep?.status === "failed" && previousStep?.tripwire !== void 0;
8127
+ const previousDisplayStatus = isPreviousTripwire ? "tripwire" : previousStep?.status;
7935
8128
  const { icon: IconComponent, color } = getConditionIconAndColor(type);
7936
8129
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7937
8130
  !withoutTopHandle && /* @__PURE__ */ jsxRuntime.jsx(react$2.Handle, { type: "target", position: react$2.Position.Top, style: { visibility: "hidden" } }),
@@ -7939,12 +8132,13 @@ function WorkflowConditionNode({ data }) {
7939
8132
  "div",
7940
8133
  {
7941
8134
  "data-workflow-node": true,
7942
- "data-workflow-step-status": previousStep?.status,
8135
+ "data-workflow-step-status": previousDisplayStatus,
7943
8136
  "data-testid": "workflow-condition-node",
7944
8137
  className: cn(
7945
8138
  "bg-surface3 rounded-lg w-[300px] border-sm border-border1",
7946
- previousStep?.status === "success" && nextStep && "bg-accent1Darker",
7947
- previousStep?.status === "failed" && nextStep && "bg-accent2Darker",
8139
+ previousDisplayStatus === "success" && nextStep && "bg-accent1Darker",
8140
+ previousDisplayStatus === "failed" && nextStep && "bg-accent2Darker",
8141
+ previousDisplayStatus === "tripwire" && nextStep && "bg-amber-950/40 border-amber-500/30",
7948
8142
  !previousStep && Boolean(nextStep?.status) && "bg-accent1Darker"
7949
8143
  ),
7950
8144
  children: [
@@ -7996,10 +8190,11 @@ function WorkflowConditionNode({ data }) {
7996
8190
  "pre",
7997
8191
  {
7998
8192
  className: cn(
7999
- "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",
8000
8194
  className,
8001
- previousStep?.status === "success" && nextStep && "!bg-accent1Dark",
8002
- previousStep?.status === "failed" && nextStep && "!bg-accent2Dark"
8195
+ previousDisplayStatus === "success" && nextStep && "!bg-accent1Dark",
8196
+ previousDisplayStatus === "failed" && nextStep && "!bg-accent2Dark",
8197
+ previousDisplayStatus === "tripwire" && nextStep && "!bg-amber-900/40"
8003
8198
  ),
8004
8199
  onClick: () => setOpenDialog(true),
8005
8200
  style,
@@ -8055,7 +8250,8 @@ function WorkflowConditionNode({ data }) {
8055
8250
  stepName: nextStepId,
8056
8251
  input: previousStep?.output,
8057
8252
  mapConfig: data.mapConfig,
8058
- status: nextStep ? previousStep?.status : void 0
8253
+ tripwire: isPreviousTripwire ? previousStep?.tripwire : void 0,
8254
+ status: nextStep ? previousDisplayStatus : void 0
8059
8255
  }
8060
8256
  )
8061
8257
  ]
@@ -8101,6 +8297,8 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8101
8297
  } = data;
8102
8298
  const stepKey = parentWorkflowName ? `${parentWorkflowName}.${stepId || label}` : stepId || label;
8103
8299
  const step = steps[stepKey];
8300
+ const isTripwire = step?.status === "failed" && step?.tripwire !== void 0;
8301
+ const displayStatus = isTripwire ? "tripwire" : step?.status;
8104
8302
  const { isSleepNode, isForEachNode, isMapNode, hasSpecialBadge } = getNodeBadgeInfo({
8105
8303
  duration,
8106
8304
  date,
@@ -8115,16 +8313,17 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8115
8313
  "div",
8116
8314
  {
8117
8315
  "data-workflow-node": true,
8118
- "data-workflow-step-status": step?.status ?? "idle",
8316
+ "data-workflow-step-status": displayStatus ?? "idle",
8119
8317
  "data-testid": "workflow-default-node",
8120
8318
  className: cn(
8121
8319
  "bg-surface3 rounded-lg w-[274px] border-sm border-border1",
8122
8320
  hasSpecialBadge ? "pt-0" : "pt-2",
8123
- step?.status === "success" && "bg-accent1Darker",
8124
- step?.status === "failed" && "bg-accent2Darker",
8125
- step?.status === "suspended" && "bg-accent3Darker",
8126
- step?.status === "waiting" && "bg-accent5Darker",
8127
- step?.status === "running" && "bg-accent6Darker"
8321
+ displayStatus === "success" && "bg-accent1Darker",
8322
+ displayStatus === "failed" && "bg-accent2Darker",
8323
+ displayStatus === "tripwire" && "bg-amber-950/40 border-amber-500/30",
8324
+ displayStatus === "suspended" && "bg-accent3Darker",
8325
+ displayStatus === "waiting" && "bg-accent5Darker",
8326
+ displayStatus === "running" && "bg-accent6Darker"
8128
8327
  ),
8129
8328
  children: [
8130
8329
  hasSpecialBadge && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pt-2 pb-1 flex gap-1.5 flex-wrap", children: [
@@ -8142,11 +8341,12 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8142
8341
  ] }),
8143
8342
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
8144
8343
  /* @__PURE__ */ jsxRuntime.jsxs(Icon, { children: [
8145
- step?.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8146
- step?.status === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8147
- step?.status === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8148
- step?.status === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8149
- step?.status === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8344
+ displayStatus === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8345
+ displayStatus === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8346
+ displayStatus === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8347
+ displayStatus === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8348
+ displayStatus === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8349
+ displayStatus === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8150
8350
  !step && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { className: "text-icon2" })
8151
8351
  ] }),
8152
8352
  /* @__PURE__ */ jsxRuntime.jsxs(Txt, { variant: "ui-lg", className: "text-icon6 font-medium inline-flex items-center gap-1 justify-between w-full", children: [
@@ -8176,9 +8376,10 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8176
8376
  resumeData: step?.resumeData,
8177
8377
  output: step?.output,
8178
8378
  suspendOutput: step?.suspendOutput,
8179
- error: step?.error,
8379
+ error: isTripwire ? void 0 : step?.error,
8380
+ tripwire: isTripwire ? step?.tripwire : void 0,
8180
8381
  mapConfig,
8181
- status: step?.status,
8382
+ status: displayStatus,
8182
8383
  stepKey
8183
8384
  }
8184
8385
  )
@@ -8242,172 +8443,29 @@ function WorkflowLoopResultNode({ data }) {
8242
8443
  );
8243
8444
  }
8244
8445
 
8245
- function Spinner({ color = "#fff", className }) {
8246
- return /* @__PURE__ */ jsxRuntime.jsx(
8247
- "svg",
8248
- {
8249
- className: clsx("animate-spin duration-700", className),
8250
- xmlns: "http://www.w3.org/2000/svg",
8251
- width: "24",
8252
- height: "24",
8253
- viewBox: "0 0 24 24",
8254
- fill: "none",
8255
- stroke: "currentColor",
8256
- strokeWidth: "2",
8257
- strokeLinecap: "round",
8258
- strokeLinejoin: "round",
8259
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
8260
- }
8261
- );
8262
- }
8263
-
8264
- const Slider = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
8265
- SliderPrimitive__namespace.Root,
8266
- {
8267
- ref,
8268
- className: cn("relative flex w-full touch-none select-none items-center", className),
8269
- ...props,
8270
- children: [
8271
- /* @__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" }) }),
8272
- /* @__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" })
8273
- ]
8274
- }
8275
- ));
8276
- Slider.displayName = SliderPrimitive__namespace.Root.displayName;
8277
-
8278
- const ZoomSlider = React.forwardRef(({ className, ...props }) => {
8279
- const { zoom } = react$2.useViewport();
8280
- const { zoomTo, zoomIn, zoomOut, fitView } = react$2.useReactFlow();
8281
- return /* @__PURE__ */ jsxRuntime.jsxs(react$2.Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
8282
- /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "h-4 w-4" }) }),
8283
- /* @__PURE__ */ jsxRuntime.jsx(
8284
- Slider,
8285
- {
8286
- className: "w-[140px]",
8287
- value: [zoom],
8288
- min: 0.01,
8289
- max: 1,
8290
- step: 0.01,
8291
- onValueChange: (values) => {
8292
- zoomTo(values[0]);
8293
- }
8294
- }
8295
- ),
8296
- /* @__PURE__ */ jsxRuntime.jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }) }),
8297
- /* @__PURE__ */ jsxRuntime.jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
8298
- (100 * zoom).toFixed(0),
8299
- "%"
8300
- ] }),
8301
- /* @__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" }) })
8302
- ] });
8303
- });
8304
- ZoomSlider.displayName = "ZoomSlider";
8305
-
8306
- function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
8307
- const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
8308
- stepGraph
8309
- });
8310
- const [isMounted, setIsMounted] = React.useState(false);
8311
- const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
8312
- const [edges] = react$2.useEdgesState(initialEdges);
8313
- const { steps } = useCurrentRun();
8314
- const nodeTypes = {
8315
- "default-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
8316
- "condition-node": WorkflowConditionNode,
8317
- "after-node": WorkflowAfterNode,
8318
- "loop-result-node": WorkflowLoopResultNode,
8319
- "nested-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
8320
- };
8321
- React.useEffect(() => {
8322
- if (open) {
8323
- setTimeout(() => {
8324
- setIsMounted(true);
8325
- }, 500);
8326
- }
8327
- }, [open]);
8328
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxRuntime.jsxs(
8329
- react$2.ReactFlow,
8330
- {
8331
- nodes,
8332
- edges: edges.map((e) => ({
8333
- ...e,
8334
- style: {
8335
- ...e.style,
8336
- 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
8337
- }
8338
- })),
8339
- fitView: true,
8340
- fitViewOptions: {
8341
- maxZoom: 1
8342
- },
8343
- minZoom: 0.01,
8344
- maxZoom: 1,
8345
- nodeTypes,
8346
- onNodesChange,
8347
- children: [
8348
- /* @__PURE__ */ jsxRuntime.jsx(ZoomSlider, { position: "bottom-left" }),
8349
- /* @__PURE__ */ jsxRuntime.jsx(react$2.Background, { variant: react$2.BackgroundVariant.Lines, gap: 12, size: 0.5 })
8350
- ]
8351
- }
8352
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) });
8353
- }
8354
-
8355
8446
  const WorkflowNestedGraphContext = React.createContext(
8356
8447
  {}
8357
8448
  );
8358
8449
  function WorkflowNestedGraphProvider({ children }) {
8359
- const [stepGraph, setStepGraph] = React.useState(null);
8360
- const [parentStepGraphList, setParentStepGraphList] = React.useState([]);
8361
- const [openDialog, setOpenDialog] = React.useState(false);
8362
- const [label, setLabel] = React.useState("");
8363
- const [fullStep, setFullStep] = React.useState("");
8364
- const closeNestedGraph = () => {
8365
- if (parentStepGraphList.length) {
8366
- const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
8367
- setStepGraph(lastStepGraph.stepGraph);
8368
- setLabel(lastStepGraph.label);
8369
- setFullStep(lastStepGraph.fullStep);
8370
- setParentStepGraphList(parentStepGraphList.slice(0, -1));
8371
- } else {
8372
- setOpenDialog(false);
8373
- setStepGraph(null);
8374
- setLabel("");
8375
- setFullStep("");
8376
- }
8377
- };
8450
+ const { showNestedGraph: showNestedGraphInPanel, closeStepDetail } = useWorkflowStepDetail();
8378
8451
  const showNestedGraph = ({
8379
- label: newLabel,
8380
- stepGraph: newStepGraph,
8381
- fullStep: newFullStep
8452
+ label,
8453
+ stepGraph,
8454
+ fullStep
8382
8455
  }) => {
8383
- if (stepGraph) {
8384
- setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
8385
- }
8386
- setLabel(newLabel);
8387
- setFullStep(newFullStep);
8388
- setStepGraph(newStepGraph);
8389
- setOpenDialog(true);
8456
+ showNestedGraphInPanel({ label, stepGraph, fullStep });
8390
8457
  };
8391
- return /* @__PURE__ */ jsxRuntime.jsxs(
8458
+ const closeNestedGraph = () => {
8459
+ closeStepDetail();
8460
+ };
8461
+ return /* @__PURE__ */ jsxRuntime.jsx(
8392
8462
  WorkflowNestedGraphContext.Provider,
8393
8463
  {
8394
8464
  value: {
8395
8465
  showNestedGraph,
8396
8466
  closeNestedGraph
8397
8467
  },
8398
- children: [
8399
- children,
8400
- /* @__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: [
8401
- /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
8402
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "text-current w-4 h-4" }),
8403
- /* @__PURE__ */ jsxRuntime.jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
8404
- label,
8405
- " workflow"
8406
- ] })
8407
- ] }),
8408
- /* @__PURE__ */ jsxRuntime.jsx(react$2.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedGraph, { stepGraph, open: openDialog, workflowName: fullStep }) })
8409
- ] }) }) }, `${label}-${fullStep}`)
8410
- ]
8468
+ children
8411
8469
  }
8412
8470
  );
8413
8471
  }
@@ -8430,6 +8488,8 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8430
8488
  const fullLabel = parentWorkflowName ? `${parentWorkflowName}.${label}` : label;
8431
8489
  const stepKey = parentWorkflowName ? `${parentWorkflowName}.${stepId || label}` : stepId || label;
8432
8490
  const step = steps[stepKey];
8491
+ const isTripwire = step?.status === "failed" && step?.tripwire !== void 0;
8492
+ const displayStatus = isTripwire ? "tripwire" : step?.status;
8433
8493
  const { isForEachNode, isMapNode, isNestedWorkflow, hasSpecialBadge } = getNodeBadgeInfo({
8434
8494
  isForEach,
8435
8495
  mapConfig,
@@ -8444,15 +8504,16 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8444
8504
  {
8445
8505
  "data-testid": "workflow-nested-node",
8446
8506
  "data-workflow-node": true,
8447
- "data-workflow-step-status": step?.status,
8507
+ "data-workflow-step-status": displayStatus,
8448
8508
  className: cn(
8449
8509
  "bg-surface3 rounded-lg w-[274px] border-sm border-border1",
8450
8510
  hasSpecialBadge ? "pt-0" : "pt-2",
8451
- step?.status === "success" && "bg-accent1Darker",
8452
- step?.status === "failed" && "bg-accent2Darker",
8453
- step?.status === "suspended" && "bg-accent3Darker",
8454
- step?.status === "waiting" && "bg-accent5Darker",
8455
- step?.status === "running" && "bg-accent6Darker"
8511
+ displayStatus === "success" && "bg-accent1Darker",
8512
+ displayStatus === "failed" && "bg-accent2Darker",
8513
+ displayStatus === "tripwire" && "bg-amber-950/40 border-amber-500/30",
8514
+ displayStatus === "suspended" && "bg-accent3Darker",
8515
+ displayStatus === "waiting" && "bg-accent5Darker",
8516
+ displayStatus === "running" && "bg-accent6Darker"
8456
8517
  ),
8457
8518
  children: [
8458
8519
  hasSpecialBadge && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pt-2 pb-1 flex gap-1.5 flex-wrap", children: [
@@ -8464,11 +8525,12 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8464
8525
  ] }),
8465
8526
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
8466
8527
  /* @__PURE__ */ jsxRuntime.jsxs(Icon, { children: [
8467
- step?.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8468
- step?.status === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8469
- step?.status === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8470
- step?.status === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8471
- step?.status === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8528
+ displayStatus === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8529
+ displayStatus === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8530
+ displayStatus === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8531
+ displayStatus === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8532
+ displayStatus === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8533
+ displayStatus === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8472
8534
  !step && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { className: "text-icon2" })
8473
8535
  ] }),
8474
8536
  /* @__PURE__ */ jsxRuntime.jsxs(Txt, { variant: "ui-lg", className: "text-icon6 font-medium inline-flex items-center gap-1 justify-between w-full", children: [
@@ -8488,9 +8550,10 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8488
8550
  output: step?.output,
8489
8551
  suspendOutput: step?.suspendOutput,
8490
8552
  error: step?.error,
8553
+ tripwire: isTripwire ? step?.tripwire : void 0,
8491
8554
  mapConfig,
8492
8555
  onShowNestedGraph: () => showNestedGraph({ label, fullStep: fullLabel, stepGraph }),
8493
- status: step?.status,
8556
+ status: displayStatus,
8494
8557
  stepKey
8495
8558
  }
8496
8559
  )
@@ -8501,6 +8564,48 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8501
8564
  ] });
8502
8565
  }
8503
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
+
8504
8609
  function WorkflowGraphInner({ workflow }) {
8505
8610
  const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
8506
8611
  const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
@@ -8596,7 +8701,12 @@ const WorkflowCard = ({ header, children, footer }) => {
8596
8701
  ] });
8597
8702
  };
8598
8703
 
8599
- const WorkflowStatus = ({ stepId, status, result }) => {
8704
+ const WorkflowStatus = ({ stepId, status, result, tripwire }) => {
8705
+ const [isTripwireExpanded, setIsTripwireExpanded] = React.useState(false);
8706
+ const isTripwire = status === "tripwire";
8707
+ const hasTripwireMetadata = Boolean(
8708
+ tripwire && (tripwire.retry !== void 0 || tripwire.metadata !== void 0 || tripwire.processorId !== void 0)
8709
+ );
8600
8710
  return /* @__PURE__ */ jsxRuntime.jsx(
8601
8711
  WorkflowCard,
8602
8712
  {
@@ -8604,19 +8714,74 @@ const WorkflowStatus = ({ stepId, status, result }) => {
8604
8714
  /* @__PURE__ */ jsxRuntime.jsxs(Icon, { children: [
8605
8715
  status === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8606
8716
  status === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8717
+ status === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8607
8718
  status === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CirclePause, { className: "text-accent3" }),
8608
8719
  status === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8609
8720
  status === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" })
8610
8721
  ] }),
8611
8722
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: stepId.charAt(0).toUpperCase() + stepId.slice(1) })
8612
8723
  ] }),
8613
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
8724
+ children: isTripwire && tripwire ? /* @__PURE__ */ jsxRuntime.jsx(
8725
+ TripwireDetails,
8726
+ {
8727
+ tripwire,
8728
+ isExpanded: isTripwireExpanded,
8729
+ onToggleExpand: () => setIsTripwireExpanded(!isTripwireExpanded),
8730
+ hasMetadata: hasTripwireMetadata
8731
+ }
8732
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
8614
8733
  /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: JSON.stringify(result, null, 2), className: "absolute top-2 right-2 z-10" }),
8615
8734
  /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlighter$1, { data: result })
8616
8735
  ] })
8617
8736
  }
8618
8737
  );
8619
8738
  };
8739
+ const TripwireDetails = ({ tripwire, isExpanded, onToggleExpand, hasMetadata }) => {
8740
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-amber-500/30 bg-amber-950/20 overflow-hidden", children: [
8741
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4", children: [
8742
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "w-5 h-5 text-amber-400 mt-0.5 flex-shrink-0" }),
8743
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
8744
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-200 mb-1", children: "Content Blocked" }),
8745
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-amber-300/90", children: tripwire.reason || "Tripwire triggered" })
8746
+ ] })
8747
+ ] }),
8748
+ hasMetadata && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8749
+ /* @__PURE__ */ jsxRuntime.jsxs(
8750
+ "button",
8751
+ {
8752
+ onClick: onToggleExpand,
8753
+ className: "w-full flex items-center gap-2 px-4 py-2 text-xs text-amber-400/70 hover:text-amber-400 hover:bg-amber-900/20 transition-colors border-t border-amber-500/20",
8754
+ children: [
8755
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3.5 h-3.5" }),
8756
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Details" })
8757
+ ]
8758
+ }
8759
+ ),
8760
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-4 space-y-3 border-t border-amber-500/20 bg-amber-950/10", children: [
8761
+ tripwire.retry !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-3", children: [
8762
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-3.5 h-3.5 text-amber-400/60" }),
8763
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
8764
+ "Retry:",
8765
+ " ",
8766
+ tripwire.retry ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-green-400", children: "Allowed" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-400", children: "Not allowed" })
8767
+ ] })
8768
+ ] }),
8769
+ tripwire.processorId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8770
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-3.5 h-3.5 text-amber-400/60" }),
8771
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
8772
+ "Processor:",
8773
+ " ",
8774
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded bg-amber-900/30 text-amber-200 font-mono", children: tripwire.processorId })
8775
+ ] })
8776
+ ] }),
8777
+ tripwire.metadata !== void 0 && tripwire.metadata !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-1", children: [
8778
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-400/60 mb-1.5", children: "Metadata:" }),
8779
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-amber-200/80 bg-amber-900/30 rounded p-2 overflow-x-auto font-mono", children: String(JSON.stringify(tripwire.metadata, null, 2)) })
8780
+ ] })
8781
+ ] })
8782
+ ] })
8783
+ ] });
8784
+ };
8620
8785
 
8621
8786
  const isObjectEmpty = (objectName) => {
8622
8787
  return objectName && Object.keys(objectName).length === 0 && objectName.constructor === Object;
@@ -8649,11 +8814,11 @@ function WorkflowTrigger({
8649
8814
  setIsRunning(true);
8650
8815
  setCancelResponse(null);
8651
8816
  setResult(null);
8652
- const { runId } = await createWorkflowRun({ workflowId });
8653
- setRunId?.(runId);
8654
- setInnerRunId(runId);
8655
- setContextRunId(runId);
8656
- 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 });
8657
8822
  } catch (err) {
8658
8823
  setIsRunning(false);
8659
8824
  sonner.toast.error("Error executing workflow");
@@ -8663,10 +8828,10 @@ function WorkflowTrigger({
8663
8828
  if (!workflow) return;
8664
8829
  setCancelResponse(null);
8665
8830
  const { stepId, runId: prevRunId, resumeData } = step;
8666
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
8831
+ const run = await createWorkflowRun({ workflowId, prevRunId });
8667
8832
  await resumeWorkflow({
8668
8833
  step: stepId,
8669
- runId,
8834
+ runId: run.runId,
8670
8835
  resumeData,
8671
8836
  workflowId,
8672
8837
  requestContext
@@ -8709,8 +8874,8 @@ function WorkflowTrigger({
8709
8874
  const zodInputSchema = triggerSchema ? resolveSerializedZodOutput(jsonToZod.jsonSchemaToZod(superjson.parse(triggerSchema))) : null;
8710
8875
  const workflowActivePaths = streamResultToUse?.steps ?? {};
8711
8876
  const hasWorkflowActivePaths = Object.values(workflowActivePaths).length > 0;
8712
- const doneStatuses = ["success", "failed", "canceled"];
8713
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full pt-3 pb-12 overflow-y-auto", children: [
8877
+ const doneStatuses = ["success", "failed", "canceled", "tripwire"];
8878
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full pt-3 overflow-y-auto", children: [
8714
8879
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 px-5 pb-5 border-b-sm border-border1", children: [
8715
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: [
8716
8881
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin text-icon6" }) }),
@@ -8793,18 +8958,30 @@ function WorkflowTrigger({
8793
8958
  const { status } = step;
8794
8959
  let output = void 0;
8795
8960
  let suspendOutput = void 0;
8961
+ let error = void 0;
8796
8962
  if (step.status === "suspended") {
8797
8963
  suspendOutput = step.suspendOutput;
8798
8964
  }
8799
8965
  if (step.status === "success") {
8800
8966
  output = step.output;
8801
8967
  }
8968
+ if (step.status === "failed") {
8969
+ error = step.error;
8970
+ }
8971
+ const tripwireInfo = step.status === "failed" && step.tripwire ? step.tripwire : streamResultToUse?.status === "tripwire" ? {
8972
+ reason: streamResultToUse?.tripwire?.reason,
8973
+ retry: streamResultToUse?.tripwire?.retry,
8974
+ metadata: streamResultToUse?.tripwire?.metadata,
8975
+ processorId: streamResultToUse?.tripwire?.processorId
8976
+ } : void 0;
8977
+ const displayStatus = step.status === "failed" && step.tripwire ? "tripwire" : status;
8802
8978
  return /* @__PURE__ */ jsxRuntime.jsx(
8803
8979
  WorkflowStatus,
8804
8980
  {
8805
8981
  stepId,
8806
- status,
8807
- result: output ?? suspendOutput ?? {}
8982
+ status: displayStatus,
8983
+ result: output ?? suspendOutput ?? error ?? {},
8984
+ tripwire: tripwireInfo
8808
8985
  },
8809
8986
  stepId
8810
8987
  );
@@ -9153,10 +9330,14 @@ const columns$4 = [
9153
9330
  header: "Name",
9154
9331
  cell: ({ row }) => {
9155
9332
  const { Link, paths } = useLinkComponent();
9333
+ const workflow = row.original;
9156
9334
  return /* @__PURE__ */ jsxRuntime.jsx(
9157
9335
  EntryCell,
9158
9336
  {
9159
- name: /* @__PURE__ */ jsxRuntime.jsx(Link, { href: paths.workflowLink(row.original.id), children: row.original.name }),
9337
+ name: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9338
+ /* @__PURE__ */ jsxRuntime.jsx(Link, { href: paths.workflowLink(row.original.id), children: row.original.name }),
9339
+ workflow.isProcessorWorkflow && /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cpu, { className: "h-3 w-3" }), className: "!h-badge-sm bg-violet-500/20 text-violet-400", children: "Processor" })
9340
+ ] }),
9160
9341
  description: void 0,
9161
9342
  meta: void 0
9162
9343
  }
@@ -9368,19 +9549,33 @@ const PlaygroundTabs = ({
9368
9549
  const TabList$1 = ({ children, className }) => {
9369
9550
  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 }) });
9370
9551
  };
9371
- const Tab$1 = ({ children, value, onClick }) => {
9372
- return /* @__PURE__ */ jsxRuntime.jsx(
9552
+ const Tab$1 = ({ children, value, onClick, onClose }) => {
9553
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9373
9554
  TabsTrigger,
9374
9555
  {
9375
9556
  value,
9376
- 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",
9557
+ 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",
9377
9558
  onClick,
9378
- children
9559
+ children: [
9560
+ children,
9561
+ onClose && /* @__PURE__ */ jsxRuntime.jsx(
9562
+ "button",
9563
+ {
9564
+ onClick: (e) => {
9565
+ e.stopPropagation();
9566
+ onClose();
9567
+ },
9568
+ className: "p-0.5 hover:bg-surface3 rounded transition-colors",
9569
+ "aria-label": "Close tab",
9570
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
9571
+ }
9572
+ )
9573
+ ]
9379
9574
  }
9380
9575
  );
9381
9576
  };
9382
9577
  const TabContent$1 = ({ children, value }) => {
9383
- return /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value, className: "h-full overflow-hidden flex flex-col", children });
9578
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value, className: "h-full overflow-auto flex flex-col", children });
9384
9579
  };
9385
9580
 
9386
9581
  const TracingRunOptions = () => {
@@ -9403,20 +9598,127 @@ const TracingRunOptions = () => {
9403
9598
  strValue = JSON.stringify(settings?.tracingOptions, null, 2);
9404
9599
  } catch {
9405
9600
  }
9406
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 px-5 py-2", children: [
9407
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "h3", variant: "ui-md", className: "text-icon3", children: "Tracing Options" }),
9408
- /* @__PURE__ */ jsxRuntime.jsx(
9409
- CodeMirror,
9410
- {
9411
- value: strValue,
9412
- onChange: handleChange,
9413
- theme,
9414
- extensions: [langJson.jsonLanguage],
9415
- className: "h-[400px] overflow-y-scroll bg-surface3 rounded-lg overflow-hidden p-3"
9416
- }
9417
- )
9601
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 px-5 py-2", children: [
9602
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "h3", variant: "ui-md", className: "text-icon3", children: "Tracing Options" }),
9603
+ /* @__PURE__ */ jsxRuntime.jsx(
9604
+ CodeMirror,
9605
+ {
9606
+ value: strValue,
9607
+ onChange: handleChange,
9608
+ theme,
9609
+ extensions: [langJson.jsonLanguage],
9610
+ className: "h-[400px] overflow-y-scroll bg-surface3 rounded-lg overflow-hidden p-3"
9611
+ }
9612
+ )
9613
+ ] });
9614
+ };
9615
+
9616
+ function Spinner({ color = "#fff", className }) {
9617
+ return /* @__PURE__ */ jsxRuntime.jsx(
9618
+ "svg",
9619
+ {
9620
+ className: clsx("animate-spin duration-700", className),
9621
+ xmlns: "http://www.w3.org/2000/svg",
9622
+ width: "24",
9623
+ height: "24",
9624
+ viewBox: "0 0 24 24",
9625
+ fill: "none",
9626
+ stroke: "currentColor",
9627
+ strokeWidth: "2",
9628
+ strokeLinecap: "round",
9629
+ strokeLinejoin: "round",
9630
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", stroke: color })
9631
+ }
9632
+ );
9633
+ }
9634
+
9635
+ function WorkflowNestedGraph({ stepGraph, open, workflowName }) {
9636
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
9637
+ stepGraph
9638
+ });
9639
+ const [isMounted, setIsMounted] = React.useState(false);
9640
+ const [nodes, _, onNodesChange] = react$2.useNodesState(initialNodes);
9641
+ const [edges] = react$2.useEdgesState(initialEdges);
9642
+ const { steps } = useCurrentRun();
9643
+ const nodeTypes = {
9644
+ "default-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowDefaultNode, { parentWorkflowName: workflowName, ...props }),
9645
+ "condition-node": WorkflowConditionNode,
9646
+ "after-node": WorkflowAfterNode,
9647
+ "loop-result-node": WorkflowLoopResultNode,
9648
+ "nested-node": (props) => /* @__PURE__ */ jsxRuntime.jsx(WorkflowNestedNode, { parentWorkflowName: workflowName, ...props })
9649
+ };
9650
+ React.useEffect(() => {
9651
+ if (open) {
9652
+ setTimeout(() => {
9653
+ setIsMounted(true);
9654
+ }, 500);
9655
+ }
9656
+ }, [open]);
9657
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxRuntime.jsxs(
9658
+ react$2.ReactFlow,
9659
+ {
9660
+ nodes,
9661
+ edges: edges.map((e) => ({
9662
+ ...e,
9663
+ style: {
9664
+ ...e.style,
9665
+ 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
9666
+ }
9667
+ })),
9668
+ fitView: true,
9669
+ fitViewOptions: {
9670
+ maxZoom: 1
9671
+ },
9672
+ minZoom: 0.01,
9673
+ maxZoom: 1,
9674
+ nodeTypes,
9675
+ onNodesChange,
9676
+ children: [
9677
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomSlider, { position: "bottom-left" }),
9678
+ /* @__PURE__ */ jsxRuntime.jsx(react$2.Background, { variant: react$2.BackgroundVariant.Lines, gap: 12, size: 0.5 })
9679
+ ]
9680
+ }
9681
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) });
9682
+ }
9683
+
9684
+ function WorkflowStepDetailContent() {
9685
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9686
+ if (!stepDetail) {
9687
+ return null;
9688
+ }
9689
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
9690
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b-sm border-border1 bg-surface1", children: [
9691
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9692
+ stepDetail.type === "map-config" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.List, { className: "w-4 h-4", style: { color: BADGE_COLORS.map } }),
9693
+ stepDetail.type === "nested-graph" && /* @__PURE__ */ jsxRuntime.jsx(WorkflowIcon, { className: "w-4 h-4", style: { color: BADGE_COLORS.workflow } }),
9694
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
9695
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-md", className: "text-icon6 font-medium", children: stepDetail.type === "map-config" ? `${stepDetail.stepName} Config` : `${stepDetail.stepName} Workflow` }),
9696
+ stepDetail.type === "map-config" && stepDetail.stepId && stepDetail.stepId !== stepDetail.stepName && /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-icon3", children: stepDetail.stepId })
9697
+ ] })
9698
+ ] }),
9699
+ /* @__PURE__ */ jsxRuntime.jsx(
9700
+ "button",
9701
+ {
9702
+ onClick: closeStepDetail,
9703
+ className: "p-1 hover:bg-surface3 rounded transition-colors",
9704
+ "aria-label": "Close",
9705
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4 text-icon3" })
9706
+ }
9707
+ )
9708
+ ] }),
9709
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto", children: [
9710
+ stepDetail.type === "map-config" && stepDetail.mapConfig && /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: stepDetail.mapConfig }),
9711
+ 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(
9712
+ WorkflowNestedGraph,
9713
+ {
9714
+ stepGraph: stepDetail.nestedGraph.stepGraph,
9715
+ open: true,
9716
+ workflowName: stepDetail.nestedGraph.fullStep
9717
+ }
9718
+ ) }) })
9719
+ ] })
9418
9720
  ] });
9419
- };
9721
+ }
9420
9722
 
9421
9723
  function WorkflowInformation({ workflowId, initialRunId }) {
9422
9724
  const { data: workflow, isLoading, error } = useWorkflow(workflowId);
@@ -9431,10 +9733,21 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9431
9733
  cancelWorkflowRun,
9432
9734
  isCancellingWorkflowRun
9433
9735
  } = React.useContext(WorkflowRunContext);
9736
+ const { stepDetail, closeStepDetail } = useWorkflowStepDetail();
9434
9737
  const [tab, setTab] = React.useState("current-run");
9435
9738
  const [runId, setRunId] = React.useState("");
9436
9739
  const { handleCopy } = useCopyToClipboard({ text: workflowId });
9437
9740
  const stepsCount = Object.keys(workflow?.steps ?? {}).length;
9741
+ const nodeDetailTabName = React.useMemo(() => {
9742
+ if (!stepDetail) return null;
9743
+ if (stepDetail.type === "map-config") {
9744
+ return "Map Config";
9745
+ }
9746
+ if (stepDetail.type === "nested-graph") {
9747
+ return "Nested Workflow";
9748
+ }
9749
+ return "Node";
9750
+ }, [stepDetail]);
9438
9751
  React.useEffect(() => {
9439
9752
  if (!runId && !initialRunId) {
9440
9753
  closeStreamsAndReset();
@@ -9446,6 +9759,19 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9446
9759
  toast.error(`Error loading workflow: ${errorMessage}`);
9447
9760
  }
9448
9761
  }, [error]);
9762
+ React.useEffect(() => {
9763
+ if (stepDetail) {
9764
+ setTab("node-details");
9765
+ } else if (tab === "node-details") {
9766
+ setTab("current-run");
9767
+ }
9768
+ }, [stepDetail]);
9769
+ const handleTabChange = (newTab) => {
9770
+ if (tab === "node-details" && newTab !== "node-details") {
9771
+ closeStepDetail();
9772
+ }
9773
+ setTab(newTab);
9774
+ };
9449
9775
  if (error) {
9450
9776
  return null;
9451
9777
  }
@@ -9459,12 +9785,27 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9459
9785
  stepsCount,
9460
9786
  " step",
9461
9787
  stepsCount > 1 ? "s" : ""
9462
- ] })
9788
+ ] }),
9789
+ 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" })
9463
9790
  ] }) }),
9464
- /* @__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: [
9791
+ /* @__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: [
9465
9792
  /* @__PURE__ */ jsxRuntime.jsxs(TabList$1, { children: [
9466
9793
  /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "current-run", children: "Current Run" }),
9467
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "run-options", children: "Run options" })
9794
+ /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "run-options", children: "Run Options" }),
9795
+ stepDetail && nodeDetailTabName && /* @__PURE__ */ jsxRuntime.jsxs(
9796
+ Tab$1,
9797
+ {
9798
+ value: "node-details",
9799
+ onClose: () => {
9800
+ closeStepDetail();
9801
+ setTab("current-run");
9802
+ },
9803
+ children: [
9804
+ nodeDetailTabName,
9805
+ " Details"
9806
+ ]
9807
+ }
9808
+ )
9468
9809
  ] }),
9469
9810
  /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "current-run", children: workflowId ? initialRunId ? /* @__PURE__ */ jsxRuntime.jsx(
9470
9811
  WorkflowRunDetail,
@@ -9499,7 +9840,8 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9499
9840
  cancelWorkflowRun
9500
9841
  }
9501
9842
  ) : null }),
9502
- /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsxRuntime.jsx(TracingRunOptions, {}) })
9843
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "run-options", children: /* @__PURE__ */ jsxRuntime.jsx(TracingRunOptions, {}) }),
9844
+ stepDetail && /* @__PURE__ */ jsxRuntime.jsx(TabContent$1, { value: "node-details", children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowStepDetailContent, {}) })
9503
9845
  ] }) })
9504
9846
  ] });
9505
9847
  }
@@ -9731,7 +10073,8 @@ const WorkflowBadge = ({
9731
10073
  isStreaming,
9732
10074
  metadata,
9733
10075
  toolCallId,
9734
- toolApprovalMetadata
10076
+ toolApprovalMetadata,
10077
+ suspendPayload
9735
10078
  }) => {
9736
10079
  const { runId, status } = result || {};
9737
10080
  const { data: workflow, isLoading: isWorkflowLoading } = useWorkflow(workflowId);
@@ -9743,6 +10086,7 @@ const WorkflowBadge = ({
9743
10086
  const snapshot = typeof run?.snapshot === "object" ? run?.snapshot : void 0;
9744
10087
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
9745
10088
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
10089
+ 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" });
9746
10090
  if (isWorkflowLoading || !workflow) return /* @__PURE__ */ jsxRuntime.jsx(LoadingBadge, {});
9747
10091
  return /* @__PURE__ */ jsxRuntime.jsxs(
9748
10092
  BadgeWrapper,
@@ -9759,6 +10103,10 @@ const WorkflowBadge = ({
9759
10103
  }
9760
10104
  ),
9761
10105
  children: [
10106
+ suspendPayloadSlot !== void 0 && suspendPayload && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10107
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium pb-2", children: "Tool suspend payload" }),
10108
+ suspendPayloadSlot
10109
+ ] }),
9762
10110
  !isStreaming && !isLoading && /* @__PURE__ */ jsxRuntime.jsx(WorkflowRunProvider, { snapshot, workflowId, initialRunId: runId, withoutTimeTravel: true, children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }) }),
9763
10111
  isStreaming && /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }),
9764
10112
  /* @__PURE__ */ jsxRuntime.jsx(ToolApprovalButtons, { toolCalled: !!status, toolCallId, toolApprovalMetadata })
@@ -9894,7 +10242,9 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
9894
10242
  const agentToolName = toolName.startsWith("agent-") ? toolName.substring("agent-".length) : toolName;
9895
10243
  const workflowToolName = toolName.startsWith("workflow-") ? toolName.substring("workflow-".length) : toolName;
9896
10244
  const requireApprovalMetadata = metadata?.mode === "stream" && metadata?.requireApprovalMetadata;
9897
- const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolCallId] : void 0;
10245
+ const suspendedTools = metadata?.mode === "stream" && metadata?.suspendedTools;
10246
+ const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolName] ?? requireApprovalMetadata?.[toolCallId] : void 0;
10247
+ const suspendedToolMetadata = suspendedTools ? suspendedTools?.[toolName] : void 0;
9898
10248
  useWorkflowStream(result);
9899
10249
  if (isAgent) {
9900
10250
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9918,7 +10268,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
9918
10268
  result,
9919
10269
  metadata,
9920
10270
  toolCallId,
9921
- toolApprovalMetadata
10271
+ toolApprovalMetadata,
10272
+ suspendPayload: suspendedToolMetadata?.suspendPayload
9922
10273
  }
9923
10274
  );
9924
10275
  }
@@ -9931,7 +10282,8 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
9931
10282
  toolOutput: result?.toolOutput || [],
9932
10283
  metadata,
9933
10284
  toolCallId,
9934
- toolApprovalMetadata
10285
+ toolApprovalMetadata,
10286
+ suspendPayload: suspendedToolMetadata?.suspendPayload
9935
10287
  }
9936
10288
  );
9937
10289
  };
@@ -11012,25 +11364,36 @@ const ThreadWelcome = ({ agentName }) => {
11012
11364
  };
11013
11365
  const Composer = ({ hasMemory, agentId }) => {
11014
11366
  const { setThreadInput } = useThreadInput();
11367
+ const textareaRef = React.useRef(null);
11015
11368
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-4", children: /* @__PURE__ */ jsxRuntime.jsxs(react.ComposerPrimitive.Root, { children: [
11016
11369
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[568px] w-full mx-auto pb-2", children: /* @__PURE__ */ jsxRuntime.jsx(ComposerAttachments, {}) }),
11017
- /* @__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: [
11018
- /* @__PURE__ */ jsxRuntime.jsx(react.ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
11019
- "textarea",
11020
- {
11021
- className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11022
- autoFocus: document.activeElement === document.body,
11023
- placeholder: "Enter your message...",
11024
- name: "",
11025
- id: "",
11026
- onChange: (e) => setThreadInput?.(e.target.value)
11027
- }
11028
- ) }),
11029
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11030
- /* @__PURE__ */ jsxRuntime.jsx(SpeechInput, { agentId }),
11031
- /* @__PURE__ */ jsxRuntime.jsx(ComposerAction, {})
11032
- ] })
11033
- ] })
11370
+ /* @__PURE__ */ jsxRuntime.jsxs(
11371
+ "div",
11372
+ {
11373
+ 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",
11374
+ onClick: () => {
11375
+ textareaRef.current?.focus();
11376
+ },
11377
+ children: [
11378
+ /* @__PURE__ */ jsxRuntime.jsx(react.ComposerPrimitive.Input, { asChild: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
11379
+ "textarea",
11380
+ {
11381
+ ref: textareaRef,
11382
+ className: "text-ui-lg leading-ui-lg placeholder:text-icon3 text-icon6 bg-transparent focus:outline-none resize-none outline-none",
11383
+ autoFocus: document.activeElement === document.body,
11384
+ placeholder: "Enter your message...",
11385
+ name: "",
11386
+ id: "",
11387
+ onChange: (e) => setThreadInput?.(e.target.value)
11388
+ }
11389
+ ) }),
11390
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11391
+ /* @__PURE__ */ jsxRuntime.jsx(SpeechInput, { agentId }),
11392
+ /* @__PURE__ */ jsxRuntime.jsx(ComposerAction, {})
11393
+ ] })
11394
+ ]
11395
+ }
11396
+ )
11034
11397
  ] }) });
11035
11398
  };
11036
11399
  const SpeechInput = ({ agentId }) => {
@@ -11368,34 +11731,33 @@ function useAgentSettingsState({ agentId, defaultSettings: defaultSettingsProp }
11368
11731
  React.useEffect(() => {
11369
11732
  try {
11370
11733
  const stored = localStorage.getItem(LOCAL_STORAGE_KEY);
11371
- if (stored) {
11372
- const parsed = JSON.parse(stored);
11373
- const settings2 = {
11374
- ...parsed,
11375
- modelSettings: {
11376
- ...defaultSettingsProp?.modelSettings ?? {},
11377
- ...parsed?.modelSettings ?? {}
11378
- }
11379
- };
11380
- setSettingsState(settings2 ?? void 0);
11381
- }
11734
+ const parsed = stored ? JSON.parse(stored) : {};
11735
+ const mergedSettings = {
11736
+ ...parsed,
11737
+ modelSettings: {
11738
+ ...defaultSettings.modelSettings,
11739
+ ...parsed?.modelSettings ?? {},
11740
+ ...defaultSettingsProp?.modelSettings ?? {}
11741
+ // Code defaults win
11742
+ }
11743
+ };
11744
+ setSettingsState(mergedSettings);
11382
11745
  } catch (e) {
11383
- console.error(e);
11384
11746
  }
11385
- }, [LOCAL_STORAGE_KEY]);
11747
+ }, [LOCAL_STORAGE_KEY, defaultSettingsProp]);
11386
11748
  const setSettings = (settingsValue) => {
11387
11749
  setSettingsState((prev) => ({ ...prev, ...settingsValue }));
11388
11750
  localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ ...settingsValue, agentId }));
11389
11751
  };
11390
11752
  const resetAll = () => {
11391
- const settings2 = {
11753
+ const resetSettings = {
11392
11754
  modelSettings: {
11393
- ...defaultSettingsProp?.modelSettings ?? {},
11394
- ...defaultSettings.modelSettings
11755
+ ...defaultSettings.modelSettings,
11756
+ ...defaultSettingsProp?.modelSettings ?? {}
11395
11757
  }
11396
11758
  };
11397
- setSettingsState(settings2);
11398
- localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(settings2));
11759
+ setSettingsState(resetSettings);
11760
+ localStorage.removeItem(LOCAL_STORAGE_KEY);
11399
11761
  };
11400
11762
  return {
11401
11763
  settings,
@@ -11546,18 +11908,19 @@ const initializeMessageState = (initialMessages) => {
11546
11908
  };
11547
11909
  } else if (part.toolInvocation.state === "call") {
11548
11910
  const toolCallId = part.toolInvocation.toolCallId;
11911
+ const toolName = part.toolInvocation.toolName;
11549
11912
  const pendingToolApprovals = message.metadata?.pendingToolApprovals;
11550
11913
  const suspensionData = pendingToolApprovals?.[toolCallId];
11551
11914
  if (suspensionData) {
11552
11915
  return {
11553
11916
  type: "tool-call",
11554
11917
  toolCallId,
11555
- toolName: part.toolInvocation.toolName,
11918
+ toolName,
11556
11919
  args: part.toolInvocation.args,
11557
11920
  metadata: {
11558
11921
  mode: "stream",
11559
11922
  requireApprovalMetadata: {
11560
- [toolCallId]: suspensionData
11923
+ [toolName]: suspensionData
11561
11924
  }
11562
11925
  }
11563
11926
  };
@@ -11627,6 +11990,7 @@ function MastraRuntimeProvider({
11627
11990
  temperature,
11628
11991
  topK,
11629
11992
  topP,
11993
+ seed,
11630
11994
  chatWithGenerateLegacy,
11631
11995
  chatWithGenerate,
11632
11996
  chatWithNetwork,
@@ -11645,7 +12009,9 @@ function MastraRuntimeProvider({
11645
12009
  temperature,
11646
12010
  topK,
11647
12011
  topP,
11648
- maxTokens,
12012
+ seed,
12013
+ maxOutputTokens: maxTokens,
12014
+ // AI SDK v5 uses maxOutputTokens
11649
12015
  instructions,
11650
12016
  providerOptions,
11651
12017
  maxSteps,
@@ -11744,6 +12110,7 @@ function MastraRuntimeProvider({
11744
12110
  temperature,
11745
12111
  topK,
11746
12112
  topP,
12113
+ seed,
11747
12114
  instructions,
11748
12115
  requestContext: requestContextInstance,
11749
12116
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -11860,6 +12227,7 @@ function MastraRuntimeProvider({
11860
12227
  temperature,
11861
12228
  topK,
11862
12229
  topP,
12230
+ seed,
11863
12231
  instructions,
11864
12232
  requestContext: requestContextInstance,
11865
12233
  ...memory ? { threadId, resourceId: agentId } : {},
@@ -12180,54 +12548,60 @@ const AgentAdvancedSettings = () => {
12180
12548
  ] }),
12181
12549
  /* @__PURE__ */ jsxRuntime.jsxs(CollapsibleContent, { className: collapsibleContentClassName, children: [
12182
12550
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12183
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12551
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12184
12552
  /* @__PURE__ */ jsxRuntime.jsx(
12185
12553
  Input,
12186
12554
  {
12187
- id: "top-k",
12555
+ id: "frequency-penalty",
12188
12556
  type: "number",
12189
- value: settings?.modelSettings?.topK || "",
12557
+ step: "0.1",
12558
+ min: "-1",
12559
+ max: "1",
12560
+ value: settings?.modelSettings?.frequencyPenalty ?? "",
12190
12561
  onChange: (e) => setSettings({
12191
12562
  ...settings,
12192
12563
  modelSettings: {
12193
12564
  ...settings?.modelSettings,
12194
- topK: e.target.value ? Number(e.target.value) : void 0
12565
+ frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12195
12566
  }
12196
12567
  })
12197
12568
  }
12198
12569
  )
12199
12570
  ] }),
12200
12571
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12201
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "frequency-penalty", children: "Frequency Penalty" }),
12572
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12202
12573
  /* @__PURE__ */ jsxRuntime.jsx(
12203
12574
  Input,
12204
12575
  {
12205
- id: "frequency-penalty",
12576
+ id: "presence-penalty",
12206
12577
  type: "number",
12207
- value: settings?.modelSettings?.frequencyPenalty || "",
12578
+ step: "0.1",
12579
+ min: "-1",
12580
+ max: "1",
12581
+ value: settings?.modelSettings?.presencePenalty ?? "",
12208
12582
  onChange: (e) => setSettings({
12209
12583
  ...settings,
12210
12584
  modelSettings: {
12211
12585
  ...settings?.modelSettings,
12212
- frequencyPenalty: e.target.value ? Number(e.target.value) : void 0
12586
+ presencePenalty: e.target.value ? Number(e.target.value) : void 0
12213
12587
  }
12214
12588
  })
12215
12589
  }
12216
12590
  )
12217
12591
  ] }),
12218
12592
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12219
- /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "presence-penalty", children: "Presence Penalty" }),
12593
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "top-k", children: "Top K" }),
12220
12594
  /* @__PURE__ */ jsxRuntime.jsx(
12221
12595
  Input,
12222
12596
  {
12223
- id: "presence-penalty",
12597
+ id: "top-k",
12224
12598
  type: "number",
12225
- value: settings?.modelSettings?.presencePenalty || "",
12599
+ value: settings?.modelSettings?.topK || "",
12226
12600
  onChange: (e) => setSettings({
12227
12601
  ...settings,
12228
12602
  modelSettings: {
12229
12603
  ...settings?.modelSettings,
12230
- presencePenalty: e.target.value ? Number(e.target.value) : void 0
12604
+ topK: e.target.value ? Number(e.target.value) : void 0
12231
12605
  }
12232
12606
  })
12233
12607
  }
@@ -12287,6 +12661,24 @@ const AgentAdvancedSettings = () => {
12287
12661
  }
12288
12662
  )
12289
12663
  ] }),
12664
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
12665
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "seed", children: "Seed" }),
12666
+ /* @__PURE__ */ jsxRuntime.jsx(
12667
+ Input,
12668
+ {
12669
+ id: "seed",
12670
+ type: "number",
12671
+ value: settings?.modelSettings?.seed || "",
12672
+ onChange: (e) => setSettings({
12673
+ ...settings,
12674
+ modelSettings: {
12675
+ ...settings?.modelSettings,
12676
+ seed: e.target.value ? Number(e.target.value) : void 0
12677
+ }
12678
+ })
12679
+ }
12680
+ )
12681
+ ] }),
12290
12682
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 col-span-2", children: [
12291
12683
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
12292
12684
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "label", className: "text-icon3", variant: "ui-sm", htmlFor: "provider-options", children: "Provider Options" }),
@@ -15298,6 +15690,7 @@ const AgentMetadataModelList = ({
15298
15690
  }) => {
15299
15691
  const [modelConfigs, setModelConfigs] = React.useState(() => modelList);
15300
15692
  const hasMultipleModels = modelConfigs.length > 1;
15693
+ const enabledCount = modelConfigs.filter((m) => m.enabled !== false).length;
15301
15694
  const handleDragEnd = (result) => {
15302
15695
  if (!result.destination) {
15303
15696
  return;
@@ -15332,7 +15725,8 @@ const AgentMetadataModelList = ({
15332
15725
  modelConfig,
15333
15726
  updateModelInModelList: updateModel,
15334
15727
  showDragHandle: hasMultipleModels,
15335
- dragHandleProps: provided2.dragHandleProps
15728
+ dragHandleProps: provided2.dragHandleProps,
15729
+ isLastEnabled: modelConfig.enabled !== false && enabledCount === 1
15336
15730
  }
15337
15731
  ) }) }, modelConfig.id)),
15338
15732
  provided.placeholder
@@ -15342,7 +15736,8 @@ const AgentMetadataModelListItem = ({
15342
15736
  modelConfig,
15343
15737
  updateModelInModelList,
15344
15738
  showDragHandle,
15345
- dragHandleProps
15739
+ dragHandleProps,
15740
+ isLastEnabled
15346
15741
  }) => {
15347
15742
  const [enabled, setEnabled] = React.useState(() => modelConfig.enabled);
15348
15743
  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: [
@@ -15356,7 +15751,10 @@ const AgentMetadataModelListItem = ({
15356
15751
  autoSave: true
15357
15752
  }
15358
15753
  ) }),
15359
- /* @__PURE__ */ jsxRuntime.jsx(
15754
+ isLastEnabled ? /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
15755
+ /* @__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" }) }) }),
15756
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "At least one model must be enabled" }) })
15757
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsx(
15360
15758
  Switch,
15361
15759
  {
15362
15760
  checked: enabled,
@@ -15374,7 +15772,14 @@ function usePromptEnhancer({ agentId }) {
15374
15772
  const client = react$1.useMastraClient();
15375
15773
  return reactQuery.useMutation({
15376
15774
  mutationFn: async ({ instructions, userComment }) => {
15377
- return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15775
+ try {
15776
+ return await client.getAgent(agentId).enhanceInstructions(instructions, userComment);
15777
+ } catch (error) {
15778
+ const errorMessage = error instanceof Error ? error.message : "Error enhancing prompt";
15779
+ toast.error(errorMessage);
15780
+ console.error("Error enhancing prompt:", error);
15781
+ throw error;
15782
+ }
15378
15783
  }
15379
15784
  });
15380
15785
  }
@@ -15417,21 +15822,53 @@ const PromptEnhancer = ({ agentId }) => {
15417
15822
  const PromptEnhancerTextarea = ({ agentId }) => {
15418
15823
  const { prompt, setPrompt } = useAgentPromptExperiment();
15419
15824
  const { mutateAsync: enhancePrompt, isPending } = usePromptEnhancer({ agentId });
15825
+ const { data: agent, isLoading: isAgentLoading, isError: isAgentError } = useAgent(agentId);
15826
+ const { data: providersData, isLoading: isProvidersLoading } = useAgentsModelProviders();
15827
+ const providers = providersData?.providers || [];
15828
+ const isProviderConnected = (providerId) => {
15829
+ const cleanId = cleanProviderId(providerId);
15830
+ const provider = providers.find((p) => cleanProviderId(p.id) === cleanId);
15831
+ return provider?.connected === true;
15832
+ };
15833
+ const hasConnectedModel = () => {
15834
+ if (agent?.modelList && agent.modelList.length > 0) {
15835
+ return agent.modelList.some((m) => m.enabled !== false && isProviderConnected(m.model.provider));
15836
+ }
15837
+ return agent?.provider ? isProviderConnected(agent.provider) : false;
15838
+ };
15839
+ const isDataLoading = isAgentLoading || isProvidersLoading;
15840
+ const hasValidModel = !isDataLoading && !isAgentError && hasConnectedModel();
15420
15841
  const handleSubmit = async (e) => {
15421
15842
  e.preventDefault();
15422
15843
  const form = e.target;
15423
15844
  const formData = new FormData(form);
15424
15845
  const userComment = formData.get("userComment");
15425
- const result = await enhancePrompt({ instructions: prompt, userComment });
15426
- form.reset();
15427
- setPrompt(result.new_prompt);
15846
+ try {
15847
+ const result = await enhancePrompt({ instructions: prompt, userComment });
15848
+ form.reset();
15849
+ setPrompt(result.new_prompt);
15850
+ } catch {
15851
+ }
15428
15852
  };
15853
+ const isDisabled = isPending || !hasValidModel;
15854
+ const showWarning = !isDataLoading && !hasValidModel;
15429
15855
  return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
15430
- /* @__PURE__ */ jsxRuntime.jsx(Input, { name: "userComment", placeholder: "Enter your comment here...", className: "resize-none", disabled: isPending }),
15431
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(Button$1, { variant: "light", type: "submit", disabled: isPending, children: [
15432
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcwIcon, {}) }),
15433
- "Enhance prompt"
15434
- ] }) })
15856
+ /* @__PURE__ */ jsxRuntime.jsx(
15857
+ Input,
15858
+ {
15859
+ name: "userComment",
15860
+ placeholder: "Enter your comment here...",
15861
+ className: "resize-none",
15862
+ disabled: isDisabled
15863
+ }
15864
+ ),
15865
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end items-center gap-2", children: [
15866
+ showWarning && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-yellow-200", children: "No model with a configured API key found." }),
15867
+ /* @__PURE__ */ jsxRuntime.jsxs(Button$1, { variant: "light", type: "submit", disabled: isDisabled, children: [
15868
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: isPending ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcwIcon, {}) }),
15869
+ "Enhance prompt"
15870
+ ] })
15871
+ ] })
15435
15872
  ] });
15436
15873
  };
15437
15874
 
@@ -16205,13 +16642,16 @@ const AgentWorkingMemory = ({ agentId }) => {
16205
16642
  placeholder: "Enter working memory content..."
16206
16643
  }
16207
16644
  ),
16208
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
16645
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2", children: !isEditing ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: !threadExists ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
16646
+ /* @__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" }) }) }),
16647
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Working memory will be available after the agent calls updateWorkingMemory" }) })
16648
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
16209
16649
  Button$2,
16210
16650
  {
16211
16651
  variant: "secondary",
16212
16652
  size: "sm",
16213
16653
  onClick: () => setIsEditing(true),
16214
- disabled: !threadExists || isUpdating,
16654
+ disabled: isUpdating,
16215
16655
  className: "text-xs",
16216
16656
  children: "Edit Working Memory"
16217
16657
  }
@@ -16308,22 +16748,6 @@ const AgentMemoryConfig = ({ agentId }) => {
16308
16748
  ]
16309
16749
  });
16310
16750
  }
16311
- if (config.workingMemory) {
16312
- sections.push({
16313
- title: "Working Memory",
16314
- items: [
16315
- {
16316
- label: "Enabled",
16317
- value: config.workingMemory.enabled,
16318
- badge: config.workingMemory.enabled ? "success" : void 0
16319
- },
16320
- ...config.workingMemory.enabled ? [
16321
- { label: "Scope", value: config.workingMemory.scope || "resource" },
16322
- { label: "Template", value: config.workingMemory.template || "default" }
16323
- ] : []
16324
- ]
16325
- });
16326
- }
16327
16751
  return sections;
16328
16752
  }, [config]);
16329
16753
  const toggleSection = (title) => {
@@ -16383,7 +16807,7 @@ const AgentMemoryConfig = ({ agentId }) => {
16383
16807
  ),
16384
16808
  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: [
16385
16809
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-icon3", children: item.label }),
16386
- renderValue(item.value || "", item.badge)
16810
+ renderValue(item.value ?? "", item.badge)
16387
16811
  ] }, `${section.title}-${item.label}`)) })
16388
16812
  ] }, section.title)) })
16389
16813
  ] });
@@ -18514,6 +18938,17 @@ const Tabs = Object.assign(TabsRoot, {
18514
18938
  Content: TabContent
18515
18939
  });
18516
18940
 
18941
+ function isTokenDetailsObject(value) {
18942
+ return typeof value === "object" && value !== null;
18943
+ }
18944
+ const detailKeyLabels = {
18945
+ text: "Text",
18946
+ cacheRead: "Cache Read",
18947
+ cacheWrite: "Cache Write",
18948
+ audio: "Audio",
18949
+ image: "Image",
18950
+ reasoning: "Reasoning"
18951
+ };
18517
18952
  function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18518
18953
  if (!traceUsage && !spanUsage) {
18519
18954
  console.warn("No usage data available");
@@ -18618,6 +19053,14 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18618
19053
  cachedInputTokens: {
18619
19054
  label: "Cached Input Tokens",
18620
19055
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {})
19056
+ },
19057
+ inputDetails: {
19058
+ label: "Input Details",
19059
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {})
19060
+ },
19061
+ outputDetails: {
19062
+ label: "Output Details",
19063
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {})
18621
19064
  }
18622
19065
  };
18623
19066
  const commonTokenPresentations = {
@@ -18633,47 +19076,79 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
18633
19076
  };
18634
19077
  let usageKeyOrder = [];
18635
19078
  if (hasV5Format) {
18636
- usageKeyOrder = ["totalTokens", "inputTokens", "outputTokens", "reasoningTokens", "cachedInputTokens"];
19079
+ usageKeyOrder = [
19080
+ "totalTokens",
19081
+ "inputTokens",
19082
+ "outputTokens",
19083
+ "reasoningTokens",
19084
+ "cachedInputTokens",
19085
+ "inputDetails",
19086
+ "outputDetails"
19087
+ ];
18637
19088
  } else {
18638
19089
  usageKeyOrder = ["totalTokens", "promptTokens", "completionTokens"];
18639
19090
  }
18640
- const usageAsArray = Object.entries(traceUsage || spanUsage || {}).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
18641
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => /* @__PURE__ */ jsxRuntime.jsxs(
18642
- "div",
18643
- {
18644
- className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
18645
- "min-h-[5.5rem]": traceUsage
18646
- }),
18647
- children: [
18648
- /* @__PURE__ */ jsxRuntime.jsxs(
18649
- "div",
18650
- {
18651
- className: cn(
18652
- "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
18653
- "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
18654
- ),
18655
- children: [
18656
- tokenPresentations?.[key]?.icon,
18657
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
18658
- /* @__PURE__ */ jsxRuntime.jsx("b", { className: "text-[1rem]", children: value })
18659
- ]
18660
- }
18661
- ),
18662
- tokensByProviderValid && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => /* @__PURE__ */ jsxRuntime.jsxs(
18663
- "dl",
18664
- {
18665
- className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
18666
- children: [
18667
- /* @__PURE__ */ jsxRuntime.jsx("dt", { children: provider }),
18668
- /* @__PURE__ */ jsxRuntime.jsx("dd", { children: providerTokens?.[key] })
18669
- ]
18670
- },
18671
- provider
18672
- )) })
18673
- ]
18674
- },
18675
- key
18676
- )) });
19091
+ const usageAsArray = Object.entries(traceUsage || spanUsage || {}).filter((entry) => {
19092
+ const value = entry[1];
19093
+ return typeof value === "number" || isTokenDetailsObject(value);
19094
+ }).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
19095
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-[1.5rem] flex-wrap", className), children: usageAsArray.map(({ key, value }) => {
19096
+ const isObject = isTokenDetailsObject(value);
19097
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19098
+ "div",
19099
+ {
19100
+ className: cn("bg-white/5 p-[.75rem] px-[1rem] rounded-lg text-[0.875rem] flex-grow", {
19101
+ "min-h-[5.5rem]": traceUsage
19102
+ }),
19103
+ children: [
19104
+ /* @__PURE__ */ jsxRuntime.jsxs(
19105
+ "div",
19106
+ {
19107
+ className: cn(
19108
+ "grid grid-cols-[1.5rem_1fr_auto] gap-[.5rem] items-center",
19109
+ "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
19110
+ ),
19111
+ children: [
19112
+ tokenPresentations?.[key]?.icon,
19113
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem]", children: tokenPresentations?.[key]?.label }),
19114
+ !isObject && /* @__PURE__ */ jsxRuntime.jsx("b", { className: "text-[1rem]", children: value })
19115
+ ]
19116
+ }
19117
+ ),
19118
+ isObject && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(value).map(([detailKey, detailValue]) => {
19119
+ if (typeof detailValue !== "number") return null;
19120
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19121
+ "dl",
19122
+ {
19123
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19124
+ children: [
19125
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: detailKeyLabels[detailKey] || detailKey }),
19126
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: detailValue })
19127
+ ]
19128
+ },
19129
+ detailKey
19130
+ );
19131
+ }) }),
19132
+ !isObject && tokensByProviderValid && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.875rem] mt-[0.5rem] pl-[2rem]", children: Object.entries(tokensByProvider).map(([provider, providerTokens]) => {
19133
+ const tokenValue = providerTokens?.[key];
19134
+ if (typeof tokenValue !== "number") return null;
19135
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19136
+ "dl",
19137
+ {
19138
+ className: "grid grid-cols-[1fr_auto] gap-x-[1rem] gap-y-[.25rem] justify-between text-icon3",
19139
+ children: [
19140
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: provider }),
19141
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: tokenValue })
19142
+ ]
19143
+ },
19144
+ provider
19145
+ );
19146
+ }) })
19147
+ ]
19148
+ },
19149
+ key
19150
+ );
19151
+ }) });
18677
19152
  }
18678
19153
 
18679
19154
  function isTokenLimitExceeded(span) {
@@ -18786,7 +19261,7 @@ function SpanTabs({
18786
19261
  SpanScoring,
18787
19262
  {
18788
19263
  traceId: trace?.traceId,
18789
- isTopLevelSpan: span?.parentSpanId === null,
19264
+ isTopLevelSpan: !Boolean(span?.parentSpanId),
18790
19265
  spanId: span?.spanId,
18791
19266
  entityType,
18792
19267
  scorers,
@@ -19946,14 +20421,6 @@ const MCPToolPanel = ({ toolId, serverId }) => {
19946
20421
  );
19947
20422
  };
19948
20423
 
19949
- const CodeMirrorBlock = (props) => {
19950
- const theme = useCodemirrorTheme$1();
19951
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4 relative", children: [
19952
- /* @__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" }) }),
19953
- /* @__PURE__ */ jsxRuntime.jsx(CodeMirror, { extensions: [langJson.json()], theme, ...props })
19954
- ] });
19955
- };
19956
-
19957
20424
  const MCPDetail = ({ isLoading, server }) => {
19958
20425
  const [{ sseUrl, httpStreamUrl }, setUrls] = React.useState({
19959
20426
  sseUrl: "",
@@ -19975,112 +20442,45 @@ const MCPDetail = ({ isLoading, server }) => {
19975
20442
  if (isLoading) return null;
19976
20443
  if (!server)
19977
20444
  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" }) });
20445
+ const commandLineConfig = `npx -y mcp-remote ${sseUrl}`;
19978
20446
  return /* @__PURE__ */ jsxRuntime.jsxs(MainContentContent, { isDivided: true, children: [
19979
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-8 py-20 mx-auto max-w-[604px] w-full", children: [
20447
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-8 py-12 mx-auto max-w-2xl w-full", children: [
19980
20448
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "h1", variant: "header-md", className: "text-icon6 font-medium pb-4", children: server.name }),
19981
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
19982
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
19983
- /* @__PURE__ */ jsxRuntime.jsx(
19984
- Badge,
19985
- {
19986
- icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "SSE" }),
19987
- className: "!text-icon4",
19988
- children: sseUrl
19989
- }
19990
- ),
19991
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" })
19992
- ] }),
19993
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
19994
- /* @__PURE__ */ jsxRuntime.jsx(
19995
- Badge,
19996
- {
19997
- icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono w-6 text-accent1 text-ui-xs font-medium", children: "HTTP" }),
19998
- className: "!text-icon4",
19999
- children: httpStreamUrl
20000
- }
20001
- ),
20002
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" })
20003
- ] })
20004
- ] }),
20005
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 pt-3 pb-9", children: [
20449
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 pb-6", children: [
20006
20450
  /* @__PURE__ */ jsxRuntime.jsx(Badge, { icon: /* @__PURE__ */ jsxRuntime.jsx(FolderIcon, { className: "text-icon6" }), className: "rounded-r-sm !text-icon4", children: "Version" }),
20007
20451
  /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "rounded-l-sm !text-icon4", children: server.version_detail.version })
20008
20452
  ] }),
20009
- /* @__PURE__ */ jsxRuntime.jsx(McpSetupTabs, { sseUrl, serverName: server.name })
20453
+ /* @__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." }),
20454
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
20455
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20456
+ /* @__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" }),
20457
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for stateless HTTP transport with streamable responses." }),
20458
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20459
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: httpStreamUrl }),
20460
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy HTTP Stream URL", content: httpStreamUrl, iconSize: "sm" }) })
20461
+ ] })
20462
+ ] }),
20463
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20464
+ /* @__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" }),
20465
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for real-time communication via SSE." }),
20466
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20467
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: sseUrl }),
20468
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy SSE URL", content: sseUrl, iconSize: "sm" }) })
20469
+ ] })
20470
+ ] }),
20471
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface3 p-4", children: [
20472
+ /* @__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" }),
20473
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "text-icon3 pt-1 pb-2", children: "Use for local command-line access via npx and mcp-remote." }),
20474
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
20475
+ /* @__PURE__ */ jsxRuntime.jsx(Txt, { className: "px-2 py-1 bg-surface4 rounded-lg", children: commandLineConfig }),
20476
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { tooltip: "Copy Command Line Config", content: commandLineConfig, iconSize: "sm" }) })
20477
+ ] })
20478
+ ] })
20479
+ ] })
20010
20480
  ] }),
20011
20481
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full overflow-y-scroll border-l-sm border-border1", children: /* @__PURE__ */ jsxRuntime.jsx(McpToolList, { server }) })
20012
20482
  ] });
20013
20483
  };
20014
- const McpSetupTabs = ({ sseUrl, serverName }) => {
20015
- const { Link } = useLinkComponent();
20016
- return /* @__PURE__ */ jsxRuntime.jsxs(PlaygroundTabs, { defaultTab: "cursor", children: [
20017
- /* @__PURE__ */ jsxRuntime.jsxs(TabList$1, { children: [
20018
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "cursor", children: "Cursor" }),
20019
- /* @__PURE__ */ jsxRuntime.jsx(Tab$1, { value: "windsurf", children: "Windsurf" })
20020
- ] }),
20021
- /* @__PURE__ */ jsxRuntime.jsxs(TabContent$1, { value: "cursor", children: [
20022
- /* @__PURE__ */ jsxRuntime.jsxs(Txt, { className: "text-icon3 pb-4", children: [
20023
- "Cursor comes with built-in MCP Support.",
20024
- " ",
20025
- /* @__PURE__ */ jsxRuntime.jsx(
20026
- Link,
20027
- {
20028
- href: "https://docs.cursor.com/context/model-context-protocol",
20029
- target: "_blank",
20030
- rel: "noopener noreferrer",
20031
- className: "underline hover:text-icon6",
20032
- children: "Following the documentation"
20033
- }
20034
- ),
20035
- ", you can register an MCP server using SSE with the following configuration."
20036
- ] }),
20037
- /* @__PURE__ */ jsxRuntime.jsx(
20038
- CodeMirrorBlock,
20039
- {
20040
- editable: false,
20041
- value: `{
20042
- "mcpServers": {
20043
- "${serverName}": {
20044
- "url": "${sseUrl}"
20045
- }
20046
- }
20047
- }`
20048
- }
20049
- )
20050
- ] }),
20051
- /* @__PURE__ */ jsxRuntime.jsxs(TabContent$1, { value: "windsurf", children: [
20052
- /* @__PURE__ */ jsxRuntime.jsxs(Txt, { className: "text-icon3 pb-4", children: [
20053
- "Windsurf comes with built-in MCP Support.",
20054
- " ",
20055
- /* @__PURE__ */ jsxRuntime.jsx(
20056
- Link,
20057
- {
20058
- href: "https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json",
20059
- target: "_blank",
20060
- rel: "noopener noreferrer",
20061
- className: "underline hover:text-icon6",
20062
- children: "Following the documentation"
20063
- }
20064
- ),
20065
- ", you can register an MCP server using SSE with the following configuration."
20066
- ] }),
20067
- /* @__PURE__ */ jsxRuntime.jsx(
20068
- CodeMirrorBlock,
20069
- {
20070
- editable: false,
20071
- value: `{
20072
- "mcpServers": {
20073
- "${serverName}": {
20074
- "command": "npx",
20075
- "args": ["-y", "mcp-remote", "${sseUrl}"]
20076
- }
20077
- }
20078
- }`
20079
- }
20080
- )
20081
- ] })
20082
- ] });
20083
- };
20084
20484
  const McpToolList = ({ server }) => {
20085
20485
  const { data: tools = {}, isLoading } = useMCPServerTools(server);
20086
20486
  if (isLoading) return null;
@@ -20522,6 +20922,8 @@ exports.WorkflowRunContext = WorkflowRunContext;
20522
20922
  exports.WorkflowRunDetail = WorkflowRunDetail;
20523
20923
  exports.WorkflowRunList = WorkflowRunList;
20524
20924
  exports.WorkflowRunProvider = WorkflowRunProvider;
20925
+ exports.WorkflowStepDetailContext = WorkflowStepDetailContext;
20926
+ exports.WorkflowStepDetailProvider = WorkflowStepDetailProvider;
20525
20927
  exports.WorkflowTable = WorkflowTable;
20526
20928
  exports.WorkflowTrigger = WorkflowTrigger;
20527
20929
  exports.WorkingMemoryContext = WorkingMemoryContext;
@@ -20584,6 +20986,7 @@ exports.useUpdateModelInModelList = useUpdateModelInModelList;
20584
20986
  exports.useWorkflow = useWorkflow;
20585
20987
  exports.useWorkflowRunExecutionResult = useWorkflowRunExecutionResult;
20586
20988
  exports.useWorkflowRuns = useWorkflowRuns;
20989
+ exports.useWorkflowStepDetail = useWorkflowStepDetail;
20587
20990
  exports.useWorkflows = useWorkflows;
20588
20991
  exports.useWorkingMemory = useWorkingMemory;
20589
20992
  Object.keys(reactQuery).forEach(k => {