# Picobot 工具机制增强实现日志

## 实现记录

### 1. SchemaCleanr - 跨 Provider Schema 归一化

**日期**: 2026-04-07
**Commit**: `d5b6cd2`

#### 背景
不同 LLM provider 对 JSON Schema 支持差异很大：
- **Gemini**: 最严格，不支持 `minLength`, `maxLength`, `pattern`, `minimum`, `maximum` 等
- **Anthropic**: 中等，只要求解决 `$ref`
- **OpenAI**: 最宽松，支持大部分关键词

#### 实现方案

创建 `src/tools/schema.rs`，提供：

1. **`CleaningStrategy` enum**
   ```rust
   pub enum CleaningStrategy {
       Gemini,     // 最严格
       Anthropic,  // 中等
       OpenAI,     // 最宽松
       Conservative,
   }
   ```

2. **`SchemaCleanr::clean()`** - 核心清洗函数
   - 移除 provider 不支持的关键词
   - 解析 `$ref` 到 `$defs`/`definitions`
   - 将 `anyOf`/`oneOf` 合并为 `enum`
   - 将 `const` 转换为 `enum`
   - 移除 `type` 数组中的 `null`

3. **`SchemaCleanr::validate()`** - Schema 验证

#### 使用方法
```rust
use picobot::tools::{SchemaCleanr, CleaningStrategy};

// Gemini 兼容清洗（最严格）
let cleaned = SchemaCleanr::clean_for_gemini(schema);

// Anthropic 兼容清洗
let cleaned = SchemaCleanr::clean_for_anthropic(schema);

// OpenAI 兼容清洗（最宽松）
let cleaned = SchemaCleanr::clean_for_openai(schema);

// 自定义策略
let cleaned = SchemaCleanr::clean(schema, CleaningStrategy::Conservative);
```

#### 工具 Trait 增强

在 `src/tools/traits.rs` 的 `Tool` trait 中新增：

```rust
pub trait Tool: Send + Sync + 'static {
    // ... 原有方法 ...

    /// 是否只读（无副作用）
    fn read_only(&self) -> bool { false }

    /// 是否可以与其他工具并行执行
    fn concurrency_safe(&self) -> bool {
        self.read_only() && !self.exclusive()
    }

    /// 是否需要独占执行
    fn exclusive(&self) -> bool { false }
}
```

这些属性为后续的并行工具执行提供基础。

#### 测试
- 12 个单元测试覆盖所有清洗逻辑
- 运行 `cargo test --lib tools::schema` 验证

### 2. file_read 工具

**日期**: 2026-04-07
**Commit**: `a9e7aab`

#### 功能
- 读取文件内容（支持 offset/limit 分页）
- 返回带行号的内容，便于引用
- 自动处理二进制文件（base64 编码）
- 可选的目录限制（安全隔离）

#### Schema
```json
{
  "type": "object",
  "properties": {
    "path": { "type": "string", "description": "文件路径" },
    "offset": { "type": "integer", "description": "起始行号(1-indexed)" },
    "limit": { "type": "integer", "description": "最大行数" }
  },
  "required": ["path"]
}
```

#### 使用方法
```rust
use picobot::tools::FileReadTool;

// 基本用法
let tool = FileReadTool::new();
let result = tool.execute(json!({
    "path": "/some/file.txt",
    "offset": 1,
    "limit": 100
})).await;
```

#### 测试
- 4 个单元测试
- `cargo test --lib tools::file_read`

### 3. file_write 工具

**日期**: 2026-04-07
**Commit**: `16b052b`

#### 功能
- 写入内容到文件
- 自动创建父目录
- 覆盖已存在文件

#### Schema
```json
{
  "type": "object",
  "properties": {
    "path": { "type": "string", "description": "文件路径" },
    "content": { "type": "string", "description": "写入内容" }
  },
  "required": ["path", "content"]
}
```

#### 测试
- 5 个单元测试
- `cargo test --lib tools::file_write`

### 4. file_edit 工具

**日期**: 2026-04-07
**Commit**: `f3187ce`

#### 功能
- 编辑文件，替换 old_text 为 new_text
- 支持多行编辑
- 模糊匹配处理微小差异
- replace_all 选项批量替换

#### Schema
```json
{
  "type": "object",
  "properties": {
    "path": { "type": "string", "description": "文件路径" },
    "old_text": { "type": "string", "description": "要替换的文本" },
    "new_text": { "type": "string", "description": "替换后的文本" },
    "replace_all": { "type": "boolean", "description": "替换所有匹配", "default": false }
  },
  "required": ["path", "old_text", "new_text"]
}
```

#### 测试
- 5 个单元测试
- `cargo test --lib tools::file_edit`

### 5. bash 工具

**日期**: 2026-04-07
**Commit**: `68e3663`

#### 功能
- 执行 shell 命令
- 超时控制
- 危险命令检测（rm -rf, fork bombs）
- 输出截断
- 工作目录支持

