Skip to main content

Module scripted_tool

Module scripted_tool 

Source
Expand description

Scripted tool: compose ToolDef+callback pairs into a single Tool via bash scripts. Requires the scripted_tool feature. Scripted tool

Compose tool definitions + callbacks into a single Tool that accepts bash scripts. Each registered tool becomes a builtin command inside the interpreter, so an LLM can orchestrate many operations in one call using pipes, variables, loops, and conditionals.

This module follows the same contract surface as crate::tool:

§Architecture

┌─────────────────────────────────────────┐
│  ScriptedTool  (implements Tool)        │
│                                         │
│  ┌─────────┐ ┌─────────┐ ┌──────────┐  │
│  │get_user │ │get_order│ │inventory │  │
│  │(builtin)│ │(builtin)│ │(builtin) │  │
│  └─────────┘ └─────────┘ └──────────┘  │
│        ↑           ↑           ↑        │
│  bash script: pipes, vars, jq, loops    │
└─────────────────────────────────────────┘

§Example

use bashkit::{ScriptedTool, Tool, ToolArgs, ToolDef};

let tool = ScriptedTool::builder("api")
    .tool_fn(
        ToolDef::new("greet", "Greet a user")
            .with_schema(serde_json::json!({
                "type": "object",
                "properties": { "name": {"type": "string"} }
            })),
        |args: &ToolArgs| {
            let name = args.param_str("name").unwrap_or("world");
            Ok(format!("hello {name}\n"))
        },
    )
    .build();

let output = tool
    .execution(serde_json::json!({"commands": "greet --name Alice"}))
    .expect("valid args")
    .execute()
    .await
    .expect("execution succeeds");

assert_eq!(output.result["stdout"], "hello Alice\n");
assert!(tool.help().contains("## Tool Commands"));

§Shared context across callbacks

When multiple tool callbacks need shared resources (HTTP clients, auth tokens, config), use the standard Rust closure-capture pattern with Arc:

use bashkit::{ScriptedTool, ToolArgs, ToolDef};
use std::sync::Arc;

let api_key = Arc::new("sk-secret-key".to_string());
let base_url = Arc::new("https://api.example.com".to_string());

let k = api_key.clone();
let u = base_url.clone();
let mut builder = ScriptedTool::builder("api");
builder = builder.tool_fn(
    ToolDef::new("get_user", "Fetch user by ID"),
    move |args: &ToolArgs| {
        let _key = &*k;   // shared API key
        let _url = &*u;   // shared base URL
        Ok(format!("{{\"id\":1}}\n"))
    },
);

let k2 = api_key.clone();
let u2 = base_url.clone();
builder = builder.tool_fn(
    ToolDef::new("list_orders", "List orders"),
    move |_args: &ToolArgs| {
        let _key = &*k2;
        let _url = &*u2;
        Ok(format!("[]\n"))
    },
);
let _tool = builder.build();

For mutable shared state, use Arc<Mutex<T>>:

use bashkit::{ScriptedTool, ToolArgs, ToolDef};
use std::sync::{Arc, Mutex};

let call_count = Arc::new(Mutex::new(0u64));
let c = call_count.clone();
let tool = ScriptedTool::builder("api")
    .tool_fn(
        ToolDef::new("tracked", "Counted call"),
        move |_args: &ToolArgs| {
            let mut count = c.lock().unwrap();
            *count += 1;
            Ok(format!("call #{count}\n"))
        },
    )
    .build();

§State across execute() calls

Each execute() creates a fresh Bash interpreter — no state carries over. This is a security feature (clean sandbox per call). The LLM carries state between calls via its context window: it sees stdout from each call and can pass relevant data from one call’s output into the next call’s script.

For persistent state across calls via callbacks, use Arc in closures — the same Arc<ToolCallback> instances are reused across execute() calls.

Structs§

DiscoverTool
A Tool that exposes only discover and help builtins for runtime schema discovery. Returned by ScriptingToolSet::tools in DiscoveryMode::WithDiscovery mode alongside the main script tool.
ScriptedCommandInvocation
One builtin/tool invocation inside a scripted tool execute.
ScriptedExecutionTrace
Inner execution trace captured for the last ScriptedTool::execute() call.
ScriptedTool
A Tool that orchestrates multiple tools via bash scripts.
ScriptedToolBuilder
Builder for ScriptedTool.
ScriptingToolSet
Higher-level wrapper around ScriptedTool with mode-controlled tool exposure.
ScriptingToolSetBuilder
Builder for ScriptingToolSet.
ToolArgs
Parsed arguments passed to a tool exec function.
ToolDef
OpenAPI-style tool definition: name, description, input schema.
ToolDefExtension
Bash extension that registers ToolDef-backed commands plus help and discover.
ToolDefExtensionBuilder
Builder for ToolDefExtension.
ToolImpl
Complete tool: definition + sync/async exec functions.

Enums§

CallbackKind
Sync or async callback for a registered tool.
DiscoveryMode
Controls how ScriptingToolSet::tools exposes tool information to the LLM.
ScriptedCommandKind
Kind of inner command invocation recorded during a ScriptedTool execute.

Type Aliases§

AsyncToolCallback
Alias for AsyncToolExec (backward compatibility).
AsyncToolExec
Asynchronous execution function for a tool.
SyncToolExec
Synchronous execution function for a tool.
ToolCallback
Alias for SyncToolExec (backward compatibility).