echo_agent 0.1.4

Production-grade AI Agent framework for Rust — ReAct engine, multi-agent, memory, streaming, MCP, IM channels, workflows
Documentation
# Tool System

## What It Is

Tools are the only mechanism through which an Agent interacts with the external world. The LLM learns about a tool's capabilities via JSON Schema, decides when to call it and with what parameters, and the framework handles the actual execution and returns the result back to the LLM.

---

## Problem It Solves

LLMs are pure text models — they cannot:
- Execute code or shell commands
- Query real-time data (weather, stocks, databases)
- Read or write files
- Call external APIs

The tool system provides a standardized bridge, enabling the LLM to drive any external capability through declarative invocation.

---

## Architecture

```
Tool trait                        ← unified interface all tools implement
ToolManager                       ← registry + executor
    ├─ register(tool)
    ├─ execute_tool(name, params)  ← unified execution entry (timeout, retry, concurrency)
    └─ to_openai_tools()           ← serialize to OpenAI function-calling format

Built-in tools (builtin):
    ├─ final_answer               ← output final result (always registered)
    ├─ plan                       ← trigger planning mode (Planner role)
    ├─ create_task / update_task  ← manage DAG sub-tasks
    ├─ agent_tool                 ← dispatch to SubAgent (Orchestrator role)
    ├─ human_in_loop              ← request human text input
    ├─ remember / recall / forget ← long-term memory operations
    └─ think                      ← explicit CoT tool (superseded by CoT text approach)

Extension tools (ready to use):
    ├─ tools/files    ← file read/write
    ├─ tools/shell    ← shell command execution
    ├─ tools/web      ← web search + page fetch (feature: web)
    └─ tools/others   ← math, weather, etc.
```

---

## Implementing a Custom Tool

Implement the `Tool` trait:

```rust
use echo_agent::tools::{Tool, ToolParameters, ToolResult};
use echo_agent::error::Result;
use serde_json::{Value, json};
use async_trait::async_trait;

struct TranslateTool;

#[async_trait]
impl Tool for TranslateTool {
    fn name(&self) -> &str {
        "translate"
    }

    fn description(&self) -> &str {
        "Translate text into a target language"
    }

    fn parameters(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "text":   { "type": "string", "description": "Text to translate" },
                "target": { "type": "string", "description": "Target language code, e.g. 'en', 'zh', 'ja'" }
            },
            "required": ["text", "target"]
        })
    }

    async fn execute(&self, params: ToolParameters) -> Result<ToolResult> {
        let text   = params["text"].as_str().unwrap_or("");
        let target = params["target"].as_str().unwrap_or("en");
        // Call actual translation API ...
        let result = format!("(Translated to {}) {}", target, text);
        Ok(ToolResult::success(result))
    }
}
```

---

## Registering and Using Tools

```rust
use echo_agent::prelude::*;

let config = AgentConfig::new("qwen3-max", "agent", "You are a translation assistant")
    .enable_tool(true);

let mut agent = ReactAgent::new(config);
agent.add_tool(Box::new(TranslateTool));
// or bulk-register: agent.add_tools(vec![...]);

let answer = agent.execute("Translate 'Hello World' to Japanese").await?;
```

---

## Execution Config (timeout / retry / concurrency)

`ToolExecutionConfig` controls execution behavior for all tools:

```rust
use echo_agent::tools::ToolExecutionConfig;

let exec_config = ToolExecutionConfig {
    timeout_ms:      5_000,   // per-call timeout 5s (0 = unlimited)
    retry_on_fail:   true,    // auto-retry on failure
    max_retries:     2,       // max 2 retries
    retry_delay_ms:  300,     // first retry delay 300ms, exponential backoff
    max_concurrency: Some(3), // max 3 concurrent tool calls
};

let config = AgentConfig::new("qwen3-max", "agent", "...")
    .tool_execution(exec_config);
```

**Exponential backoff**: retry 1 → 300ms, retry 2 → 600ms, retry 3 → 1200ms...

---

## Restricting Tools with Allowlist

Use `allowed_tools` to limit which tools a given Agent can call. Commonly used to enforce capability boundaries on SubAgents:

```rust
use echo_agent::tools::others::math::{AddTool, SubtractTool};

let config = AgentConfig::new("qwen3-max", "math_only", "Only do addition and subtraction")
    .allowed_tools(vec!["add".to_string(), "subtract".to_string()]);

let mut agent = ReactAgent::new(config);
// Even if more tools are registered, only 'add' and 'subtract' are exposed to the LLM
agent.add_tools(vec![
    Box::new(AddTool),
    Box::new(SubtractTool),
]);
```

---

## Built-in Tool Reference

| Tool Name | Module | Description |
|-----------|--------|-------------|
| `final_answer` | builtin | Output final result (auto-registered) |
| `plan` | builtin | Trigger task planning (Planner mode) |
| `create_task` | builtin | Create a DAG sub-task |
| `update_task` | builtin | Update sub-task status |
| `list_tasks` | builtin | List all sub-tasks |
| `agent_tool` | builtin | Dispatch task to a SubAgent |
| `human_in_loop` | builtin | Request human text input |
| `remember` | builtin | Write a memory to Store |
| `recall` | builtin | Search memories in Store |
| `forget` | builtin | Delete a memory from Store |
| `read_file` | files | Read file contents |
| `write_file` | files | Write file contents |
| `shell` | shell | Execute shell command |
| `add` / `subtract` / ... | others | Math operations (examples) |
| `get_weather` | others | Weather query (example) |
| `web_search` | web | Web search (requires `web` feature) |
| `web_fetch` | web | Fetch web page and convert to text (requires `web` feature) |

See: `examples/demo01_tools.rs`, `examples/demo09_file_shell.rs`, `examples/demo13_tool_execution.rs`