#### Schema
```json
{
  "type": "object",
  "properties": {
    "command": { "type": "string", "description": "Shell 命令" },
    "timeout": { "type": "integer", "description": "超时秒数", "minimum": 1, "maximum": 600 }
  },
  "required": ["command"]
}
```

#### 测试
- 7 个单元测试
- `cargo test --lib tools::bash`

### 6. http_request 工具

**日期**: 2026-04-07
**Commit**: `1581732`

#### 功能
- HTTP 客户端支持 GET/POST/PUT/DELETE/PATCH
- 域名白名单
- SSRF 保护（阻止私有IP、localhost）
- 响应大小限制和截断
- 超时控制

#### Schema
```json
{
  "type": "object",
  "properties": {
    "url": { "type": "string", "description": "请求 URL" },
    "method": { "type": "string", "description": "HTTP 方法", "enum": ["GET", "POST", "PUT", "DELETE", "PATCH"] },
    "headers": { "type": "object", "description": "请求头" },
    "body": { "type": "string", "description": "请求体" }
  },
  "required": ["url"]
}
```

#### 测试
- 8 个单元测试
- `cargo test --lib tools::http_request`

### 7. web_fetch 工具

**日期**: 2026-04-07
**Commit**: `8936e70`

#### 功能
- 获取 URL 并提取可读文本
- HTML 转纯文本
- 移除 scripts, styles, HTML 标签
- 解码 HTML 实体
- JSON 格式化输出
- SSRF 保护

#### Schema
```json
{
  "type": "object",
  "properties": {
    "url": { "type": "string", "description": "要获取的 URL" }
  },
  "required": ["url"]
}
```

#### 测试
- 6 个单元测试
- `cargo test --lib tools::web_fetch`

---

## 工具清单

| 工具 | 名称 | 文件 | 功能 |
|------|------|------|------|
| calculator | 计算器 | `src/tools/calculator.rs` | 25+ 数学和统计函数 |
| file_read | 文件读取 | `src/tools/file_read.rs` | 带分页的文件读取 |
| file_write | 文件写入 | `src/tools/file_write.rs` | 创建/覆盖文件 |
| file_edit | 文件编辑 | `src/tools/file_edit.rs` | 文本替换编辑 |
| bash | Shell 执行 | `src/tools/bash.rs` | 带安全保护的命令执行 |
| http_request | HTTP 请求 | `src/tools/http_request.rs` | API 请求 |
| web_fetch | 网页获取 | `src/tools/web_fetch.rs` | HTML 内容提取 |

## 工具机制增强

### SchemaCleanr
跨 LLM Provider 的 JSON Schema 归一化，支持：
- Gemini (最严格)
- Anthropic (中等)
- OpenAI (最宽松)
- Conservative (保守)

### 工具属性
```rust
fn read_only(&self) -> bool { false }        // 是否只读
fn concurrency_safe(&self) -> bool { true }   // 是否可并行
fn exclusive(&self) -> bool { false }          // 是否独占
```

## 运行测试

```bash
cargo test --lib                    # 所有测试
cargo test --lib tools::schema      # SchemaCleanr
```

## 工具注册

工具在 `src/gateway/session.rs` 的 `default_tools()` 函数中注册：

```rust
fn default_tools() -> ToolRegistry {
    let mut registry = ToolRegistry::new();
    registry.register(CalculatorTool::new());
    registry.register(FileReadTool::new());
    registry.register(FileWriteTool::new());
    registry.register(FileEditTool::new());
    registry.register(BashTool::new());
    registry.register(HttpRequestTool::new(
        vec!["*".to_string()], // 允许所有域名
        1_000_000,             // max_response_size
        30,                    // timeout_secs
        false,                 // allow_private_hosts
    ));
    registry.register(WebFetchTool::new(50_000, 30));
    registry
}
```

SessionManager 使用这些工具创建 AgentLoop 实例，所有工具自动对 LLM 可用。

## 更新日志

| 日期 | Commit | 变更 |
|------|--------|------|
| 2026-04-07 | `d5b6cd2` | feat: add SchemaCleanr |
| 2026-04-07 | `a9e7aab` | feat: add file_read tool |
| 2026-04-07 | `16b052b` | feat: add file_write tool |
| 2026-04-07 | `f3187ce` | feat: add file_edit tool |
| 2026-04-07 | `68e3663` | feat: add bash tool |
| 2026-04-07 | `1581732` | feat: add http_request tool |
| 2026-04-07 | `8936e70` | feat: add web_fetch tool |
| 2026-04-07 | `b13bb8c` | docs: add implementation log |
| 2026-04-08 | `98bc973` | feat: register all tools in SessionManager |
cargo test --lib tools::file_read   # file_read
cargo test --lib tools::file_write  # file_write
cargo test --lib tools::file_edit   # file_edit
cargo test --lib tools::bash        # bash
cargo test --lib tools::http_request # http_request
cargo test --lib tools::web_fetch   # web_fetch
```
