Skip to main content
Control Components A Control is a protection rule that evaluates agent interactions (inputs/outputs) and takes action based on configured criteria. It defines when to check, what to check, how to evaluate it, and what to do with the results. Control formula: Control = Scope (When) + Condition (What + How) + Action (Decision)

1. Scope (When to Check)

The Scope defines which steps trigger the control—acting as a filter to select specific sections of your agent workflow to monitor. Fields:
  • step_types: List of step types (['tool', 'llm']). If null, applies to all types.
  • step_names: List of exact step names to target (e.g., ['search_db', 'send_email'])
  • step_name_regex: Regex pattern for step name matching (e.g., "^db.*" matches all “db_” prefixed steps)
  • stages: When to evaluate - ['pre', 'post']
    • 'pre': Check before execution (block bad inputs, prevent prompt injection)
    • 'post': Check after execution (filter bad outputs, redact PII)

Example 1: Apply to all tool steps before execution

{
  "scope": {
    "step_types": ["tool"],
    "stages": ["pre"]
  }
}

Example 2: Target specific database operations

{
  "scope": {
    "step_names": ["query_database", "execute_sql", "db_lookup"],
    "stages": ["pre"]
  }
}

Example 3: Use regex to match multiple steps

{
  "scope": {
    "step_name_regex": "^db_.*",  // Matches all steps starting with "db_"
    "stages": ["pre", "post"]
  }
}

Example 4: Full scope configuration

{
  "scope": {
    "step_types": ["tool", "llm"],
    "step_names": ["search_db", "query_api"],
    "step_name_regex": "^db_.*",
    "stages": ["pre", "post"]
  }
}

2. Condition (What and How to Check)

The Condition is a recursive boolean tree. Leaf conditions pair a selector with an evaluator, and composite conditions can combine child conditions with and, or, and not.

Example 1: Leaf condition that checks tool output for PII

{
  "condition": {
    "selector": {
      "path": "output"
    },
    "evaluator": {
      "name": "regex",
      "config": {
        "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
      }
    }
  }
}

Example 2: Composite condition with and and not

{
  "condition": {
    "and": [
      {
        "selector": {
          "path": "context.risk_level"
        },
        "evaluator": {
          "name": "list",
          "config": {
            "values": ["high", "critical"]
          }
        }
      },
      {
        "not": {
          "selector": {
            "path": "context.user_role"
          },
          "evaluator": {
            "name": "list",
            "config": {
              "values": ["admin", "security"]
            }
          }
        }
      }
    ]
  }
}

2.1 Selector (What to Check Inside a Leaf)

Inside a leaf condition, the Selector specifies which portion of the step’s data to extract and pass to the evaluator for analysis. It uses a path specification to navigate the step object. Field:
  • path: Dot-notation path to the data you want to evaluate
Common Paths:
  • "input" - Entire input to the step
  • "output" - Step’s output/result
  • "input.query" - Specific parameter within input
  • "input.user_message" - User message field
  • "name" - The step/tool name itself
  • "context.user_id" - Context metadata
  • "*" - All available payload data

Example 1: Check tool output for PII

{
  "selector": {
    "path": "output"
  }
}

Example 2: Validate specific input parameter

{
  "selector": {
    "path": "input.sql_query"
  }
}

Example 3: Check user message in LLM input

{
  "selector": {
    "path": "input.user_message"
  }
}

Example 4: Access context metadata

{
  "selector": {
    "path": "context.user_id"
  }
}

2.2 Evaluator (How to Check Inside a Leaf)

Inside a leaf condition, the Evaluator receives the data extracted by the selector and evaluates it against configured rules, returning whether the data matches specified criteria. Components:
  • config: Evaluator-specific configuration, validated against the evaluator’s schema
  • metadata: Optional evaluator identification

Example 1: Regex evaluator to detect PII

{
  "evaluator": {
    "name": "regex",
    "config": {
      "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"  // Social Security Number pattern
    }
  }
}

Example 2: List evaluator for banned terms

{
  "evaluator": {
    "name": "list",
    "config": {
      "values": ["DROP TABLE", "DELETE FROM", "TRUNCATE"],
      "case_sensitive": false
    }
  }
}

Example 3: AI-powered toxicity detection with Luna-2

To use this evaluator, install the package:
pip install agent-control-evaluators[galileo]
{
  "evaluator": {
    "name": "galileo.luna2",
    "config": {
      "metric": "input_toxicity",
      "operator": "gt",
      "target_value": 0.5
    }
  }
}

Example 4: Complex regex for multiple PII types

{
  "evaluator": {
    "name": "regex",
    "config": {
      "pattern": "(?:\\b\\d{3}-\\d{2}-\\d{4}\\b|\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})"
    }
  }
}
Custom Evaluators: Agent Control supports custom evaluators for domain-specific requirements. See examples/DeepEval for a complete example of creating and integrating custom evaluators.

3. Action (What to Do)

The Action defines what happens when the evaluator matches/detects an issue. Fields:
  • decision: The enforcement action to take
    • "allow" - Continue execution (useful for allowlist controls)
    • "deny" - Hard stop execution (blocks the request)
    • "steer" - Provides corrective guidance to help agents satisfy control requirement
    • "warn" - Log a warning but continue execution
    • "log" - Log the match for observability only
  • metadata: Optional additional context (JSON object)

