Skip to navigation

gates

View as MarkdownOpen in Claude

functions[].gates attaches semantic gates to a SWAIG function. A semantic gate is a yes/no question about the call that must come out yes before the function runs. When the AI calls the function, a decision model reads the conversation and answers each of the function’s questions first. If every gate passes, the function runs as usual. If any gate fails, the function doesn’t run, and the AI gets the response you wrote for that gate in on_fail instead.

For when to use gates and how to write good questions, see the semantic gates guide.

Properties

functions[].gates
object[]

An array of 1 to 8 gates. Every gate is checked at once, and all must pass. When more than one fails, the first failing gate in the array supplies the on_fail response. A gated function needs a description (or the deprecated purpose) and a web_hook_url or a data_map. The web_hook_url is the function’s own or comes from SWAIG.defaults; a function returned by includes takes it from the defaults the include returns instead.

Inside a gate, a key not listed below is an error, not an ignored setting. Gate keys are matched exactly, case included, so Question is an unknown key. The function’s own gates and gate_fillers keys are matched without regard to case, like every function property.

gates[].question
stringRequired

The yes/no question, at most 8 KB. Name what it’s about with the names of the inputs the decision model reads, in backticks: `conversation`, `semantic_state`, `proposed_function`, or `visual_input` (see What a gate reads). ${...} variables from global_data are expanded when the check runs, written as ${global_data.key} or as the bare top-level key, ${key}; @{...} functions are not run.

gates[].threshold
numberRequired

The gate passes when the probability that the answer is yes is at or above this value. Above 0 and at most 1. Higher is stricter; use 0.9 or above for actions that are hard to undo.

gates[].on_fail
objectRequired

What the AI gets instead of the function’s result when this is the first gate that fails. Shaped like a data_map output, at most 8 KB as compact JSON, keys and quotes included.

on_fail.response
string | objectRequired

What the function returns to the AI. A non-empty string, or an object with tool_result (required, non-empty), what the AI sees as the function’s result, and tool_prompt (optional), an instruction placed right after it. Write it so the AI knows the action didn’t happen. Realtime (speech-to-speech) agents don’t use tool_prompt; on those, put everything the AI needs in tool_result.

on_fail.action
object[]

Actions to run, as a function’s response would. Must be an array, even for one action. The actions run as written: ${...} variables in them are not expanded, though a SWML action resolves the variables in its own document when it runs.

on_fail.post_process
booleanDefaults to false

Lets the AI take its turn before the actions run.

gates[].id
stringDefaults to gate_1, gate_2, … by position

A name for the gate, reported in the call records: 1 to 64 letters, digits, or underscores, unique within the function. Default ids count too, so an id of gate_2 clashes with a second gate that has no id.

gates[].criteria
object

What counts as yes and what counts as no, for the near misses the question alone leaves open. Set true, false, or both, each a non-empty string of at most 2 KB.

gates[].visual_input
boolean | integer

How many of the caller’s newest video frames the gate looks at: true is 1, a whole number from 0 to 5, and false or 0 is none. Frames are taken when the check starts, at most one per second and none older than 8 seconds. A function’s gates are checked together, so each sees as many frames as the gate that asks for the most. If the call has no video frame to show, the gate fails without being asked, so a gate with visual_input always fails when the post-prompt AI calls the function after the call.

Sizes are bytes of UTF-8 text. If any gate breaks a rule on this page, or the gated function lacks a description or a web_hook_url or data_map, the function isn’t added to the agent at all, and the rest of the agent works without it, even with semantic_gates_enabled set to false. A calling.error event with error_reason invalid_semantic_gate names the function and the reason. For the rest of that ai method, no other definition of that name and no MCP tool with that name is used either, so the function can never run without its gates.

When a function name is defined more than once, the first definition wins, gates included. Functions from includes load before SWAIG.functions, so an included definition of a name wins over an inline one.

An ungated earlier definition removes the gates

If the first definition of a name has no gates, a later gated definition of that name is dropped, and the function runs without being checked. No calling.error event fires. Define each gated function once, and when an include returns it, put the gates in the include’s definition.

