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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @mastra/playground-ui
2
2
 
3
+ ## 7.0.0-beta.11
4
+
5
+ ### Patch Changes
6
+
7
+ - Support new Workflow tripwire run status. Tripwires that are thrown from within a workflow will now bubble up and return a graceful state with information about tripwires. ([#10947](https://github.com/mastra-ai/mastra/pull/10947))
8
+
9
+ When a workflow contains an agent step that triggers a tripwire, the workflow returns with `status: 'tripwire'` and includes tripwire details:
10
+
11
+ ```typescript showLineNumbers copy
12
+ const run = await workflow.createRun();
13
+ const result = await run.start({ inputData: { message: 'Hello' } });
14
+
15
+ if (result.status === 'tripwire') {
16
+ console.log('Workflow terminated by tripwire:', result.tripwire?.reason);
17
+ console.log('Processor ID:', result.tripwire?.processorId);
18
+ console.log('Retry requested:', result.tripwire?.retry);
19
+ }
20
+ ```
21
+
22
+ Adds new UI state for tripwire in agent chat and workflow UI.
23
+
24
+ This is distinct from `status: 'failed'` which indicates an unexpected error. A tripwire status means a processor intentionally stopped execution (e.g., for content moderation).
25
+
26
+ - Updated dependencies [[`38380b6`](https://github.com/mastra-ai/mastra/commit/38380b60fca905824bdf6b43df307a58efb1aa15), [`798d0c7`](https://github.com/mastra-ai/mastra/commit/798d0c740232653b1d754870e6b43a55c364ffe2), [`ffe84d5`](https://github.com/mastra-ai/mastra/commit/ffe84d54f3b0f85167fe977efd027dba027eb998), [`2c212e7`](https://github.com/mastra-ai/mastra/commit/2c212e704c90e2db83d4109e62c03f0f6ebd2667), [`4ca4306`](https://github.com/mastra-ai/mastra/commit/4ca430614daa5fa04730205a302a43bf4accfe9f), [`3bf6c5f`](https://github.com/mastra-ai/mastra/commit/3bf6c5f104c25226cd84e0c77f9dec15f2cac2db), [`3bf6c5f`](https://github.com/mastra-ai/mastra/commit/3bf6c5f104c25226cd84e0c77f9dec15f2cac2db)]:
27
+ - @mastra/core@1.0.0-beta.11
28
+ - @mastra/client-js@1.0.0-beta.11
29
+ - @mastra/ai-sdk@1.0.0-beta.8
30
+ - @mastra/react@0.1.0-beta.11
31
+
3
32
  ## 7.0.0-beta.10
4
33
 
5
34
  ### Minor Changes
package/dist/index.cjs.js CHANGED
@@ -3464,6 +3464,55 @@ const defaultComponents = reactMarkdown.unstable_memoizeMarkdownComponents({
3464
3464
  img: ImageWithFallback
3465
3465
  });
3466
3466
 
3467
+ const TripwireNotice = ({ reason, tripwire }) => {
3468
+ const [isExpanded, setIsExpanded] = React.useState(false);
3469
+ const hasMetadata = tripwire && (tripwire.retry !== void 0 || tripwire.tripwirePayload || tripwire.processorId);
3470
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-amber-500/30 bg-amber-950/20 overflow-hidden", children: [
3471
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4", children: [
3472
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "w-5 h-5 text-amber-400 mt-0.5 flex-shrink-0" }),
3473
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
3474
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-200 mb-1", children: "Content Blocked" }),
3475
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-amber-300/90", children: reason })
3476
+ ] })
3477
+ ] }),
3478
+ hasMetadata && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3479
+ /* @__PURE__ */ jsxRuntime.jsxs(
3480
+ "button",
3481
+ {
3482
+ onClick: () => setIsExpanded(!isExpanded),
3483
+ 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",
3484
+ children: [
3485
+ 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" }),
3486
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Details" })
3487
+ ]
3488
+ }
3489
+ ),
3490
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-4 space-y-3 border-t border-amber-500/20 bg-amber-950/10", children: [
3491
+ tripwire.retry !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-3", children: [
3492
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-3.5 h-3.5 text-amber-400/60" }),
3493
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
3494
+ "Retry:",
3495
+ " ",
3496
+ tripwire.retry ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-green-400", children: "Allowed" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-400", children: "Not allowed" })
3497
+ ] })
3498
+ ] }),
3499
+ tripwire.processorId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3500
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-3.5 h-3.5 text-amber-400/60" }),
3501
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
3502
+ "Processor:",
3503
+ " ",
3504
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded bg-amber-900/30 text-amber-200 font-mono", children: tripwire.processorId })
3505
+ ] })
3506
+ ] }),
3507
+ tripwire.tripwirePayload !== void 0 && tripwire.tripwirePayload !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-1", children: [
3508
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-400/60 mb-1.5", children: "Metadata:" }),
3509
+ /* @__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)) })
3510
+ ] })
3511
+ ] })
3512
+ ] })
3513
+ ] });
3514
+ };
3515
+
3467
3516
  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
3517
  /* @__PURE__ */ jsxRuntime.jsx(
3469
3518
  "path",
@@ -4254,6 +4303,9 @@ const ErrorAwareText = () => {
4254
4303
  const part = react.useAssistantState(({ part: part2 }) => part2);
4255
4304
  const text = part.text || "";
4256
4305
  const metadata = part.metadata || {};
4306
+ if (metadata?.status === "tripwire") {
4307
+ return /* @__PURE__ */ jsxRuntime.jsx(TripwireNotice, { reason: text, tripwire: metadata.tripwire });
4308
+ }
4257
4309
  if (metadata?.status === "warning") {
4258
4310
  return /* @__PURE__ */ jsxRuntime.jsxs(Alert$1, { variant: "warning", children: [
4259
4311
  /* @__PURE__ */ jsxRuntime.jsx(AlertTitle$1, { as: "h5", children: "Warning" }),
@@ -4686,6 +4738,7 @@ function convertWorkflowRunStateToStreamResult(runState) {
4686
4738
  Object.entries(context).forEach(([stepId, stepResult]) => {
4687
4739
  if (stepId !== "input" && "status" in stepResult) {
4688
4740
  const result = stepResult;
4741
+ const hasTripwire = result.status === "failed" && result.tripwire !== void 0;
4689
4742
  steps[stepId] = {
4690
4743
  status: result.status,
4691
4744
  output: "output" in result ? result.output : void 0,
@@ -4693,7 +4746,9 @@ function convertWorkflowRunStateToStreamResult(runState) {
4693
4746
  suspendPayload: "suspendPayload" in result ? result.suspendPayload : void 0,
4694
4747
  suspendOutput: "suspendOutput" in result ? result.suspendOutput : void 0,
4695
4748
  resumePayload: "resumePayload" in result ? result.resumePayload : void 0,
4696
- error: "error" in result ? result.error : void 0,
4749
+ // Don't include error when tripwire is present - tripwire takes precedence
4750
+ error: hasTripwire ? void 0 : "error" in result ? result.error : void 0,
4751
+ tripwire: hasTripwire ? result.tripwire : void 0,
4697
4752
  startedAt: "startedAt" in result ? result.startedAt : Date.now(),
4698
4753
  endedAt: "endedAt" in result ? result.endedAt : void 0,
4699
4754
  suspendedAt: "suspendedAt" in result ? result.suspendedAt : void 0,
@@ -4718,7 +4773,15 @@ function convertWorkflowRunStateToStreamResult(runState) {
4718
4773
  status: runState.status,
4719
4774
  ...runState.status === "success" ? { result: runState.result } : {},
4720
4775
  ...runState.status === "failed" ? { error: runState.error } : {},
4721
- ...runState.status === "suspended" ? { suspended: suspendedStepIds, suspendPayload } : {}
4776
+ ...runState.status === "suspended" ? { suspended: suspendedStepIds, suspendPayload } : {},
4777
+ ...runState.status === "tripwire" && runState.tripwire ? {
4778
+ tripwire: {
4779
+ reason: runState.tripwire.reason,
4780
+ retry: runState.tripwire.retry,
4781
+ metadata: runState.tripwire.metadata,
4782
+ processorId: runState.tripwire.processorId
4783
+ }
4784
+ } : {}
4722
4785
  };
4723
4786
  }
4724
4787
 
@@ -6151,10 +6214,13 @@ const useCurrentRun = () => {
6151
6214
  const context = React.useContext(WorkflowRunContext);
6152
6215
  const workflowCurrentSteps = context.result?.steps ?? {};
6153
6216
  const steps = Object.entries(workflowCurrentSteps).reduce((acc, [key, value]) => {
6217
+ const hasTripwire = "tripwire" in value && value.tripwire;
6154
6218
  return {
6155
6219
  ...acc,
6156
6220
  [key]: {
6157
- error: "error" in value ? value.error : void 0,
6221
+ // Don't include error when tripwire is present - tripwire takes precedence
6222
+ error: hasTripwire ? void 0 : "error" in value ? value.error : void 0,
6223
+ tripwire: hasTripwire ? value.tripwire : void 0,
6158
6224
  startedAt: value.startedAt,
6159
6225
  endedAt: "endedAt" in value ? value.endedAt : void 0,
6160
6226
  status: value.status,
@@ -7203,12 +7269,23 @@ function inferFieldType(schema, fieldConfig) {
7203
7269
  if (schema instanceof z.z.ZodDiscriminatedUnion) {
7204
7270
  return "discriminated-union";
7205
7271
  }
7272
+ if (schema instanceof z.z.ZodLiteral) {
7273
+ const v4Values = schema._zod?.def?.values;
7274
+ const v3Value = schema._def?.value;
7275
+ const literalValue = v4Values !== void 0 ? Array.isArray(v4Values) ? v4Values[0] : v4Values : v3Value;
7276
+ if (typeof literalValue === "number") return "number";
7277
+ if (typeof literalValue === "boolean") return "boolean";
7278
+ return "string";
7279
+ }
7206
7280
  return "string";
7207
7281
  }
7208
7282
 
7209
7283
  function getDefaultValueInZodStack(schema) {
7210
7284
  if (schema instanceof z$1.core.$ZodDefault) {
7211
7285
  return schema._zod.def.defaultValue;
7286
+ } else if (schema instanceof z$1.core.$ZodLiteral) {
7287
+ const values = schema._zod.def.values;
7288
+ return Array.isArray(values) ? values[0] : values;
7212
7289
  } else if ("innerType" in schema._zod.def) {
7213
7290
  return getDefaultValueInZodStack(schema._zod.def.innerType);
7214
7291
  } else if ("shape" in schema._zod.def) {
@@ -7825,6 +7902,7 @@ const WorkflowStepActionBar = ({
7825
7902
  resumeData,
7826
7903
  suspendOutput,
7827
7904
  error,
7905
+ tripwire,
7828
7906
  mapConfig,
7829
7907
  stepName,
7830
7908
  stepId,
@@ -7836,19 +7914,21 @@ const WorkflowStepActionBar = ({
7836
7914
  const [isOutputOpen, setIsOutputOpen] = React.useState(false);
7837
7915
  const [isResumeDataOpen, setIsResumeDataOpen] = React.useState(false);
7838
7916
  const [isErrorOpen, setIsErrorOpen] = React.useState(false);
7917
+ const [isTripwireOpen, setIsTripwireOpen] = React.useState(false);
7839
7918
  const [isMapConfigOpen, setIsMapConfigOpen] = React.useState(false);
7840
7919
  const [isTimeTravelOpen, setIsTimeTravelOpen] = React.useState(false);
7841
7920
  const { withoutTimeTravel } = React.useContext(WorkflowRunContext);
7842
7921
  const dialogContentClass = "bg-surface2 rounded-lg border-sm border-border1 max-w-4xl w-full px-0";
7843
7922
  const dialogTitleClass = "border-b-sm border-border1 pb-4 px-6";
7844
7923
  const showTimeTravel = !withoutTimeTravel && stepKey && !mapConfig;
7845
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (input || output || error || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxRuntime.jsxs(
7924
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: (input || output || error || tripwire || mapConfig || resumeData || onShowNestedGraph || showTimeTravel) && /* @__PURE__ */ jsxRuntime.jsxs(
7846
7925
  "div",
7847
7926
  {
7848
7927
  className: cn(
7849
7928
  "flex flex-wrap items-center bg-surface4 border-t-sm border-border1 px-2 py-1 gap-2 rounded-b-lg",
7850
7929
  status === "success" && "bg-accent1Dark",
7851
7930
  status === "failed" && "bg-accent2Dark",
7931
+ status === "tripwire" && "bg-amber-900/40 border-amber-500/20",
7852
7932
  status === "suspended" && "bg-accent3Dark",
7853
7933
  status === "waiting" && "bg-accent5Dark",
7854
7934
  status === "running" && "bg-accent6Dark"
@@ -7917,6 +7997,26 @@ const WorkflowStepActionBar = ({
7917
7997
  ] }),
7918
7998
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(CodeDialogContent, { data: error }) })
7919
7999
  ] }) })
8000
+ ] }),
8001
+ tripwire && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8002
+ /* @__PURE__ */ jsxRuntime.jsx(Button$1, { onClick: () => setIsTripwireOpen(true), className: "text-amber-400 hover:text-amber-300", children: "Tripwire" }),
8003
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isTripwireOpen, onOpenChange: setIsTripwireOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: dialogContentClass, children: [
8004
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: dialogTitleClass, children: [
8005
+ stepName,
8006
+ " tripwire"
8007
+ ] }),
8008
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
8009
+ CodeDialogContent,
8010
+ {
8011
+ data: {
8012
+ reason: tripwire.reason,
8013
+ retry: tripwire.retry,
8014
+ metadata: tripwire.metadata,
8015
+ processorId: tripwire.processorId
8016
+ }
8017
+ }
8018
+ ) })
8019
+ ] }) })
7920
8020
  ] })
7921
8021
  ]
7922
8022
  }
@@ -7932,6 +8032,8 @@ function WorkflowConditionNode({ data }) {
7932
8032
  const { steps } = useCurrentRun();
7933
8033
  const previousStep = steps[previousStepId];
7934
8034
  const nextStep = steps[nextStepId];
8035
+ const isPreviousTripwire = previousStep?.status === "failed" && previousStep?.tripwire !== void 0;
8036
+ const previousDisplayStatus = isPreviousTripwire ? "tripwire" : previousStep?.status;
7935
8037
  const { icon: IconComponent, color } = getConditionIconAndColor(type);
7936
8038
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7937
8039
  !withoutTopHandle && /* @__PURE__ */ jsxRuntime.jsx(react$2.Handle, { type: "target", position: react$2.Position.Top, style: { visibility: "hidden" } }),
@@ -7939,12 +8041,13 @@ function WorkflowConditionNode({ data }) {
7939
8041
  "div",
7940
8042
  {
7941
8043
  "data-workflow-node": true,
7942
- "data-workflow-step-status": previousStep?.status,
8044
+ "data-workflow-step-status": previousDisplayStatus,
7943
8045
  "data-testid": "workflow-condition-node",
7944
8046
  className: cn(
7945
8047
  "bg-surface3 rounded-lg w-[300px] border-sm border-border1",
7946
- previousStep?.status === "success" && nextStep && "bg-accent1Darker",
7947
- previousStep?.status === "failed" && nextStep && "bg-accent2Darker",
8048
+ previousDisplayStatus === "success" && nextStep && "bg-accent1Darker",
8049
+ previousDisplayStatus === "failed" && nextStep && "bg-accent2Darker",
8050
+ previousDisplayStatus === "tripwire" && nextStep && "bg-amber-950/40 border-amber-500/30",
7948
8051
  !previousStep && Boolean(nextStep?.status) && "bg-accent1Darker"
7949
8052
  ),
7950
8053
  children: [
@@ -7998,8 +8101,9 @@ function WorkflowConditionNode({ data }) {
7998
8101
  className: cn(
7999
8102
  "relative font-mono p-3 w-full cursor-pointer rounded-lg text-xs !bg-surface4 overflow-scroll",
8000
8103
  className,
8001
- previousStep?.status === "success" && nextStep && "!bg-accent1Dark",
8002
- previousStep?.status === "failed" && nextStep && "!bg-accent2Dark"
8104
+ previousDisplayStatus === "success" && nextStep && "!bg-accent1Dark",
8105
+ previousDisplayStatus === "failed" && nextStep && "!bg-accent2Dark",
8106
+ previousDisplayStatus === "tripwire" && nextStep && "!bg-amber-900/40"
8003
8107
  ),
8004
8108
  onClick: () => setOpenDialog(true),
8005
8109
  style,
@@ -8055,7 +8159,8 @@ function WorkflowConditionNode({ data }) {
8055
8159
  stepName: nextStepId,
8056
8160
  input: previousStep?.output,
8057
8161
  mapConfig: data.mapConfig,
8058
- status: nextStep ? previousStep?.status : void 0
8162
+ tripwire: isPreviousTripwire ? previousStep?.tripwire : void 0,
8163
+ status: nextStep ? previousDisplayStatus : void 0
8059
8164
  }
8060
8165
  )
8061
8166
  ]
@@ -8101,6 +8206,8 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8101
8206
  } = data;
8102
8207
  const stepKey = parentWorkflowName ? `${parentWorkflowName}.${stepId || label}` : stepId || label;
8103
8208
  const step = steps[stepKey];
8209
+ const isTripwire = step?.status === "failed" && step?.tripwire !== void 0;
8210
+ const displayStatus = isTripwire ? "tripwire" : step?.status;
8104
8211
  const { isSleepNode, isForEachNode, isMapNode, hasSpecialBadge } = getNodeBadgeInfo({
8105
8212
  duration,
8106
8213
  date,
@@ -8115,16 +8222,17 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8115
8222
  "div",
8116
8223
  {
8117
8224
  "data-workflow-node": true,
8118
- "data-workflow-step-status": step?.status ?? "idle",
8225
+ "data-workflow-step-status": displayStatus ?? "idle",
8119
8226
  "data-testid": "workflow-default-node",
8120
8227
  className: cn(
8121
8228
  "bg-surface3 rounded-lg w-[274px] border-sm border-border1",
8122
8229
  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"
8230
+ displayStatus === "success" && "bg-accent1Darker",
8231
+ displayStatus === "failed" && "bg-accent2Darker",
8232
+ displayStatus === "tripwire" && "bg-amber-950/40 border-amber-500/30",
8233
+ displayStatus === "suspended" && "bg-accent3Darker",
8234
+ displayStatus === "waiting" && "bg-accent5Darker",
8235
+ displayStatus === "running" && "bg-accent6Darker"
8128
8236
  ),
8129
8237
  children: [
8130
8238
  hasSpecialBadge && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pt-2 pb-1 flex gap-1.5 flex-wrap", children: [
@@ -8142,11 +8250,12 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8142
8250
  ] }),
8143
8251
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
8144
8252
  /* @__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" }),
8253
+ displayStatus === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8254
+ displayStatus === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8255
+ displayStatus === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8256
+ displayStatus === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8257
+ displayStatus === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8258
+ displayStatus === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8150
8259
  !step && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { className: "text-icon2" })
8151
8260
  ] }),
8152
8261
  /* @__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 +8285,10 @@ function WorkflowDefaultNode({ data, parentWorkflowName }) {
8176
8285
  resumeData: step?.resumeData,
8177
8286
  output: step?.output,
8178
8287
  suspendOutput: step?.suspendOutput,
8179
- error: step?.error,
8288
+ error: isTripwire ? void 0 : step?.error,
8289
+ tripwire: isTripwire ? step?.tripwire : void 0,
8180
8290
  mapConfig,
8181
- status: step?.status,
8291
+ status: displayStatus,
8182
8292
  stepKey
8183
8293
  }
8184
8294
  )
@@ -8430,6 +8540,8 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8430
8540
  const fullLabel = parentWorkflowName ? `${parentWorkflowName}.${label}` : label;
8431
8541
  const stepKey = parentWorkflowName ? `${parentWorkflowName}.${stepId || label}` : stepId || label;
8432
8542
  const step = steps[stepKey];
8543
+ const isTripwire = step?.status === "failed" && step?.tripwire !== void 0;
8544
+ const displayStatus = isTripwire ? "tripwire" : step?.status;
8433
8545
  const { isForEachNode, isMapNode, isNestedWorkflow, hasSpecialBadge } = getNodeBadgeInfo({
8434
8546
  isForEach,
8435
8547
  mapConfig,
@@ -8444,15 +8556,16 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8444
8556
  {
8445
8557
  "data-testid": "workflow-nested-node",
8446
8558
  "data-workflow-node": true,
8447
- "data-workflow-step-status": step?.status,
8559
+ "data-workflow-step-status": displayStatus,
8448
8560
  className: cn(
8449
8561
  "bg-surface3 rounded-lg w-[274px] border-sm border-border1",
8450
8562
  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"
8563
+ displayStatus === "success" && "bg-accent1Darker",
8564
+ displayStatus === "failed" && "bg-accent2Darker",
8565
+ displayStatus === "tripwire" && "bg-amber-950/40 border-amber-500/30",
8566
+ displayStatus === "suspended" && "bg-accent3Darker",
8567
+ displayStatus === "waiting" && "bg-accent5Darker",
8568
+ displayStatus === "running" && "bg-accent6Darker"
8456
8569
  ),
8457
8570
  children: [
8458
8571
  hasSpecialBadge && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pt-2 pb-1 flex gap-1.5 flex-wrap", children: [
@@ -8464,11 +8577,12 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8464
8577
  ] }),
8465
8578
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
8466
8579
  /* @__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" }),
8580
+ displayStatus === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8581
+ displayStatus === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8582
+ displayStatus === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8583
+ displayStatus === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PauseIcon, { className: "text-accent3" }),
8584
+ displayStatus === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8585
+ displayStatus === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" }),
8472
8586
  !step && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { className: "text-icon2" })
8473
8587
  ] }),
8474
8588
  /* @__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 +8602,10 @@ function WorkflowNestedNode({ data, parentWorkflowName }) {
8488
8602
  output: step?.output,
8489
8603
  suspendOutput: step?.suspendOutput,
8490
8604
  error: step?.error,
8605
+ tripwire: isTripwire ? step?.tripwire : void 0,
8491
8606
  mapConfig,
8492
8607
  onShowNestedGraph: () => showNestedGraph({ label, fullStep: fullLabel, stepGraph }),
8493
- status: step?.status,
8608
+ status: displayStatus,
8494
8609
  stepKey
8495
8610
  }
8496
8611
  )
@@ -8596,7 +8711,12 @@ const WorkflowCard = ({ header, children, footer }) => {
8596
8711
  ] });
8597
8712
  };
8598
8713
 
8599
- const WorkflowStatus = ({ stepId, status, result }) => {
8714
+ const WorkflowStatus = ({ stepId, status, result, tripwire }) => {
8715
+ const [isTripwireExpanded, setIsTripwireExpanded] = React.useState(false);
8716
+ const isTripwire = status === "tripwire";
8717
+ const hasTripwireMetadata = Boolean(
8718
+ tripwire && (tripwire.retry !== void 0 || tripwire.metadata !== void 0 || tripwire.processorId !== void 0)
8719
+ );
8600
8720
  return /* @__PURE__ */ jsxRuntime.jsx(
8601
8721
  WorkflowCard,
8602
8722
  {
@@ -8604,19 +8724,74 @@ const WorkflowStatus = ({ stepId, status, result }) => {
8604
8724
  /* @__PURE__ */ jsxRuntime.jsxs(Icon, { children: [
8605
8725
  status === "success" && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-accent1" }),
8606
8726
  status === "failed" && /* @__PURE__ */ jsxRuntime.jsx(CrossIcon, { className: "text-accent2" }),
8727
+ status === "tripwire" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "text-amber-400" }),
8607
8728
  status === "suspended" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CirclePause, { className: "text-accent3" }),
8608
8729
  status === "waiting" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HourglassIcon, { className: "text-accent5" }),
8609
8730
  status === "running" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "text-accent6 animate-spin" })
8610
8731
  ] }),
8611
8732
  /* @__PURE__ */ jsxRuntime.jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: stepId.charAt(0).toUpperCase() + stepId.slice(1) })
