🚀 一个 Rust 工作区,实现了基于 OpenRouter / 兼容 API 的函数调用 AI 智能体,提供 Read/Write/Edit/Bash 四类工具。基于领域驱动设计和洋葱架构原则,构建在四个隔离的 crate 之上。
架构
oy (CLI 入口, 默认启动 TUI) ────
├──► oy-agent (编排) ──► oy-ai (AI 提供者抽象)
oy (oy -p "prompt" 直接执行) ────
| Crate | 层 | 描述 |
|---|---|---|
oy-ai |
核心 | AI 提供者 trait、值对象(ChatMessage、ToolCall)、OpenRouter 实现 |
oy-agent |
领域 | Agent 实体、Tool trait、编排器循环、工具实现(Read/Write/Edit/Bash)、会话持久化 |
oy-code-cli |
基础设施 | CLI 参数解析(clap)、二进制入口 oy |
oy-tui |
基础设施 | 基于 ratatui 的 TUI shell,markdown 渲染、命令系统、主题切换 |
依赖方向
oy-code-cli→oy-agent→oy-aioy-tui→oy-agent→oy-aioy-code-cli→oy-tui(无 prompt 时启动 TUI)
快速开始
前置条件
- Rust 1.85+(
rust-toolchain.toml自动配置) - 一个 OpenRouter 或兼容的 API 密钥
配置
~/.oy-ai-agent/config.toml:
= "sk-or-..."
= "https://openrouter.ai/api/v1"
= "anthropic/claude-haiku-4.5"
= "light" # "light" 或 "dark"
也可通过环境变量设置:
安装与运行
# 从 crates.io 安装
# 启动 TUI(默认)
# 或直接使用 CLI 模式
本地开发
# 构建
# 启动 TUI
# 测试
TUI 功能
命令系统
在输入框输入 / 弹出命令选择器:
| 命令 | 功能 |
|---|---|
/model |
三步表单设置 API Base URL / API Key / Model,保存 config,重启 agent 且保留会话消息 |
/settings → /theme |
切换 light / dark 主题,持久化到 config.toml |
快捷键:↑/↓ 导航选择器,Enter 确认,Esc 取消,Ctrl+O 展开/折叠工具结果。
Markdown 渲染
AI 回复内容以 Markdown 格式渲染,支持:
| 语法 | 显示 |
|---|---|
**bold** |
加粗 |
*italic* |
斜体 |
`code` |
黑底青字 |
``` 代码块 |
独立段落,代码高亮 |
# Heading |
标题 |
- list |
列表 |
> quote |
引用块 |
--- |
分割线 |
工具调用 & 结果显示
- 每个工具调用显示为
🔧 工具调用 · Read,含实时计时器 - 结果返回后合并显示在调用下方,带用时时长
✓ (0.5s) - Read 结果折叠至前 5 行,Bash 结果折叠至后 5 行
Ctrl+O展开全部内容
主题
内置 light / dark 双主题:
- light:白底,消息气泡淡蓝/淡绿/淡紫
- dark:黑底,消息气泡深蓝/深绿/深紫
通过 /settings → /theme 切换,设置持久化到 config.toml。
消息背景色
每条消息独立背景色,整行填充:
| 消息类型 | Light 主题 | Dark 主题 |
|---|---|---|
| User | Rgb(235,240,255) 浅蓝 |
Rgb(25,30,50) 深蓝 |
| Assistant | Rgb(235,255,235) 浅绿 |
Rgb(20,30,20) 深绿 |
| Tool | Rgb(255,235,255) 浅紫 |
Rgb(40,20,40) 深紫 |
Agent 状态指示器
状态栏显示 agent 运行状态:• 空闲,⠋⠙⠹… 旋转动画表示工作中。
可用工具
| 工具 | 功能 | 输入 |
|---|---|---|
| Read | 读取文件内容 | file_path |
| Write | 创建或覆盖文件 | file_path, content |
| Edit | 精确替换文件中的文本段 | file_path, old_text, new_text |
| Bash | 通过 sh -c 执行命令 |
command(含命令黑名单) |
项目结构
oy/
├── Cargo.toml # 工作区
├── oy-ai/ # AI 提供者抽象
│ └── src/
│ ├── domain/ (AiProvider trait, ChatMessage, ToolCall, AiConfig, AiError)
│ └── infrastructure/ (OpenRouter 实现)
├── oy-agent/ # 智能体编排
│ ├── tests/integration_test.rs # MockProvider 集成测试
│ └── src/
│ ├── domain/ (Agent trait, Tool trait, ToolRegistry, AgentError)
│ ├── application/ (Orchestrator 主循环)
│ └── infrastructure/ (ReadTool, WriteTool, EditTool, BashTool, 持久化)
├── oy-code-cli/ # CLI 二进制 `oy`
│ └── src/ (CliArgs, run())
└── oy-tui/ # TUI 二进制
└── src/
├── app.rs # 应用状态、事件循环、键盘处理、命令执行
├── ui.rs # ratatui 渲染(消息区、输入框、状态栏、弹出框)
├── message.rs # Message 枚举、to_lines() MD 渲染、visual_line_count
├── command.rs # 命令注册器、CommandInfo、CommandItem
├── event.rs # 事件循环(tick、crossterm、agent 信号)
├── load_config.rs # config.toml 加载/保存
├── theme.rs # Theme 结构体、DARK_THEME / LIGHT_THEME
├── agent.rs # AgentManager
└── main.rs # 入口
测试
cargo test --workspace # 116 个测试
| 测试套件 | 位置 | 测试数 |
|---|---|---|
| oy-ai 单元 | oy-ai/src/domain/ |
23 |
| oy-agent 单元 + 工具 | oy-agent/src/ |
58 |
| oy-agent 集成 | oy-agent/tests/ |
5 |
| oy-tui 单元 | oy-tui/src/ |
30 |
会话持久化
对话历史自动保存到 ~/.oy-ai-agent/sessions/<项目路径>/<uuidv7>.json。切换模型时(/model 命令),旧 agent 的上下文通过 oneshot channel 提取,注入到新 agent,确保会话不丢失。
许可证
MIT