What a gate reads

The decision model reads these inputs, under these names, and nothing else:

NameWhat it holds
conversationThe most recent part of the call, oldest first: semantic_gate_history entries, 20 by default. It holds the caller’s turns, the agent’s replies, and what the agent was told to say outside its replies, such as say actions and fillers. An agent reply the caller cut off is included without its text.
semantic_stateWhatever you’ve stored in global_data.semantic_state, or {}. The key is matched exactly, so Semantic_State isn’t read.
proposed_functionThe function’s name, its description, and the arguments the AI is calling it with.
visual_inputThe caller’s video frames, when a gate sets visual_input.

Other global_data values reach the decision model only when a question names them as ${...} variables. The backticked names in a question aren’t variables, and nothing replaces them. They tell the decision model which input to read, so that “in conversation” means the conversation it was given, not the ordinary word. What a gate reads is captured when the check starts: something the caller says while it runs doesn’t change the result.

When a function is blocked

A blocked function doesn’t run: your webhook isn’t called, the data_map doesn’t run, and nothing is sent to an MCP server. The function’s wait_file doesn’t play, and the call doesn’t use up its active count.

When the check can’t be completed, because it timed out, the decision model failed or gave no usable answer, or the AI’s arguments weren’t exactly one JSON object (missing, not valid JSON, text after the object, a repeated key, or a \u0000 escape), the function is blocked too, and the AI gets There is a temporary problem and this could not be completed right now. Every outcome other than a pass, a fail, or gates turned off also fires a calling.error event:

{
"error": "ai: Semantic gate error\n",
"function": "cancel_account",
"error_reason": "timeout",
"evaluation_id": "d7b5c0f2-6a1e-4c8b-9f3d-2b7e1a0c5d44",
"fatal": false
}

error_reason is the check’s outcome, and evaluation_id matches the record in the call’s swaig_log. The post-prompt callback reference lists every outcome and phase value that record can carry.

Each checked call adds a semantic_gates record to its swaig_log entry, and the post-prompt callback adds semantic_gates_blocked and a semantic_gates tally for the call. When the post-prompt AI was blocked and wrote no summary, post_prompt_data reads “<function> was not run.” for each blocked call.

Where gates apply

Gates work on webhook functions, data_map functions, and functions returned by includes. A function you also serve from an MCP server keeps its gates. Functions the post-prompt AI calls after the call ends are gated too.

These names can’t have gates: startup_hook, hangup_hook, check_for_input, end_call, hangup, check_time, wait_for_user, wait_seconds, adjust_response_latency, next_step, change_context, gather_submit, get_visual_input, get_ideal_strategy, and pause_conversation. Built-in functions and MCP tools you haven’t defined yourself are never gated. The amazon_bedrock and ai_sidecar methods don’t check gates.

Examples

Require an explicit request

version: 1.0.0
sections:
main:
- ai:
prompt:
text: You help callers manage their account.
SWAIG:
functions:
- function: cancel_account
description: Cancel the caller's account.
web_hook_url: https://example.com/swaig
parameters:
type: object
properties:
reason:
type: string
description: Why the caller is cancelling.
gate_fillers:
default:
- Let me check that.
gates:
- id: explicit_request
question: Has the caller explicitly asked to cancel their account in `conversation`?
criteria:
"true": The caller says they want to cancel.
"false": The caller asked about cancelling, or said something else.
threshold: 0.95
on_fail:
response:
tool_result: cancel_account was not run.
tool_prompt: Ask the caller to confirm that they want to cancel.

Check a recorded fact and the caller’s video

A gate can ask about what your application stored in global_data.semantic_state, and another can look at the caller’s camera.

gates:
- id: identity_verified
question: Does `semantic_state` show the caller's identity as verified?
threshold: 0.9
on_fail:
response: release_records was not run. Verify the caller's identity first.
- id: id_shown
question: Is the caller holding a photo ID up to the camera in `visual_input`?
threshold: 0.9
visual_input: 1
on_fail:
response: release_records was not run. Ask the caller to hold their ID up to the camera.