Skip to content

agentix.guards

guards

The guard subsystem — agentix's security checkpoints.

Guards are opt-in: an Agent with no guards runs a clean loop. Pass guards=secure_defaults() (or your own list) to turn on the protections.

Decision dataclass

Decision(type: DecisionType, reason: str = '')

A guard's verdict on a pending tool call.

Guard

Base guard. Subclass and override the hooks you need; defaults are no-ops (allow / pass-through), so a guard only implements what it cares about.

Three checkpoints, covering both boundaries: * before_call — a pending tool call (ingress to a tool). * after_output — a tool's result re-entering context (egress from a tool). * on_answer — the model's final answer leaving for the user (egress to the user). Use it for redaction / DLP on what the user sees.

GuardContext dataclass

GuardContext(policy: AgentPolicy)

Read-only context handed to every guard for a given call.

GuardPipeline

GuardPipeline(guards: Sequence[Guard] = ())

Runs an ordered list of guards as a single checkpoint.

CallbackGuard

CallbackGuard(check: PermissionCheck)

Bases: Guard

Decide each tool call with a user-supplied callback (can_use_tool).

The callback receives the :class:ToolCall and :class:GuardContext and returns a :class:Decision (Decision.allow() / .deny(reason) / .confirm(reason)) or a plain bool. Sync or async::

async def can_use(call, ctx):
    if call.name == "refund" and call.args["amount"] > 1000:
        return Decision.deny("refunds over $1000 need a manager")
    return Decision.allow()

Agent(..., guards=[CallbackGuard(can_use)], confirm_fn=...)

ToolAllowlistGuard

ToolAllowlistGuard(allowed: Iterable[str])

Bases: Guard

Allow only the named tools; deny any other tool call.

Useful to scope a run to a subset of registered tools (or to cleanly reject a tool the model hallucinated).

PiiRedactionGuard

PiiRedactionGuard(
    patterns: Sequence[str] | None = None,
    *,
    mask: str = "[REDACTED]",
)

Bases: Guard

Masks PII in the final answer before the user sees it.

Opt-in (not in :func:secure_defaults) because redacting user-facing text is an application/compliance choice and can mask data the user legitimately asked for. Configure patterns and mask for your domain.

wrap_as_untrusted_data

wrap_as_untrusted_data(text: str) -> str

Mark tool output so the model treats it as content to reason ABOUT, not instructions to follow. The system prompt must explain this convention.

secure_defaults

secure_defaults(
    policy: AgentPolicy | None = None,
) -> list[Guard]

A conservative, non-destructive default pipeline:

  • :class:TierGuard — enforce prohibited / confirm-first tiers.
  • :class:PiiUrlGuard — block PII in URLs/query strings.
  • :class:InjectionGuard — flag injection-like tool output.
  • :class:UntrustedDataGuard — wrap tool output as untrusted data.

:class:RecipientTrustGuard is intentionally not included — it needs an app-specific trust predicate; add it explicitly when relevant.