Important: “Deny Wins” Semantics

Agent Control uses “deny wins” logic: if any enabled control with a deny action matches, the request is blocked regardless of other control results. This ensures fail-safe behavior.

Example 1: Block on match

{
  "action": {
    "decision": "deny"
  }
}

Example 2: Warn without blocking

{
  "action": {
    "decision": "warn"
  }
}

Example 3: Action with metadata

{
  "action": {
    "decision": "deny",
    "metadata": {
      "reason": "PII detected in output",
      "severity": "high",
      "compliance": "GDPR"
    }
  }
}

Example 4: Action with steer and steering context

{
  "action": {
    "decision": "steer",
    "steering_context": {
      "message": "Remove PII and rephrase the response without account numbers or SSNs.",
      "required_actions": [
        "redact_pii",
        "generalize_account_details"
      ]
    },
    "metadata": {
      "reason": "PII detected in output",
      "severity": "medium",
      "compliance": "GDPR"
    }
  }
}

Complete Control Example

Putting it all together - a control that blocks Social Security Numbers in tool outputs:
{
  "name": "block-ssn-output",
  "description": "Prevent SSN leakage in tool responses",
  "enabled": true,
  "scope": {
    "step_types": ["tool"],
    "stages": ["post"]
  },
  "condition": {
    "selector": {
      "path": "output"
    },
    "evaluator": {
      "name": "regex",
      "config": {
        "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
      }
    }
  },
  "action": {
    "decision": "deny",
    "metadata": {
      "reason": "SSN detected",
      "compliance": "PII protection"
    }
  }
}

Defining Controls

You can create and configure controls via the SDK, API, or UI.

Example: Block PII in Output (Regex)

Via Python SDK:
from agent_control import AgentControlClient, controls

async with AgentControlClient() as client:
    await controls.create_control(
        client,
        name="block-ssn-output",
        data={
            "description": "Block Social Security Numbers in responses",
            "enabled": True,
            "execution": "server",
            "scope": {"step_names": ["generate_response"], "stages": ["post"]},
            "condition": {
                "selector": {"path": "output"},
                "evaluator": {
                    "name": "regex",
                    "config": {"pattern": r"\b\d{3}-\d{2}-\d{4}\b"}
                },
            },
            "action": {"decision": "deny"}
        }
    )
Via curl:

# Step 1: Create control

CONTROL_ID=$(curl -X PUT http://localhost:8000/api/v1/controls \
  -H "Content-Type: application/json" \
  -d '{"name": "block-ssn-output"}' | jq -r '.control_id')

# Step 2: Set control configuration

curl -X PUT "http://localhost:8000/api/v1/controls/$CONTROL_ID/data" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "description": "Block Social Security Numbers in responses",
      "enabled": true,
      "execution": "server",
      "scope": {"step_names": ["generate_response"], "stages": ["post"]},
      "condition": {
        "selector": {"path": "output"},
        "evaluator": {
          "name": "regex",
          "config": {"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"}
        }
      },
      "action": {"decision": "deny"}
    }
  }'
Regex pattern note: the pattern itself is \b\d{3}-\d{2}-\d{4}\b. Python raw strings render that as r"\b\d{3}-\d{2}-\d{4}\b", while JSON payloads must escape backslashes as "\\b\\d{3}-\\d{2}-\\d{4}\\b".

Example: Block Toxic Input (Luna-2 AI)

To use this evaluator, install the package and restart the server.
pip install agent-control-evaluators[galileo]
Via Python SDK:
await controls.create_control(
    client,
    name="block-toxic-input",
    data={
        "description": "Block toxic or harmful user messages",
        "enabled": True,
        "execution": "server",
        "scope": {"step_names": ["process_user_message"], "step_types": ["llm"], "stages": ["pre"]},
        "condition": {
            "selector": {"path": "input"},
            "evaluator": {
                "name": "galileo.luna2",
                "config": {
                    "metric": "input_toxicity",
                    "operator": "gt",
                    "target_value": 0.5
                }
            }
        },
        "action": {"decision": "deny"}
    }
)
Via curl:

# Create control with Luna-2 evaluator

CONTROL_ID=$(curl -X PUT http://localhost:8000/api/v1/controls \
  -H "Content-Type: application/json" \
  -d '{"name": "block-toxic-input"}' | jq -r '.control_id')

curl -X PUT "http://localhost:8000/api/v1/controls/$CONTROL_ID/data" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "description": "Block toxic or harmful user messages",
      "enabled": true,
      "execution": "server",
      "scope": {"step_names": ["process_user_message"], "step_types": ["llm"], "stages": ["pre"]},
      "condition": {
        "selector": {"path": "input"},
        "evaluator": {
          "name": "galileo.luna2",
          "config": {
            "metric": "input_toxicity",
            "operator": "gt",
            "target_value": 0.5
          }
        }
      },
      "action": {"decision": "deny"}
    }
  }'
Note: For the Luna-2 evaluator, set the GALILEO_API_KEY environment variable. See the Evaluators for all available evaluators.