Skip to main content

createToolApprovalGate

workflow.createToolApprovalGate() Create a tool to approve the gate. Workflow declares the invokable tool in tools of specific entrypoint,Conversation continues to declare it in tools of executor, and then uses gate to check the running policy before actually calling the tool.

The tool has three results: if it is not registered, the input verification will fail; if it is disabled, the call will be rejected; if it is enabled but not automatically approved, the waiting/recovery protocol of the user input node will be reused to generate an approval request.

Signature

workflow.createToolApprovalGate(): WorkflowToolApprovalGate
interface WorkflowToolApprovalGate {
approve(
input: WorkflowToolApprovalRequestInput,
context: NodeContext,
): Promise<WorkflowToolApprovalDecision>;

wrap<Args extends unknown[], Result>(
name: string,
fn: (...args: Args) => Promise<Result> | Result,
options?: {
label?: string;
description?: string;
reason?: string;
arguments?: (...args: Args) => unknown;
},
): (context: NodeContext, ...args: Args) => Promise<Result>;
}

Tools Registration

The selected Workflow entrypoint or Conversation executor declares the tool default policy through tools. The runtime only accepts the override policy of the execution configuration declared tool, and the unknown tool is ignored.

export const executor = workflow.defineExecutor<Input, OutputPayload>({
projectType: "workflow",
defaultEntrypoint: "main",
entrypoints: [
workflow.defineEntrypoint<Input, OutputPayload>({
id: "main",
title: "Full workflow",
workflow: toolWorkflow,
tools: [
{
name: "search",
label: "Search",
description: "Search external sources.",
enabled: true,
autoApprove: false,
},
],
createInput({ args }) {
return { query: args.join(" ") };
},
}),
],
});
FieldTypeDescription
namestringStable tool name. Required. Empty strings are ignored.
labelstringShow name.
descriptionstringDescription of the purpose of the tool.
enabledbooleanWhether it is enabled by default. true when not passed.
autoApprovebooleanAutomatically approve by default. false when not passed.

approve

approve(input, context) only performs approval checks and does not call business functions. { approved: true } is returned when approval is passed; tool_permission_denied is thrown when user rejects.

Input fieldTypeDescription
namestringTool name, must match the tools declaration of the current entrypoint or Conversation executor.
labelstringThe name of this approval is displayed; if it is not passed, use the tool declaration.
descriptionstringThis approval description; use tool declaration if not passed.
reasonstringCall reason.
argumentsunknownThe parameter snapshot of this call is written to the approval request metadata.

wrap

wrap(name, fn, options) returns a new function. When calling a new function, the first argument must be NodeContext, and gate will approve it before passing the remaining arguments to the original function.

const approval = workflow.createToolApprovalGate();

const searchWithApproval = approval.wrap(
"search",
async (query: string) => {
return fetchSearchResult(query);
},
{
label: "Search",
reason: "External research is needed before answering.",
arguments: (query) => ({ query }),
},
);

const result = await searchWithApproval(context, input.query);

Running behavior

StatusBehavior
Tool not registeredThrows WorkflowError of type input_validation.
Tool is disabledThrows WorkflowError of type tool_permission_denied.
autoApprove: trueDirectly return { approved: true }, does not generate wait request.
Requires approvalThe tool-approval request is created and the running status becomes waiting_for_input.
User ApprovalRestore the same runId, return { approved: true }, and continue calling the tool.
User RejectedThrow tool_permission_denied.

Approval requests use workflow.createUserInputNode() the same set of recovery agreements. The request ID contains workflow, runId, and tool name by default, and params contains a boolean field approved.

Desktop and public Embed render tool-approval as a dedicated decision interface, directly showing tool ID and arguments parameter snapshots, and providing "approve and continue" and "reject and end" actions. The interface does not display generic Boolean switches, nor does it implicitly approve tool invocations through Enter.

In Conversation mode, the enablement of the tool is saved with the auto-approval policy by dialog. When you switch back to a conversation, the Tools Permissions panel restores the last state of the conversation, and subsequent runs and approval restores also use the policy snapshot of the conversation. Conversations that are new or do not have a standalone policy use the executor tools default value directly and do not inherit overridden values from project-level or other conversations. Plain Workflow Run still uses project-level tool policies.

CLI Recovery

Local CLI does not pop up interactive approvals. The first run outputs a waiting_for_input report, followed by a recovery using the same runId and --resolved-user-inputs-json:

workflow-code json . -- --message "run tool"
workflow-code json . \
--run-id <run-id> \
--resolved-user-inputs-json '[{"requestId":"<request-id>","nodeName":"tool-approval","values":{"approved":true},"submittedAt":"2026-07-08T00:00:00.000Z"}]' \
-- --message "run tool"

Desktop and server runner also pass in the tool policy snapshot for this run through --tool-permissions-json. Normal manual CLI debugging usually does not require this parameter to be passed directly, unless you want to simulate the enable or automatic approval policies passed in by the host.

Error

SituationError TypeDescription
Tool name is emptyinput_validationname must be a non-empty string.
Tool not registered at executor.toolsinput_validationOnly declared tools can be approved.
Tool disabled by policytool_permission_deniedThe current run does not allow the tool to be called.
User Rejected Approvaltool_permission_deniedOn recovery values.approved !== true.
No user input runtime and approval requireduser_input_requiredThe host does not provide an input handler that pauses resume.