import { ApprovalGate } from "smithers-orchestrator";
type ApprovalGateProps = {
id: string;
output: OutputTarget; // z.ZodObject<z.ZodRawShape> | { $inferSelect: Record<string, unknown> } | string
request: { title: string; summary?: string; metadata?: Record<string, unknown> };
when: boolean; // true => require human; false => auto-approve immediately
onDeny?: "fail" | "continue" | "skip"; // if omitted, denial fails the task
skipIf?: boolean;
timeoutMs?: number;
heartbeatTimeoutMs?: number;
heartbeatTimeout?: number;
retries?: number;
retryPolicy?: { backoff?: "fixed" | "linear" | "exponential"; initialDelayMs?: number };
continueOnFail?: boolean;
};
const risk = ctx.output(outputs.riskScore, { nodeId: "risk" });
<Workflow name="deploy-pipeline">
<Sequence>
<Task id="risk" output={outputs.riskScore} agent={riskAgent}>
Assess deploy risk.
</Task>
<ApprovalGate
id="deploy-approval"
output={outputs.deployDecision}
when={risk.level === "high"}
request={{
title: "Approve high-risk deploy?",
summary: `Risk score: ${risk.score}/100`,
}}
onDeny="fail"
/>
<Task id="deploy" output={outputs.deploy}>
{{ deployed: true }}
</Task>
</Sequence>
</Workflow>
Notes
- Auto-approve emits a valid
ApprovalDecision({ approved: true, note: "auto-approved", ... }); downstream branching stays uniform. onDenyapplies only to the human path; auto-approve always succeeds.
Source
The<ApprovalGate> implementation and the files it imports, straight from the package source. This section is generated; edit the source, not this block.
// @smithers-type-exports-begin
/** @typedef {import("./ApprovalGateProps.ts").ApprovalGateProps} ApprovalGateProps */
// @smithers-type-exports-end
import React from "react";
import { Branch } from "./Branch.js";
import { Approval } from "./Approval.js";
import { Task } from "./Task.js";
/**
* Conditional approval gate. Requires human approval only when `when` is true;
* otherwise auto-approves with a static `{ approved: true }` decision.
*
* Composes Branch + Approval + Task internally.
* @param {ApprovalGateProps} props
*/
export function ApprovalGate(props) {
if (props.skipIf)
return null;
return React.createElement(Branch, {
if: props.when,
then: React.createElement(Approval, {
id: props.id,
output: props.output,
request: props.request,
onDeny: props.onDeny,
timeoutMs: props.timeoutMs,
heartbeatTimeoutMs: props.heartbeatTimeoutMs,
heartbeatTimeout: props.heartbeatTimeout,
retries: props.retries,
retryPolicy: props.retryPolicy,
continueOnFail: props.continueOnFail,
}),
else: React.createElement(Task, {
id: props.id,
output: props.output,
label: `${props.request.title} (auto-approved)`,
children: {
approved: true,
note: "auto-approved",
decidedBy: null,
decidedAt: null,
},
}),
});
}