Releases: cherish-ltt/oy
v0.8.0
v0.8.0 — Session 加载、HTML 导出与键盘冲突修复
Release date: 2026-06-15
功能特性
CLI: oy session {path} 子命令
- commit
ba4c262 - 新增
oy session {path}子命令,通过oy-code-cli的Commands枚举注册。 - 加载有效 session:调用
load_session_messages验证文件,有效则启动 TUI 恢复对话。 - 无效文件友好提示:非 session 文件输出
❌ 'xxx' is not a valid OY session file.+ℹ️ No new conversation will be created.,不创建新对话。 - 向后兼容:原有的
--session/-s标志位保持不变,行为不受影响。 - 代码复用:提取
validate_session_file共享辅助函数,消除run_session_path与run_session_command之间的重复代码。
TUI: /output-session-to-html 命令
- commit
1262918 - 新增
/output-session-to-html斜杠命令,将当前会话的所有 ChatMessage 导出为自包含 HTML 文件。 - HTML 模板:使用 Rust 静态字符串模板(非 LLM 生成),内联 CSS/JS,无外部依赖。
- 侧边栏:消息列表(点击滚动到对应消息)、角色筛选按钮(All / System / User / AI / Tool)、搜索框。
- 主区域:完整对话历史,按角色使用不同颜色区分(System=灰色、User=蓝色、Assistant=绿色、Tool=紫色、Thinking=黄绿)。
- AI Thinking:
reasoning_content使用<details>标签默认折叠。 - Dark/Light 模式:切换按钮,默认 light,通过
localStorage持久化用户偏好。 - 安全防护:所有用户/AI 内容经
html_escape转义,防 XSS。 - 导出路径:保存到当前目录
.oy-agent-output/sessions-output/html/oy_session_{unix_timestamp}.html,目录自动创建。 - 新增
oy-tui/src/html_export.rs模块,包含 14 个单元测试。
Bug 修复
方向键冲突 — ↑/↓ 改为 Alt+↑/Alt+↓ 切换历史
- commit
715c310 - 问题:之前
↑/↓同时承担「光标移动」和「user prompt 历史浏览」两个职责,导致多行输入时光标操作与历史导航冲突。 - 解决方案:将历史浏览功能迁移到
Alt+↑/Alt+↓(Mac 上为⌥↑/⌥↓),↑/↓仅保留光标移动功能。 - Alt+↑:进入历史模式 / 翻更旧的 prompt。
- Alt+↓:翻更新的 prompt / 归位清空 input。
- 状态栏提示:使用
#[cfg(target_os = "macos")]平台感知显示。
Alt+Enter 平台感知提示
- commit
7aeec4a - 状态栏中
Alt+Enter改为平台感知显示:macOS 显示⌥Enter,Windows/Linux 显示Alt+Enter。 - 与已有的
⌥↑/⌥↓ history/Alt+↑/Alt+↓ history保持一致。
HTML 导出路径优化
- commit
5171451 - 将
/output-session-to-html的导出路径从当前目录改为.oy-agent-output/sessions-output/html/。 - 目录不存在时自动创建(
create_dir_all),创建失败时显示错误信息。
完整提交日志
ba4c262 feat(cli): add 'oy session <path>' subcommand for loading session files
1262918 feat(tui): add /output-session-to-html command for exporting chat to HTML
715c310 fix(tui): change history navigation from arrow keys to Alt+Up/Alt+Down to resolve cursor conflict
7aeec4a fix(tui): add platform-specific hint for Alt+Enter (⌥Enter on macOS)
5171451 fix(tui): change HTML export path to .oy-agent-output/sessions-output/html/ with auto-create dir
What's Changed
- v0.8.0 — Session 加载、HTML 导出与键盘冲突修复 by @cherish-ltt in #12
Full Changelog: v0.7.1...v0.8.0
v0.7.1
v0.7.1 版本发布
Bug 修复(8 项)
基于 PR #10 Code Review 反馈,修复了以下 8 个问题:
- API 响应验证 —
opencode_go_provider.rs增加 choices/message 防御性检查 + error 字段检查,防止无限循环 - GrepTool 参数注入 — 使用
--分隔符 + extension 白名单校验,防止选项注入 - Sub-Agent Runner panic — 使用
catch_unwind包裹 tool.execute(),防止 panic 导致进程崩溃 - eprintln! 干扰 TUI — 替换为
log::warn!,避免 stderr 破坏终端渲染 - BashTool 超时泄漏 — 实现 thread + mpsc + recv_timeout 超时机制,超时 kill 子进程
- EditTool 空文本 — 拒绝空 old_text,防止意外全局替换
- agent.rs 冗余循环 — 简化 replace_messages_preserve_system_prompt 循环逻辑
- 辅助函数 exit — build_provider_config 等函数改为返回 Result,由调用者处理错误
新功能
- Input 历史 prompt 浏览 — input 为空时 ↑/↓ 切换 user 历史 prompt,支持连续切换、归位清空
CI 验收
- cargo fmt --all -- --check ✅
- cargo clippy --all-targets -- -D warnings ✅
- cargo build --verbose ✅
- cargo test --verbose ✅(233 tests passed)
完整提交日志
408b8dc fix(oy-ai): 增强 API 响应验证防止无限循环
a8ffe9e fix(grep): 修复参数注入漏洞 — 添加 -- 分隔符和 extension 校验
19110e2 fix(sub-agent-runner): 使用 catch_unwind 防止工具 panic 导致进程崩溃
f05832d fix(persistence): 替换 eprintln! 为 log::warn! 避免 TUI 渲染干扰
d44dd4d fix(bash): 添加同步超时机制防止线程/进程泄漏
c54e06b fix(edit): 增加 old_text 空字符串校验防止意外替换行为
0866fd1 refactor(agent): 简化 replace_messages_preserve_system_prompt 循环逻辑
aa26a1a fix: 移除辅助函数中的 std::process::exit,改为返回错误由调用者处理
1c3fcf6 feat(tui): input 为空时 ↑/↓ 切换 user 历史 prompt
c7faf89 docs: add input history prompt feature to v0.7.1 changelog
What's Changed
- v0.7.1 — PR #10 Code Review 反馈修复 + 功能增强 by @cherish-ltt in #11
Full Changelog: v0.7.0...v0.7.1
v0.7.0
GrepTool, Clippy Thresholds & Code Decomposition
Bug 修复
- 系统提示词注入修复:Agent trait 新增
insert_message_front方法;修复系统提示词插入位置逻辑;replace_messages_preserve_system_prompt空消息时正确过滤源 System 角色消息 - CLI session 选择器修复:明确区分
CancelvsInvalid选择状态 - GrepTool Windows 条件编译:通过
#[cfg]隔离 Unix/Windows 平台代码
功能特性
- Tool 超时机制:Tool trait 新增
default_timeout(),LLM 可动态覆盖超时,Worker 执行层tokio::time::timeout包裹,超时返回信息而非错误,TUI 实时显示(elapsed/timeout) - 新增 GrepTool:系统
grep搜索工具,支持正则、路径过滤、扩展名过滤、结果数限制 - 社区 PR 合入:不可读目录跳过而非 panic
重构优化
- Clippy 阈值 lint 配置:
.clippy.toml配置 + crate root#![deny()] - 大量函数拆解:orchestrator.rs、sub_agent_runner.rs、reactor.rs、skill.rs、edit.rs、persistence.rs、message.rs、ui.rs、app.rs 等模块函数提取拆分
- TUI 复杂函数 allow、移除未使用参数与冗余赋值
文档变更
- 简化子 crate README
- GitHelper 能力同步(commit/issue/PR)
CI 改进
- clippy
--all-targets覆盖所有 target
完整提交日志
详见 doc/versions/v0.7.0.md
What's Changed
- Release v0.7.0 — GrepTool, Clippy Thresholds & Code Decomposition by @cherish-ltt in #10
Full Changelog: v0.6.1...v0.7.0
v0.6.1
v0.6.1 — Bug Fixes & Prompt Enhancement
Release date: 2026-06-12
Bug 修复
Worker::run Idle 状态阻塞修复
- commit
7f67cf8 - 问题:Worker::run 主循环中,无条件 try_recv 排水循环会在 Agent 处于 Idle 状态时清空通道中的 Prompt 命令并注入消息历史,随后 Idle 分支的 recv().await 因通道为空而无限期阻塞,导致用户第一个 Prompt 被"吞掉"不触发 AI 思考。
- 修复:仅在非 Idle 状态时运行 try_recv 排水循环,Idle 状态下命令正常走 assembly_prompts 路径触发状态机流转。
Agent 切换时系统提示词覆盖修复
- commit
0735983 - 问题:MainAgent 与 CommanderAgent 切换时,replace_messages 直接 clear 所有消息并用源 Agent 消息覆盖,导致目标 Agent 的系统提示词被替换,Agent 失去角色定位和工具集。
- 修复:replace_messages 保留目标 Agent 自身的 System Prompt(第一条消息),仅替换后续的用户/助理/工具消息。
Windows 路径兼容性修复
- commits
c185edd、4c37c9f - 问题:MainAgent/CommanderAgent 的 save_session 和 SubAgentRunner 中的路径处理仅替换正斜杠
/,未处理 Windows 的反斜杠\和盘符冒号:,导致在 Windows 上创建嵌套目录或保存失败。 - 修复:统一使用
.replace(['/', '\\'], "-").replace(':', "")处理路径,确保跨平台兼容。
功能增强
新增 oy sub-sessions 子命令
- commit
3aac623 - 新增独立子命令
oy sub-sessions,用于列出和交互式加载子代理 session 文件。 - 扫描
~/.oy-ai-agent/sessions/*/sub_agents/*.json,按修改时间降序排列。 - 交互式选择器风格与
oy -r一致,支持选择后通过 TUI 加载查看。 - 不修改
list_all_sessions(),不影响oy -r原有行为。
CI 验收标准注入 + GitHelper 能力扩展
- commit
54f8826 - CommanderAgent:新增步骤 0「探索 CI 配置」,要求读取
.github/workflows/*.yml提取验收标准;创建 planner 时通过 context 传入 CI 标准。 - Planner:工作方式增加 CI 验收标准感知;计划模板新增「CI 验收标准」章节。
- GitHelper:从仅支持 commit 扩展为支持
gh issue create和gh pr create,成为完整的仓库协作助手。 - 后续优化(
72036b4):将 CI 验收标准描述从 Rust 特化(cargo fmt/clippy/build/test)泛化为语言无关描述,以.github/workflows/*.yml为最终标准,无 CI 时按「测试通过 → 检查通过 → 代码格式化」三层递进。
重构优化
消除代码重复 + 补充单元测试
- commits
0dd7cb8、d2d02d3 - 提取
replace_messages_preserve_system_prompt共享函数到domain/agent.rs,消除 CommanderAgent 和 MainAgent 间的重复实现。 - 将
drain_pending_enter_prompts重命名为drain_pending_commands,消除命名误导。 - 为两个 Agent 各补充 3 个 replace_messages 单元测试,覆盖保留自身 System Prompt、空自身消息、源无 System 三种场景。
- 应用 clippy 和 fmt 格式化优化:长链式调用换行、嵌套 if let 合并为 let-chains。
完整提交日志
3aac623 feat: 新增 `oy sub-sessions` 子命令独立查看子代理 session
72036b4 refactor: 泛化 CI 验收标准描述,消除 Rust 特化语言
54f8826 feat: 优化系统提示词 — CI 验收标准注入 + GitHelper 能力扩展
0dd7cb8 refactor: 消除 replace_messages 代码重复、重命名 drain_pending_commands、补充单元测试
d2d02d3 style: 应用 clippy 和 fmt 格式化优化
4c37c9f fix: 修复 sub_agent_runner.rs 中三处 Windows 路径兼容性问题
c185edd fix: 修复 save_session 中 Windows 路径兼容性问题
0735983 fix: 修复 Agent 切换时 replace_messages 覆盖系统提示词的问题
7f67cf8 fix: 修复 Worker::run 中 try_recv 排水循环在 Idle 状态下导致阻塞的问题
What's Changed
- docs: v0.6.1 版本日志 + 多项修复与功能增强 by @cherish-ltt in #9
Full Changelog: v0.6.0...v0.6.1
v0.6.0
v0.6.0 — Sub-Agent System
Release date: 2026-06-11
子代理系统 (Sub-Agent System)
实现了一套完整的子代理协作系统。CommanderAgent 作为调度层,将用户任务拆解并委派给 Planner / Worker / Reviewer / GitHelper 四个专用子代理,形成"计划→执行→审查→提交"的自动化流水线。
架构
用户 ──► CommanderAgent (调度层)
│
├─► create_sub_agent("planner", ...) 制定计划
├─► create_sub_agent("worker", ...) 执行代码
├─► create_sub_agent("reviewer", ...) 审查产出
└─► create_sub_agent("git_helper", ...) 提交 commit
子代理一览
| 代理 | 职责 | 迭代上限 | 最终能力要点 |
|---|---|---|---|
| CommanderAgent | 意图识别、任务拆分、调度子代理、结果汇总 | N/A | 可使用 Read/Bash 探索代码库;不直接 Write/Edit 代码;与 MainAgent 共享 session UUID、可互相切换并保留完整上下文 |
| Planner | 制定开发+测试计划 | 25轮 | 输出含完整 Plan 模板(影响范围/验收标准/风险防御),持久化到 .oy-agent-output/plans/ |
| Worker | 按计划产出完整可编译代码 | 50轮 | 严格遵循 Plan,不偏离、不引入未要求特性、不留 TODO 占位符 |
| Reviewer | 审计代码,输出通过/不通过 | 15轮 | 问题分三级(严重/中度/轻度),结果写入 .oy-agent-output/reviews/;中度及以上不通过 |
| GitHelper | git add + commit | 10轮 | 生成含 commit-hash-id 的输出 |
核心运行机制
- 独立 Runtime:子代理在独立 tokio runtime 中运行,不阻塞主循环
- 消息结构:System Prompt 自动注入工作目录、当前时间及工具描述,子代理具备完整上下文
- Session 持久化:MainAgent 与 CommanderAgent 共享同一 UUID 和 session 文件,切换 agent 自动恢复对话历史;子代理 session 自动保存用于调试
- Prompt 队列:Worker drain loop 不静默丢弃 prompt,所有消息可靠传递
- 错误处理:tool 执行 panic 在 UI 展示,不静默丢失
- UUID 工具:子代理可调用
uuid工具生成 v4/v7 标识符 - System Prompt 升级:五大子代理提示词强化角色定位(Planner "建筑设计师般严谨"、Worker "外科手术刀般精准"、Reviewer "编译器般严谨"),约束更明确
TUI 集成
- Shift+Tab 切换 MainAgent / CommanderAgent,状态栏显示当前 active agent
- 底部 Sub-Agents 面板:实时显示执行状态(▶ 运行中 / ✓ 完成 / ✗ 失败),支持鼠标滚轮滚动,子代理面板最多显示 5 行
- 每个 toolcall 显示对应 agent 名称,带实时计时器
- 两个 agent 共享 UI 会话历史,独立维护 LLM 上下文,response receiver 合并为统一事件流
核心文件
| 文件 | 职责 |
|---|---|
oy-agent/src/domain/sub_agent.rs |
子代理类型枚举、System Prompt 模板、迭代上限定义 |
oy-agent/src/infrastructure/agents/commander_agent.rs |
CommanderAgent 实现 |
oy-agent/src/infrastructure/agents/sub_agent_runner.rs |
子代理有界循环执行器 |
oy-agent/src/infrastructure/tools/sub_agent_tool.rs |
统一 create_sub_agent 元工具 |
其他变更
de2fa7d— feat: 移除技能列表编号,注入 Karpathy behavioral guidelines 到系统提示词5f3421f— fix: 修复 thinking/assistant 渲染尾部空行问题675e526— chore: 精简依赖特性,重组 workspace Cargo.toml458e5aa— fix: 更新测试断言匹配新 skill heading 格式
完整提交日志
以下 23 个 commit 可合并理解为本版本的一次完整 feat+fix,以最终系统能力为准。
6d16eeb feat: 实现子代理系统 (CommanderAgent/Planner/Worker/Reviewer/GitHelper)
a06bac0 fix: 修复子代理消息结构 — 添加User消息和工具描述到System Prompt
10726b0 fix: sub_agent_runner 移除 tokio::spawn 嵌套解决 tool 结果丢失
bf6b30d fix: 子代理 system prompt 注入工作目录和当前时间
2d98797 fix
1867f22 fix: tool 执行 panic 不再静默丢失,错误展示在 UI
d8a09fc fix: CommanderAgent session 持久化 + 子代理独立 runtime
2d8af7e chore: remove accidentally committed test.md
59f5cf6 fix: MainAgent 和 CommanderAgent 共用同一 UUID、同一 session 文件
a03c522 fix: 切换 agent 时从 session 文件恢复完整对话历史
c478a24 fix: Shift+Tab 切换 agent 时通过 channel 传递对话历史
c87b71e fix: 子代理创建改为 tokio::spawn + .await,移除嵌套 runtime
a110bcf fix: 子代理面板支持鼠标滚轮滚动 + 计时器冻结 + toolcall显示agent名
c025eb9 feat: 子代理自动保存 session 文件用于调试
b857ff7 feat: 新增 uuid tool (v4/v7)
25e1771 fix: Worker drain loop 不再静默丢弃 Prompt,CommanderAgent 后台启动使用共享 session UUID
28aa976 fix: 子代理面板最大显示行数从 3 提升到 5
4e7dc3b feat: 全面升级子代理系统提示词,增强角色定位、约束规范与Plan模板
5f3421f fix: resolve trailing blank lines in thinking & assistant content rendering
de2fa7d feat: remove numbering from skills title and add Karpathy behavioral guidelines
675e526 chore: prune dependency features and reorganize workspace Cargo.toml
458e5aa fix: update test assertion to match skill heading format
What's Changed
- Feat v0.6.0 by @cherish-ltt in #8
Full Changelog: v0.5.2...v0.6.0
v0.5.2
发布日期:2026-06-09
概述
本版本聚焦于 TUI 中多项关键 UX 问题的修复:配置流程缺陷(子菜单表单被重置、/model 多步流程崩溃)、配置不完整时的优雅处理、改进的命令检测(仅完全匹配 / 前缀才视为命令)、以及视觉修复(消息末尾多余空行、换行随终端 resize 自适应)。
提交记录
[7c63063] chore: bump version to 0.5.2, update dependencies, remove env var fallbacks
将所有 crate 版本更新至 0.5.2,升级依赖项(async-openai 0.41.0、ratatui 0.30.1、uuid 1.23.3、chrono 0.4.45 等),并从配置加载中移除 OPENROUTER_* / OPENCODE_MODEL 环境变量回退——配置现在完全来自 ~/.oy-ai-agent/config.toml。
涉及文件:
Cargo.lock | 159 ++++++++++++++++++++++++++++++++--------------
Cargo.toml | 16 ++---
oy-code-cli/src/lib.rs | 27 +++-----
oy-tui/src/load_config.rs | 22 +++----
4 files changed, 139 insertions(+), 85 deletions(-)
[cffbaa7] fix: prevent submenu ModelForm from being reset by cleanup code
当从 /settings 子菜单中选择 /base-url、/api-key、/model-name 或自定义 context 时,execute_submenu_item 会将 app_mode 设为 ModelForm,但随后立即被无条件的清理代码重置为 Normal。添加 return; 语句防止清理代码覆盖 ModelForm 模式,使输入表单保持打开状态。
涉及文件:
oy-tui/src/app.rs | 4 ++++
1 file changed, 4 insertions(+)
[78a5ce8] fix: clear input buffer on command execution and fix /model multi-step flow
- 在
execute_command开头清空self.input和cursor_pos,防止命令执行后残留文本(/settings、/model)出现在输入区域。 - 将
/modelstep 0 标题从"API Base URL:"改为"API Base URL (step 1/4):",使其不匹配handle_key_model_form中的is_single检查,从而让 4 步表单(url → key → model → context)正常工作,而不是在第一步后就短路退出。
涉及文件:
oy-tui/src/app.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
[a5930e5] fix: prevent panic when API config is incomplete at startup and runtime
- 添加
config_is_complete()辅助函数检查api_key、base_url、model。 - 在会话恢复和全新启动两条路径中保护 agent 启动——配置不完整时跳过 agent 初始化,而不是 panic。
- 当 agent 因缺少配置无法启动时,显示欢迎提示消息。
- 保护
switch_reasoning_effort、switch_context_capacity和switch_single_setting:仅在所有必要字段都已配置时才重启 agent;否则保存配置并显示帮助消息。
涉及文件:
oy-tui/src/app.rs | 112 +++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 89 insertions(+), 23 deletions(-)
[7cb7256] fix: only treat exact /-prefixed input matches as commands, otherwise send as prompt
- 将
execute_command改为使用精确命令名匹配(c.name == trimmed),而非前缀匹配(c.name.starts_with(input))。 - 移除输入不匹配时的
"Unknown command"回退消息。 execute_command现在返回bool:true表示识别为命令。- 在
handle_key_normal中,当/开头的输入不是已知命令时,回退为普通 prompt 发送给 agent。 - 这使得类似
/path/1/2 check xxx或/model fix xxx的提示能作为普通 prompt 工作,而非被拒绝。
涉及文件:
oy-tui/src/app.rs | 64 ++++++++++++++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 31 deletions(-)
[75f107f] fix: only enter CommandSelector mode when /-prefixed input matches known commands
此前,任何长度大于 1 的 / 开头输入都会进入 CommandSelector 模式,即使没有命令匹配(如 /12)。这导致 Enter 被 CommandSelector 的空匹配处理程序静默消耗,阻止了输入作为 prompt 发送。
现在仅在存在实际命令匹配时才进入 CommandSelector 模式。不匹配的 / 开头输入停留在 Normal 模式,并在按下 Enter 时正确发送为 prompt。
涉及文件:
oy-tui/src/app.rs | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
[12149ac] fix: correct message line counting and auto-scroll on terminal resize
- 在
visual_default_count中,将内容传入render_markdown前应用trim_end(),与to_lines()的做法保持一致。防止尾部空白/换行使视觉行数膨胀,导致消息底部出现大面积空白区域。 - 在
App结构体中添加last_chat_widthCell<u16>字段,用于跟踪每帧渲染时聊天区域的宽度。当终端 resize 导致宽度变化时,强制 auto-scroll 到底部,使msg_heights和Paragraph::wrap使用新尺寸重新计算,让换行自适应当前终端大小。
涉及文件:
oy-tui/src/app.rs | 3 +++
oy-tui/src/message.rs | 5 +++--
oy-tui/src/ui.rs | 9 +++++++++
3 files changed, 15 insertions(+), 2 deletions(-)
What's Changed
- Fix v0.5.2 by @cherish-ltt in #7
Full Changelog: v0.5.1...v0.5.2
v0.5.1
v0.5.1 — Prompt 回显截断 & 多余空行修复
问题描述
当用户在 Input 区域粘贴长代码或多行内容时,Ratatui 回显的 prompt 末尾出现内容丢失(截断)。同时,thinking(推理)和 content(回复)内容的末尾容易出现大量多余空行。
根因分析
Bug 1:visual_line_count 未考虑终端宽度折行(核心截断原因)
文件: oy-tui/src/message.rs
所有 visual_*_count 函数(用于计算每条消息在聊天区的视觉高度)都忽略 width 参数,仅统计 render_markdown() 输出的逻辑行数,而不考虑这些行在终端宽度下会被 ratatui 的 Wrap 自动折行。
后果: 当 prompt 包含长行代码(几乎所有粘贴的代码)时,visual_line_count 返回的数值远小于实际渲染所需行数。消息区域分配的 height 不足,prompt 末尾的多行内容被 Paragraph 裁剪掉。
✅ UiMessages 已正确保留了折行计算(使用 div_ceil):
Message::UiMessages(text) => {
let line = format!("> {}", text);
let w = UnicodeWidthStr::width(line.as_str());
1.max(w.div_ceil(width)) // 正确
}❌ 其他所有消息类型都忽略了折行:
fn visual_default_count(&self, chat: &ChatMessage, _width: usize, theme: &Theme) -> usize {
// width 被完全忽略!
if let Some(c) = &chat.content {
count += Self::render_markdown(c, Style::default(), theme).len();
// 只数逻辑行数,不计算折行
}
}影响范围: AgentMessages(User、Assistant、Tool)和 ToolCallMsg、PromptQueued 等全部消息类型。
Bug 2:visual_default_count 与 to_lines 渲染不一致(末尾空行原因)
to_lines() 方法对 reasoning 和 content 的实际输出与 visual_default_count 的统计方式存在差异:
- reasoning_content:
to_lines将整个 thinking 文本(含内部换行)放在一个Line中,但旧的visual_default_count通过render_markdown拆成多个Line。两者行数不一致,导致分配高度与实际渲染不匹配。 - content:
to_lines在内容首行加了[Role]前缀(如[Assistant]),但visual_default_count没计入此前缀宽度,造成首行被低估,在宽度边界处产生空行或截断。
Bug 3:wrap_input_text 静默丢弃尾部空白(次要)
文件: oy-tui/src/ui.rs
wrap_input_text 函数中,当行末空白字符触发折行时,pending_ws 中的空白被直接丢弃,不追加到当前行。
Bug 4:Input Paragraph 缺少 .wrap() 保护(次要)
Input 区域的 Paragraph 没有设置 .wrap(),完全依赖 wrap_input_text 的预折行。预折行如有 off-by-one 错误,超长行会被直接裁剪。
修改清单
oy-tui/src/message.rs
| 修改项 | 说明 |
|---|---|
新增 count_wrapped_content_lines() |
辅助函数:对带固定前缀的文本行,按宽度计算折行后的视觉行数 |
visual_default_count |
重写:reasoning 按 [Role - thinking] 前缀 + 内容单行折行,content 按 render_markdown 各行 + 首行 [Role] 前缀折行 |
visual_read_count |
引入 [Tool - Read] 前缀宽度,使用 count_wrapped_content_lines |
visual_bash_count |
引入 [Tool - Bash] 前缀宽度 |
visual_edit_count |
result/old/new 各段分别计算前缀宽度 + 折行 |
visual_write_count |
从硬编码返回 2 改为计算 [Tool - Write] + 文件路径行的实际折行 |
ToolCallMsg 分支 |
header 按实际字符串宽度折行 + 内容 " " 前缀折行 |
PromptQueued 分支 |
从硬编码返回 2 改为计算显示文本的实际折行 |
移除 count_wrapped_lines |
原辅助函数不再使用 |
oy-tui/src/ui.rs
| 修改项 | 说明 |
|---|---|
wrap_input_text |
非空白字符触发的折行前,先将 pending_ws 刷入当前行,保留尾部空白 |
| Input Paragraph | 添加 .wrap(Wrap { trim: false }) 作为预折行的兜底保护 |
测试
- 全量测试 164 个(4 个 crate)全部通过 ✅
- 编译零警告 ✅
受影响文件
oy-tui/src/message.rs (核心修复 — visual_line_count 系列函数)
oy-tui/src/ui.rs (输入区显示修复)
What's Changed
- Fix v0.5.1 by @cherish-ltt in #6
Full Changelog: v0.5.0...v0.5.1
v0.5.0
v0.5.0 更新日志
feat — 新功能
CLI 命令扩展
-
oy update— 新增 update 子命令,通过 npm 更新 CLI 工具- 先尝试
npm install -g @ghyper9023/oy(超时 300s) - 失败后自动 fallback 到
--registry https://registry.npmjs.org/(超时 300s) - 前者更新成功则不触发后者
- 先尝试
-
oy -c— 继续最近会话- 扫描
~/.oy-ai-agent/sessions/下所有 session,按修改时间取最新 - 找到则加载历史消息进入 TUI,可继续在原 session 中聊天
- 没找到则启动空白 TUI(等同
oy) - 加载后滚动条自动定位到最新消息
- 扫描
-
oy -r— 交互式 Session 选择器- 列出所有 session,按最后修改时间降序排列
- 每行显示:
[编号] uuid前缀... | 项目目录 | 首条用户消息摘要 - 用户输入编号选择要恢复的 session
- 用户消息摘要自动折叠换行为单行文本
-
oy -s <path>/oy --session <path>— 加载指定路径的 session 文件- 直接传入任意 JSON 文件路径,尝试作为 session 加载
- 文件不存在或格式非法时打印错误并退出
- 可用于加载非标准位置的 session 文件或手动备份的对话记录
会话持久化改进
- Worker 初始化支持指定 uuid 和预加载历史消息(
Worker::with_session()) - Orchestrator 新增
start_with_session()入口,复用原 session uuid - 加载 session 后继续聊天,消息续写到同一 session 文件(不生成新文件)
- 新增
list_all_sessions()/find_latest_session()/get_session_preview()/load_session_messages()查询函数 - Session 预览文本自动扁平化为单行(换行 → 空格,连续空白合并)
refactor — 架构重构
分层调整
oy-code-cli新增 session 选择交互逻辑(纯 CLI,不依赖 ratatui)oy-tui::run_tui()签名改为接受Option<PathBuf>,支持 session 路径注入App::new()增加 session 加载分支,自动从 JSON 恢复 TUI 消息显示persistence.rs新增独立查询层,与save_session/load_session保持向后兼容
chore — 工程维护
- 版本更新至 v0.5.0
oy-code-cli新增 dependency:uuid- Cargo.lock 自动更新
What's Changed
- Feat v0.5.0 by @cherish-ltt in #5
Full Changelog: v0.4.0...v0.5.0
v0.4.0
v0.4.0 更新日志
refactor — 架构重构
Worker + Reactor 架构
- 将原来的
AgentLoop拆分为 Worker(纯状态机)与 Reactor(调度层)两部分 - 引入
WorkerCommand/WorkerEvent通道用于内部通信,解耦命令发送与状态反馈 - 新增
PromptKind(Enter / AltEnter)和PromptRequest类型,统一管理用户输入 - Reactor 负责接收 Worker 事件并按优先级调度命令,Worker 专注 LLM 调用状态流转
提示词队列系统
- 新增
PromptQueued/PromptConsumed事件,为 TUI 提供实时队列反馈 App中新增pending_prompts追踪已入列提示词的 ID- Alt+Enter 提交的提示词进入队列,等待 Worker 空闲后逐条处理
- 底层依赖:
oy-tui新增uuid依赖用于生成提示词 ID
fix — 修复
状态竞争条件 (stale-state race)
- 乐观更新策略:在发送命令给 Worker 之前,TUI 层先将
worker_state乐观更新为Thinking,防止状态传播窗口期内 TUI 请求被错误转发 notify_state从try_send改为 async send,确保状态变更不会被静默丢弃
Enter 提示词注入时序
- 在
StateChanged(ToolCall)时 flushenter_queue;Worker 在tool_call()后 draincmd_rx,将排队的提示词作为 user message 与 tool results 一起注入,在下一次 LLM 调用前发送 - Alt+Enter 提示词保持排队,直到 Worker 回到
Idle状态后才处理 FlushEnterQueue错误吞噬修复:批处理所有提示词,返回最后一个错误而非静默覆盖中间错误
队列编号动态化
- 移除
PromptQueued消息中的持久化number字段 - 移除
App中的next_prompt_number循环计数器 - 队列编号在渲染时根据位置动态计算(
index + 1) - 撤销提示词改为按队列中的第 N 个查找,而非存储的编号
- 消除旧行为的两大问题:
- 消费 [1][2][3] 后新增显示 [4] 而非 [1](编号不重置)
- 撤销中间提示词后出现 [1][3] 而非 [1][2](编号不重排)
UI 状态文本
- 更新状态栏文本,添加 Alt+Enter 快捷键提示,告知用户可将提示词发送到队列
chore — 工程维护
- 各模块版本已更新至 v0.4.0
oy-tui新增 dependency:uuid = { version = "1", features = ["v7"] }- Cargo.lock 自动更新
What's Changed
- Feat v0.4.0 by @cherish-ltt in #4
Full Changelog: v0.3.0...v0.4.0
v0.3.0
v0.3.0 更新日志
feat — 新功能
技能管理系统
- 新增
SkillSummary领域模型,封装技能元数据(folder_name / name / description / path) - 自动从
~/.oy-ai-agent/skills/和~/.claude/skills/目录发现技能(SKILL.md + YAML frontmatter) - 技能列表注入 Agent system prompt,LLM 可据此主动在需要时
Read技能文件 Agenttrait 新增set_skills默认方法,向后兼容/claude-skills命令实时开关 Claude 技能目录的读取- 会话启动时打印已加载技能列表:
[Available Skills] grill-with-docs, karpathy-guidelines, ... - 新增 14 个单元测试覆盖 frontmatter 解析、目录发现、提示片段生成
Markdown 表格渲染
- 集成
pulldown-cmark的ENABLE_TABLES选项解析表格 - 纯文本表格渲染:使用 box-drawing 字符(┌─┬┐)绘制边框
- 支持 Left / Right / Center 三对齐
- 启用 strikethrough(
删除线)解析扩展
ToolCall 参数显示
- ToolCall 状态消息增加
arguments字段 - Read/Edit/Write 工具显示
file_path参数,Bash 显示command参数 - 面板实时展示:
ToolCall Read: /path/to/file (0.2s)
输入框自动换行
- 实现
wrap_input_text算法,手动将输入文本按行宽切割 - 采用 word-wrap 策略:连续空白暂存,遇到非空白字符超宽时自动换行
- 使用
UnicodeWidthChar::width正确处理 CJK 宽字符 - 算法与
visual_cursor_pos一致,彻底修复光标位置错位问题 - 移除 ratatui 的
Wrap,避免双重换行导致的偏移
fix — 修复
- 修剪聊天消息内容末尾的空白字符(
trim_end),消除视觉闪烁 - Markdown 渲染后行尾空白/空行修剪(
trim_trailing_lines) - 所有配置 API(theme / thinking / context / base-url / api-key / model-name)写入时带上
read_claude_skills: None,防止旧配置被意外覆盖
chore — 工程维护
- 各模块版本已更新至 v0.3.0
oy-agent新增 dev-dependency:tempfile = "3"oy-tui新增 dependency:serde_json = "1"- Cargo.lock 自动更新,新增
tempfile/fastrand依赖
What's Changed
- Feat v0.3.0 by @cherish-ltt in #3
Full Changelog: v0.2.1...v0.3.0