Skip to main content

everruns_core/
tool_hooks.rs

1//! Neutral contracts for capability-contributed per-tool execution hooks.
2
3use crate::tool_context::ToolContext;
4use async_trait::async_trait;
5use everruns_contracts::tool_types::{ToolCall, ToolDefinition, ToolResult};
6
7/// Decision returned by a [`PreToolUseHook`] before a tool is dispatched.
8#[derive(Debug, Clone)]
9pub enum PreToolUseDecision {
10    /// Continue with the possibly transformed call.
11    Continue(ToolCall),
12    /// Block this call without affecting sibling calls in the batch.
13    Block {
14        /// Call that was blocked.
15        tool_call: ToolCall,
16        /// Error text recorded for the model and audit stream.
17        reason: String,
18        /// Optional message for a user-facing runtime.
19        user_message: Option<String>,
20    },
21    /// Do not run this call yet; record `result` as its outcome instead.
22    ///
23    /// For gates that park the turn on a durable request rather than answer
24    /// in-process (hosted tool approval): `result` carries a structured payload
25    /// that a post-act hook turns into a pause, and its `error` is what the
26    /// model reads. Like `Block`, the tool is never invoked and the chain stops.
27    Defer {
28        /// Call that was deferred.
29        tool_call: ToolCall,
30        /// Outcome recorded for the call in place of running it.
31        result: ToolResult,
32    },
33}
34
35/// Capability hook invoked before each individual tool execution.
36#[async_trait]
37pub trait PreToolUseHook: Send + Sync {
38    /// Transform or block a tool call before dispatch.
39    async fn before_exec(
40        &self,
41        tool_call: ToolCall,
42        tool_def: &ToolDefinition,
43        context: &ToolContext,
44    ) -> PreToolUseDecision;
45}
46
47/// Ordering for capability-contributed post-tool hooks.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
49pub enum PostToolExecHookPriority {
50    /// Inspect or block output before normal mutating hooks.
51    Guardrail = 0,
52    /// Default ordering for transformation and observability hooks.
53    Normal = 100,
54}
55
56/// Capability hook invoked after each individual tool execution.
57#[async_trait]
58pub trait PostToolExecHook: Send + Sync {
59    /// Ordering within the capability-contributed hook phase.
60    fn priority(&self) -> PostToolExecHookPriority {
61        PostToolExecHookPriority::Normal
62    }
63
64    /// Inspect or transform one tool result before engine event emission.
65    async fn after_exec(
66        &self,
67        tool_call: &ToolCall,
68        tool_def: &ToolDefinition,
69        result: &mut ToolResult,
70        context: &ToolContext,
71    );
72}