8612
8733
  ] }),
8613
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
8734
+ children: isTripwire && tripwire ? /* @__PURE__ */ jsxRuntime.jsx(
8735
+ TripwireDetails,
8736
+ {
8737
+ tripwire,
8738
+ isExpanded: isTripwireExpanded,
8739
+ onToggleExpand: () => setIsTripwireExpanded(!isTripwireExpanded),
8740
+ hasMetadata: hasTripwireMetadata
8741
+ }
8742
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
8614
8743
  /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: JSON.stringify(result, null, 2), className: "absolute top-2 right-2 z-10" }),
8615
8744
  /* @__PURE__ */ jsxRuntime.jsx(SyntaxHighlighter$1, { data: result })
8616
8745
  ] })
8617
8746
  }
8618
8747
  );
8619
8748
  };
8749
+ const TripwireDetails = ({ tripwire, isExpanded, onToggleExpand, hasMetadata }) => {
8750
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-amber-500/30 bg-amber-950/20 overflow-hidden", children: [
8751
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-4", children: [
8752
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldAlert, { className: "w-5 h-5 text-amber-400 mt-0.5 flex-shrink-0" }),
8753
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
8754
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-200 mb-1", children: "Content Blocked" }),
8755
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-amber-300/90", children: tripwire.reason || "Tripwire triggered" })
8756
+ ] })
8757
+ ] }),
8758
+ hasMetadata && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8759
+ /* @__PURE__ */ jsxRuntime.jsxs(
8760
+ "button",
8761
+ {
8762
+ onClick: onToggleExpand,
8763
+ 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",
8764
+ children: [
8765
+ 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" }),
8766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Details" })
8767
+ ]
8768
+ }
8769
+ ),
8770
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-4 space-y-3 border-t border-amber-500/20 bg-amber-950/10", children: [
8771
+ tripwire.retry !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-3", children: [
8772
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-3.5 h-3.5 text-amber-400/60" }),
8773
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
8774
+ "Retry:",
8775
+ " ",
8776
+ tripwire.retry ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-green-400", children: "Allowed" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-400", children: "Not allowed" })
8777
+ ] })
8778
+ ] }),
8779
+ tripwire.processorId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
8780
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { className: "w-3.5 h-3.5 text-amber-400/60" }),
8781
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-amber-300/70", children: [
8782
+ "Processor:",
8783
+ " ",
8784
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded bg-amber-900/30 text-amber-200 font-mono", children: tripwire.processorId })
8785
+ ] })
8786
+ ] }),
8787
+ tripwire.metadata !== void 0 && tripwire.metadata !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-1", children: [
8788
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-400/60 mb-1.5", children: "Metadata:" }),
8789
+ /* @__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)) })
8790
+ ] })
8791
+ ] })
8792
+ ] })
8793
+ ] });
8794
+ };
8620
8795
 
8621
8796
  const isObjectEmpty = (objectName) => {
8622
8797
  return objectName && Object.keys(objectName).length === 0 && objectName.constructor === Object;
@@ -8709,7 +8884,7 @@ function WorkflowTrigger({
8709
8884
  const zodInputSchema = triggerSchema ? resolveSerializedZodOutput(jsonToZod.jsonSchemaToZod(superjson.parse(triggerSchema))) : null;
8710
8885
  const workflowActivePaths = streamResultToUse?.steps ?? {};
8711
8886
  const hasWorkflowActivePaths = Object.values(workflowActivePaths).length > 0;
8712
- const doneStatuses = ["success", "failed", "canceled"];
8887
+ const doneStatuses = ["success", "failed", "canceled", "tripwire"];
8713
8888
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full pt-3 pb-12 overflow-y-auto", children: [
8714
8889
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 px-5 pb-5 border-b-sm border-border1", children: [
8715
8890
  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: [
@@ -8799,12 +8974,20 @@ function WorkflowTrigger({
8799
8974
  if (step.status === "success") {
8800
8975
  output = step.output;
8801
8976
  }
8977
+ const tripwireInfo = step.status === "failed" && step.tripwire ? step.tripwire : streamResultToUse?.status === "tripwire" ? {
8978
+ reason: streamResultToUse?.tripwire?.reason,
8979
+ retry: streamResultToUse?.tripwire?.retry,
8980
+ metadata: streamResultToUse?.tripwire?.metadata,
8981
+ processorId: streamResultToUse?.tripwire?.processorId
8982
+ } : void 0;
8983
+ const displayStatus = step.status === "failed" && step.tripwire ? "tripwire" : status;
8802
8984
  return /* @__PURE__ */ jsxRuntime.jsx(
8803
8985
  WorkflowStatus,
8804
8986
  {
8805
8987
  stepId,
8806
- status,
8807
- result: output ?? suspendOutput ?? {}
8988
+ status: displayStatus,
8989
+ result: output ?? suspendOutput ?? {},
8990
+ tripwire: tripwireInfo
8808
8991
  },
8809
8992
  stepId
8810
8993
  );
