Skip to main content

ToolGate

Trait ToolGate 

Source
pub trait ToolGate: Plugin {
    // Required method
    fn next_turn_tool_allowlist<'life0, 'life1, 'async_trait>(
        &'life0 self,
        ctx: ToolGateContext<'life1>,
    ) -> Pin<Box<dyn Future<Output = Option<HashSet<String>>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;

    // Provided methods
    fn denial_reason<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        _tool_name: &'life1 str,
        _ctx: ToolGateContext<'life2>,
    ) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'async_trait>>
       where Self: Sync + 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn conflict_priority(&self) -> i32 { ... }
    fn tool_gate_class(&self) -> ToolGateClass { ... }
    fn suppresses_advisory_gates(&self, _ctx: ToolGateContext<'_>) -> bool { ... }
}
Expand description

Per-turn allowlist of tool names the model may invoke.

Returning Some(set) means: for the very next LLM call, narrow the advertised tools to those whose names appear in set. Every other tool the agent has access to is omitted from that one request. None means no narrowing — the loop sends all tools.

Composition across multiple gates: the loop intersects every Some allowlist; absent (None) gates do not constrain. If multiple non-empty gate allowlists conflict to the empty set, the loop repairs the composition by choosing the highest-priority gate and emits a typed conflict event. Gates that own urgent recovery states should override ToolGate::conflict_priority.

Single-shot semantics emerge from the trigger condition, not from internal mutability: a gate that fires only on iteration == 0 is naturally single-shot per run. Conversation-scoped gates should keep their cross-run state in an external store, not in the plugin instance.

Required Methods§

Source

fn next_turn_tool_allowlist<'life0, 'life1, 'async_trait>( &'life0 self, ctx: ToolGateContext<'life1>, ) -> Pin<Box<dyn Future<Output = Option<HashSet<String>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Provided Methods§

Source

fn denial_reason<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _tool_name: &'life1 str, _ctx: ToolGateContext<'life2>, ) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

This gate’s specific reason for denying tool_name in the given context. The runtime queries every gate after a hidden-tool call so the error message names the actual narrower instead of guessing from the intersected allowlist’s shape — that guess sent the model to repair the wrong gate (e.g. a delivery_repair_gate strip read as a capability_gate phase mismatch and triggered futile plan-updates until wall-clock timeout).

Default: None — the runtime falls back to its shape-based heuristic. Return Some(reason) only when this gate is actively narrowing in a way that excludes tool_name in this context.

Source

fn conflict_priority(&self) -> i32

Source

fn tool_gate_class(&self) -> ToolGateClass

Source

fn suppresses_advisory_gates(&self, _ctx: ToolGateContext<'_>) -> bool

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§