pub struct BuiltinToolExecutor { /* private fields */ }Expand description
Built-in tool executor that uses ToolRegistry for dynamic dispatch
Implementations§
Source§impl BuiltinToolExecutor
impl BuiltinToolExecutor
Sourcepub fn new_with_permissions(
permission_checker: Arc<dyn PermissionChecker>,
) -> Self
pub fn new_with_permissions( permission_checker: Arc<dyn PermissionChecker>, ) -> Self
Creates a new executor with a permission checker
Sourcepub fn new_with_config(config: Arc<RwLock<Config>>) -> Self
pub fn new_with_config(config: Arc<RwLock<Config>>) -> Self
Creates a new executor that can read the shared, hot-reloadable config.
Use this when running inside the Bamboo server so tools (notably
http_request) honor proxy settings from config.json.
Sourcepub fn new_with_config_and_permissions(
config: Arc<RwLock<Config>>,
permission_checker: Arc<dyn PermissionChecker>,
) -> Self
pub fn new_with_config_and_permissions( config: Arc<RwLock<Config>>, permission_checker: Arc<dyn PermissionChecker>, ) -> Self
Creates a new executor with both shared config and a permission checker.
Sourcepub fn with_registry(registry: ToolRegistry) -> Self
pub fn with_registry(registry: ToolRegistry) -> Self
Creates a new executor from an existing registry
Sourcepub fn registry(&self) -> &ToolRegistry
pub fn registry(&self) -> &ToolRegistry
Returns a reference to the internal registry
Sourcepub fn tool_schemas() -> Vec<ToolSchema>
pub fn tool_schemas() -> Vec<ToolSchema>
Returns all built-in tool schemas
Sourcepub fn register_tool<T: Tool + 'static>(&self, tool: T) -> Result<(), ToolError>
pub fn register_tool<T: Tool + 'static>(&self, tool: T) -> Result<(), ToolError>
Registers a custom tool to this executor
Sourcepub fn register_tool_with_guide<T, G>(
&self,
tool: T,
guide: G,
) -> Result<(), ToolError>
pub fn register_tool_with_guide<T, G>( &self, tool: T, guide: G, ) -> Result<(), ToolError>
Register a tool with its guide
Sourcepub fn build_enhanced_prompt(&self, context: GuideBuildContext) -> String
pub fn build_enhanced_prompt(&self, context: GuideBuildContext) -> String
Build enhanced prompt for all registered tools
Trait Implementations§
Source§impl Default for BuiltinToolExecutor
impl Default for BuiltinToolExecutor
Source§impl ToolExecutor for BuiltinToolExecutor
impl ToolExecutor for BuiltinToolExecutor
Source§fn check_permissions_for<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: &'life2 ToolExecutionContext<'life3>,
) -> Pin<Box<dyn Future<Output = Result<Option<ToolOutcome>, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn check_permissions_for<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: &'life2 ToolExecutionContext<'life3>,
) -> Pin<Box<dyn Future<Output = Result<Option<ToolOutcome>, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
The real permission gate for built-in tools, extracted from the execute
path so it is reusable by wrapping executors (issue #341). The behavior is
byte-for-byte the same block that used to run inline in
execute_with_context_outcome:
- resolves the SAME
tool_name+argsthe execute path runs with (so the check sees exactly what the tool will run with); - “always ask” rules (
requires_forced_confirmation) force a confirmation even under bypass; everything else is skipped when the session is in bypass-permissions mode; - forced confirmations route through
check_or_request_forcedso the active mode/bypass can’t suppress the prompt; - a
ConfirmationRequiredfirst tries the cross-processApprovalProxy(a subagent worker forwarding to its host), then the interactive human sink (returning the synthesized approval pause asOk(Some(..))), then fails closed; - deny fails closed.
The only mechanical difference from the old inline block: the interactive
pause is returned as Ok(Some(outcome)) and a clean pass returns
Ok(None), so the caller decides whether to run the tool. The fallback
arg-parse warning is intentionally NOT re-logged here — the execute path
already logs it once for this call.
Source§fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
) -> Pin<Box<dyn Future<Output = Result<ToolResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn execute<'life0, 'life1, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
) -> Pin<Box<dyn Future<Output = Result<ToolResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn execute_with_context<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: ToolExecutionContext<'life2>,
) -> Pin<Box<dyn Future<Output = Result<ToolResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn execute_with_context<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: ToolExecutionContext<'life2>,
) -> Pin<Box<dyn Future<Output = Result<ToolResult, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn execute_with_context_outcome<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: ToolExecutionContext<'life2>,
) -> Pin<Box<dyn Future<Output = Result<ToolOutcome, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn execute_with_context_outcome<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call: &'life1 ToolCall,
ctx: ToolExecutionContext<'life2>,
) -> Pin<Box<dyn Future<Output = Result<ToolOutcome, ToolError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
ToolOutcome rather than the
collapsed ToolResult, so the agent loop can branch on
Completed/Running/NeedsHuman directly instead of sniffing markers on
a result. The default collapses via the execute_with_context path
(always Completed), so executors that never surface Running/NeedsHuman
(composition, MCP, tests) need no override; the built-in + overlay
executors override this to return the real outcome.Source§fn list_tools(&self) -> Vec<ToolSchema>
fn list_tools(&self) -> Vec<ToolSchema>
Source§fn tool_mutability(&self, tool_name: &str) -> ToolMutability
fn tool_mutability(&self, tool_name: &str) -> ToolMutability
Source§fn call_mutability(&self, call: &ToolCall) -> ToolMutability
fn call_mutability(&self, call: &ToolCall) -> ToolMutability
Source§fn tool_concurrency_safe(&self, tool_name: &str) -> bool
fn tool_concurrency_safe(&self, tool_name: &str) -> bool
Source§fn call_concurrency_safe(&self, call: &ToolCall) -> bool
fn call_concurrency_safe(&self, call: &ToolCall) -> bool
Source§fn call_parallel_classification(
&self,
call: &ToolCall,
) -> (ToolMutability, bool)
fn call_parallel_classification( &self, call: &ToolCall, ) -> (ToolMutability, bool)
(mutability, concurrency_safe). Read moreSource§fn tool_guidance(&self) -> Option<String>
fn tool_guidance(&self) -> Option<String>
instructions an MCP server
returns from initialize. Because it is derived from the live executor,
the text is naturally scoped to what is actually connected/loaded for the
run (a disconnected server contributes nothing). Read more