# focus — 纯 Rust 实现的 LLM Agent 框架 > 参考 [pi](https://github.com/earendil-works/pi)(TypeScript 原版)与 > [pi_agent_rust](https://github.com/Dicklesworthstone/pi_agent_rust)(Rust 移植)实现的 > 分层、极简依赖的 LLM agent 框架。**核心目标**:以最小的依赖面实现一个分层清晰、 > 可独立测试的 agent 框架,重点学习 pi 的核心设计——agent 循环、消息类型、工具抽象、流式协议。 ## ✨ 核心特性 - **双层 agent 循环**:外层 follow-up、内层 steering + 工具执行,支持 sequential / parallel 两种工具执行模式 - **流式输出**:SSE 增量解析,流式 assistant 消息随 delta 原地更新;`Esc` 随时中止 - **多 provider 支持**:Anthropic(Messages API)+ OpenAI(Responses API 与 Chat Completions 双协议),统一翻译为 `StreamEvent` 事件流,错误编码进事件而非中断循环 - **内置工具**:`read` / `write` / `edit`(pi 风格精确替换)/ `shell`,跨平台(Windows + Linux) - **会话管理**:树形会话结构(`id` + `parentId`)+ JSONL 追加写,支持分支与会话切换 - **上下文压缩**:token 估算 + 压缩方案(切点 + 摘要指令),自动执行滚动总结 - **交互式 TUI**:多行输入、Markdown 渲染、实时 transcript、折叠的思考/工具块、跨平台滚轮滚动 - **类型安全**:自研 `focus-json` 手写 JSON 编解码,不依赖 serde / serde_json - **依赖极简**:运行时依赖仅 tokio + rustls 生态(另为 TUI 特批 ratatui + crossterm) ## 🏗️ 架构设计 细粒度 **7-crate workspace** 拆分,每个 crate 职责单一、边界清晰、可独立测试。依赖严格单向向下,禁止循环。 ```text focus/ ├── crates/ │ ├── focus-json/ # 极简 JSON 解析器 / 序列化器(零外部依赖) │ ├── focus-core/ # ★ 核心层:领域类型 + Agent 循环 + Tool / StreamProvider trait │ ├── focus-transport/ # 传输层:HTTPS 客户端(tokio + rustls)、HTTP/1.1、SSE 解析 │ ├── focus-providers/ # Provider 实现(Anthropic / OpenAI) │ ├── focus-tools/ # 文件工具(read / write / edit / shell) │ ├── focus-harness/ # 会话持久化 + 上下文压缩 + 系统提示模板 │ └── focus-tui/ # 终端交互层(ratatui + crossterm),组装所有模块 ├── docs/architecture/ # 架构解读文档(三份精读笔记) └── AGENTS.md # 工程规范(依赖白名单、代码/测试/提交规范) ``` ### 分层依赖图 ```text focus-json ← 零外部依赖,纯 std focus-core ← focus-json, tokio focus-transport ← focus-json, tokio, rustls, tokio-rustls, rustls-native-certs focus-providers ← focus-core, focus-transport focus-tools ← focus-core focus-harness ← focus-core, focus-json focus-tui ← focus-core, focus-providers, focus-tools, focus-harness, focus-json, ratatui, crossterm ``` ### 核心设计要点 - **I/O 边界注入**:`focus-core` 是纯逻辑层,不碰网络 / 文件系统;provider 与工具都通过 trait 注入 - **`content` / `details` 分离**:工具结果的 `content`(模型可见)与 `details`(UI / 日志可见)分开 - **错误编码而非抛出**:`StreamProvider` 绝不用 `Err` 中断循环,错误编码进 `StreamEvent::Error` - **压缩只出方案**:harness 产出「压缩方案」,真正的摘要 LLM 调用由上层(TUI)执行——遵守依赖图约束 ## 🚀 快速开始 ### 构建与测试 ```bash # 构建整个 workspace cargo build --workspace # 运行全部测试(181 个用例,全绿) cargo test --workspace # 代码质量检查 cargo fmt --all --check cargo clippy --workspace -- -D warnings ``` ### 运行 TUI ```bash cargo run -p focus-tui ``` > 或直接运行构建产物 `target/debug/focus`。 首次启动后先配置 provider: 1. 在 TUI 中输入 `/config` 打开配置表单(或直接编辑 `~/.focus/config.json`) 2. 填写 `apiKey`、选择 provider 与模型 3. 回到输入框即可开始对话 ## ⚙️ 配置 配置文件位于 `/config.json`,`` 默认为 `~/.focus` (Windows 为 `%USERPROFILE%\.focus`),可用环境变量 `FOCUS_DATA_DIR` 覆盖。 ```json { "provider": "anthropic", "openaiProtocol": "responses", "baseUrl": "https://api.anthropic.com", "apiKey": "sk-...", "model": "claude-sonnet-4-5", "contextWindow": 200000 } ``` | 字段 | 说明 | |---|---| | `provider` | `anthropic` 或 `openai` | | `openaiProtocol` | OpenAI 协议:`responses`(默认)或 `chatCompletions` | | `baseUrl` | API 基址(可选,缺省用默认端点;具体端点路径由 provider 自行拼接) | | `apiKey` | API 密钥 | | `model` | 模型 id | | `contextWindow` | 上下文窗口(可选,缺省按已知模型表自动查询,未知模型兜底 128k) | ### 数据目录 | 内容 | 位置 | |---|---| | 配置 | `/config.json` | | 会话 | `/sessions/.jsonl`(JSONL 追加写,树结构) | ### 环境变量 | 变量 | 说明 | |---|---| | `FOCUS_DATA_DIR` | 覆盖数据根目录(默认 `~/.focus`) | | `FOCUS_SHELL` | 覆盖 `shell` 工具使用的 shell 程序(Windows 默认 PowerShell、可回退 cmd;Linux 默认 bash) | | `FOCUS_DEBUG_FILE` | 设置后,providers 把每个原始网络 chunk 追加到该文件(排查协议不兼容,如推理字段名差异) | ## ⌨️ TUI 使用 ### 命令 | 命令 | 功能 | |---|---| | `/new` | 新建会话 | | `/sessions` | 查看 / 切换历史会话 | | `/config` | 编辑配置(provider / 模型 / 密钥) | | `/compact` | 手动触发上下文压缩 | | `/help` | 显示帮助 | ### 键盘 | 按键 | 功能 | |---|---| | `Enter` | 发送消息 | | `Shift+Enter` | 换行 | | `Esc` | 运行中中止任务;空闲时退出 | | `Ctrl+C` | 退出 | | `Ctrl+D` | 继续(追问一轮) | | `Tab` | 展开 / 折叠最近的思考或工具块(两级:先预览,再全量) | | 鼠标滚轮 | 逐行滚动(Linux / Windows 均支持;上滚暂停自动跟随) | | `Ctrl+U` / `PageUp` / `PageDown` | 滚动消息区(输入为空时 `↑` `↓` 也可滚动) | ## 🧪 测试 - 所有测试位于各 crate 的 `crates//tests/`,禁止在 `src/` 内联测试 - 核心层(`focus-core`)测试**零网络依赖**,用 mock provider 驱动 - provider 测试用**录制 / 回放**的 mock transport,不打真实 API(真实 API 测试用 `#[ignore]` 标记) - 当前共 **181 个测试用例**,`cargo test --workspace` 全绿 ## 📚 文档 - [`AGENTS.md`](./AGENTS.md) — 工程规范:依赖白名单、双语注释规则、代码 / 测试 / Git 提交规范 - [`docs/architecture/00-pi-architecture-overview.md`](./docs/architecture/00-pi-architecture-overview.md) — 参考项目架构全景总览 - [`docs/architecture/01-types-and-protocol.md`](./docs/architecture/01-types-and-protocol.md) — 类型契约逐行精读 - [`docs/architecture/02-agent-loop.md`](./docs/architecture/02-agent-loop.md) — 核心循环逐行精读 ## 📄 许可证 [MIT](./Cargo.toml)