PicoBot/IMPLEMENTATION_LOG.md
xiaoski b13bb8c556 docs: add implementation log for tools
Document all implemented tools and mechanisms:
- SchemaCleanr for cross-provider schema normalization
- Tool trait enhancements (read_only, concurrency_safe, exclusive)
- file_read, file_write, file_edit, bash, http_request, web_fetch
2026-04-07 23:52:40 +08:00

307 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
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
```