@@ -9153,10 +9336,14 @@ const columns$4 = [
9153
9336
  header: "Name",
9154
9337
  cell: ({ row }) => {
9155
9338
  const { Link, paths } = useLinkComponent();
9339
+ const workflow = row.original;
9156
9340
  return /* @__PURE__ */ jsxRuntime.jsx(
9157
9341
  EntryCell,
9158
9342
  {
9159
- name: /* @__PURE__ */ jsxRuntime.jsx(Link, { href: paths.workflowLink(row.original.id), children: row.original.name }),
9343
+ name: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
9344
+ /* @__PURE__ */ jsxRuntime.jsx(Link, { href: paths.workflowLink(row.original.id), children: row.original.name }),
9345
+ 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" })
9346
+ ] }),
9160
9347
  description: void 0,
9161
9348
  meta: void 0
9162
9349
  }
@@ -9380,7 +9567,7 @@ const Tab$1 = ({ children, value, onClick }) => {
9380
9567
  );
9381
9568
  };
9382
9569
  const TabContent$1 = ({ children, value }) => {
9383
- return /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value, className: "h-full overflow-hidden flex flex-col", children });
9570
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value, className: "h-full overflow-auto flex flex-col", children });
9384
9571
  };
9385
9572
 
9386
9573
  const TracingRunOptions = () => {
@@ -9459,7 +9646,8 @@ function WorkflowInformation({ workflowId, initialRunId }) {
9459
9646
  stepsCount,
9460
9647
  " step",
9461
9648
  stepsCount > 1 ? "s" : ""
9462
- ] })
9649
+ ] }),
9650
+ 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
9651
  ] }) }),
9464
9652
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden border-t-sm border-border1 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs(PlaygroundTabs, { defaultTab: "current-run", value: tab, onValueChange: setTab, children: [
9465
9653
  /* @__PURE__ */ jsxRuntime.jsxs(TabList$1, { children: [