Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ Agent 对话默认关闭,打开某个项目的 Agent 面板时才启动本机

不要这样做:在 Windows React 层重新实现 JSON-RPC 协议;在打开 IDE 时就启动 Agent;取消尚未确认就解锁发送;把取消超时伪装成成功而不提示用户重连;把 API Key 通过环境变量或命令行传给 Agent;替用户下载一份他本机已有的 Agent CLI。

### 思考、计划、斜杠命令与模式通知

共享 Host 一直把 ACP 会话更新(`SessionUpdate`)原样转发,以前 Swift 只消费消息、工具、标题、配置和用量,其余直接丢弃。参考 CC GUI 的可折叠思考块、计划面板与 `/` 命令补全后,macOS 现在消费下面四类标准更新;Host、C ABI 和 fixture 形状都不变,只在 fixture 中补样例并由 Rust 测试确认它们能被官方 SDK 原样往返。

- **思考(`agent_thought_chunk`)**:存为独立的 `thought` 角色消息,不并进 Agent 回复。流式缓冲按角色记录,角色切换先刷新上一段,所以“思考 → 回复 → 工具 → 思考”保持原顺序。只有正在流式输出的最后一段思考默认展开,后续回复或工具到达后自动收起,用户手动展开的状态保留;搜索时临时展开匹配的思考,优先于已有的手动折叠选择;搜索期间不允许再次收起命中文字,清空搜索后恢复手动选择,不把搜索结果写回折叠偏好。手动偏好由 `AgentTranscriptView` 在视图局部内存中按会话 ID 与消息 ID 保存,再以绑定传给思考行;搜索先过滤消息,会移除并重建行,因此不能让行内状态成为偏好的所有者。切换会话保留各自选择,关闭会话或移除实际消息时释放对应偏好,销毁对话视图时一并释放;不写入功能模型、共享 Host、历史文件或安装目录,不影响代码签名和 Sparkle delta。`AgentThoughtTranscriptTests` 直接挂载实际对话容器,通过原生鼠标事件和完整渲染快照覆盖搜索移除/重建、命中时临时展开和会话切换。导出 Markdown 用引用块写出思考,便于和回复区分;历史消息数仍只统计用户与 Agent 回复。活跃思考块的标题显示“思考中…”,底部等待行改为“回复中…”并保留本轮计时,避免重复提示;取消时仍显示“正在停止…”。
- **计划(`plan`)**:ACP 规定每次都发完整计划,所以整体替换,不做合并;空列表清除计划,格式错误的更新忽略,最多保留 100 条。计划条状态只认 `pending`、`in_progress`、`completed`,未知状态的条目丢弃而不是猜测。计划栏固定在活动统计栏上方,折叠时显示进度和当前步骤。`session/load` 回放会自然恢复计划。
- **斜杠命令(`available_commands_update`)**:按会话保存上游列表,最多读取前 200 条;同名命令只保留首条定义,保证命令行身份唯一。断连时清空每个会话的旧命令,重连加载后等待新进程重新上报,避免显示已经失效的能力。输入框以 `/` 开头且命令名中还没有空白时弹出过滤结果,前缀匹配排在包含匹配之前;选择后只把 `/name ` 填入草稿,命令文本仍作为普通 prompt 原样发送,由 Agent 自己解释。实测 codex-acp 1.13.1 把 Skill 以 `$name` 形式放进同一个命令列表,而它的命令解析会跳过 `/$name`,Skill 需要以 `$name` 提及。因此名字以 `$` 开头的命令补全为 `$name `;输入 `$` 只列 Skill,Agent 没有上报 Skill 时 `$` 仍是普通文字。Lithe 不扫描 SKILL.md 或命令目录,也不内置命令表,避免和 Agent 的真实能力不一致。方向键和 Tab 导航依赖 macOS 14 的 `onKeyPress`;macOS 13 保留鼠标选择和 Return 补全。Return、Esc、方向键与 Tab 共用视图局部的补全状态,Return 在命令名未完整时只补全、完整时发送;Esc 先关闭补全,再次 Esc 才停止回复,编辑草稿后重新显示匹配。补全高度由输入区内部的局部布局容器按剩余空间限制,先保留一行可编辑文字;最小输入区放不下一整行命令时,列表浮在输入框上方,通过锚点偏好在整个对话布局中绘制,让鼠标点击范围不被较小的输入面板限制;沿用工作台悬停提示的局部 overlay 模式,不新增全局位置状态或鼠标监听。输入区的最小高度包含上下栏、可编辑行和外边距,附带文件时再预留附件行;这个值只在附件有无改变时通过视图偏好更新,不跟随拖动逐帧发布。不要让固定高度的命令列表参与分隔条的最小尺寸计算,也不要把逐帧几何尺寸发布到会话模型。
- **模式通知(`current_mode_update`)**:Agent 自己切换模式(例如退出计划模式)时,只更新 `category == "mode"` 且包含该值的配置选项,不向上游回发设置请求;选项中不存在的模式 ID 忽略,不显示原始 ID。

正确做法:新的更新类型先在 fixture 中加入样例,让 Rust 往返测试证明它是合法 ACP,再在平台功能模型中解析。不要这样做:在视图中直接解析原始更新;为了显示命令列表而自己维护一份 Claude 或 Codex 命令表。

这些状态只保存在会话内存中,不新增日志、下载、缓存或可复用工作树资源;安装目录和 bundle 仍只读,不影响代码签名和 Sparkle delta。

### 每轮耗时与上报 token

发送后用单调时钟(不受系统日期调整影响的计时源)开始测量,包含建会话、加载历史、工具执行和权限等待。界面“思考中”的秒数表示本轮已经过的时间,不声称是模型内部推理时间。只让可见等待行每秒重绘,不每秒发布整个会话。正常完成、请求失败和断连固定耗时;取消仍等上游确认才结束。每轮末尾保留统计,标签切换不会重置,失败发送和历史回放不编造记录。
Expand Down Expand Up @@ -145,6 +158,7 @@ npm 的进度选项只面向终端,HTTP 日志通常在请求完成后才输

## 验证

- `./.agents/skills/write-stable-tests/scripts/test-stability-macos.sh -- --filter AgentThoughtTranscriptTests`:在生产对话容器中通过鼠标展开/收起思考,搜索隐藏行后进入空会话使列表实际销毁,再返回并清空搜索,确认手动选择保留;同时验证命中时保持文字可见、清空后恢复折叠、会话切换独立和关闭后重新加载的默认状态。渲染只等待可观察的原生画面,每次等待最多两秒;比较同一宿主的完整画面,不依赖系统字体快照基线。窗口和功能模型在成功、失败路径都清理。
- `./.agents/skills/write-stable-tests/scripts/test-stability-macos.sh -- --filter AgentConversationSelectionTests`:原生 SwiftUI 宿主不替换根视图,直接改变模块选择,验证 Agent、模型与连接立即同步;配置确认前保留旧值、确认后刷新,来回切换保持各自配置,删除当前 Agent 时正确回退,关闭全部测试窗口和连接。另对 Claude/Codex 显式驱动最后一个标签关闭→唯一新建请求→过期响应→新会话确认→发送,确认连接不变、准备期间不闪现模型、确认后底栏恢复且消息只交给新会话。显式控制切换→连接→ready→创建确认及历史加载的事件顺序,比较原生工具栏,验证准备期间改变本地默认模型不影响显示、过期响应不能解除等待、已确认连接复用、失败和无配置能力不会一直加载。2026-10-01 修复版真实窗口已验证 Codex 初始化加载提示到 Astra/审批控件、Astra→Luna→Astra 模型切换和重新展开的勾选、模型名称搜索与空结果、Claude/Codex 来回切换保留配置,Codex 最小消息收到预期回复。关闭测试项目后确认无 Agent 子进程,990 个 bundle 文件哈希不变;Windows 对话 UI 与运行验收仍待完成。

- `./.agents/skills/write-stable-tests/scripts/test-stability-macos.sh -- --filter 'AgentConversationFeatureModelTests|AgentConversationPresentationTests'`:注入可推进的单调时钟验证排队、后台会话、取消确认、失败和断连;共享 fixture 校验用量、零值与缺失值,统计行的分组边界与历史回放不伪造。真实 Agent 的 token 口径和连续计时仍需人工验收,不能以合成数据截图代替供应商运行验证。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ PR 的测试合并提交必须在构建摘要中可追溯。被分类器选中
并发缓存主要缩短串行等待和反馈时间,不承诺减少总 runner 分钟;队列等待
和可用 runner 数量属于 CI 基础设施因素,不能与编译优化混为一谈。

Windows 安装器失败时,Bun 可能已经退出,但并行的生命周期脚本仍在运行,
继续占用依赖目录;直接删除目录会让原本可以重试的下载故障变成文件锁错误。
每次安装现在由独立 PowerShell worker 拥有:启动 Bun 前把 worker 加入
Job Object(Windows 用于管理整棵子进程树的对象),设置最后一个句柄关闭时
终止成员进程。句柄不继承给子进程,由 worker 的进程生命周期持有;worker
正常结束、失败或被取消时,系统释放句柄并终止残留脚本;每次安装还有默认
300 秒的 worker 内部期限,超时退出码为 124,不能只依赖 CI 总超时。父安装器再清理
部分缓存和依赖。文件系统释放锁可能稍晚,删除重试有单调计时的 10 秒期限,
超时明确失败,不无限等待。缓存清理后撤销旧 verified 标记,冷安装成功才
重新生成完整性清单。只重试一次,不把永久安装错误隐藏成成功。

正确做法:worker 拥有 Bun 及其脚本,结束后再清理当前工作树生成目录;
不要按进程名结束所有 Node/Bun,因为用户其他工作树或应用可能正在使用它们。
这些句柄和安装目录属于本次安装,不新增可复用资源;只有经过锁文件、Bun
版本与完整性清单校验的下载缓存可以跨工作树复制,安装包仍只读。

## 考虑过的备选方案

### 在旧 runner 上用 Swiftly 安装独立编译器
Expand All @@ -98,6 +114,13 @@ PR 的测试合并提交必须在构建摘要中可追溯。被分类器选中
能减少网络等待,但无法覆盖 Rust Core 和数据库辅助 crate 的主要编译成本,
因此扩展为缓存 Cargo 的中间输出和 build script 结果。

### 失败后仅限制安装并发或等待固定时间

不采用。相同 Bun 版本的本地生命周期探针表明,串行选项也不能保证失败后
没有残留脚本;固定等待则无法证明进程结束。直接结束全部 Node 还会影响
其他任务。Windows Job Object 提供系统级所有权和取消清理,代价是每次安装
多启动一个 PowerShell worker,安装路径的回归测试需要在 Windows 上运行。

### 只构建一个 macOS 架构

可以降低 CI 成本,但无法发现另一架构上的编译、链接和打包问题。macOS 产品
Expand Down Expand Up @@ -151,6 +174,7 @@ Swift 测试已经编译完整 Lithe 目标。再生成两个 DMG 会在普通
- `./scripts/build-official-plugins.sh --configuration debug --triple x86_64-apple-macosx`
- `./scripts/verify-rust-core.sh`
- `./scripts/verify-windows-boundaries.sh`
- `node .agents/skills/write-stable-tests/scripts/run-bun-tests-with-timing.mjs --working-directory . --max-ms 30000 --report .artifacts/test-stability/windows-dependency-install.json -- scripts/windows-frontend-install.test.ts`:Windows 无网络夹具用 IPC 确认子进程占用目录,再让安装失败,验证清理后冷重试成功、永久失败仍报错、成功退出也不留子进程、超时触发本地期限,且不清除有效缓存。
- `gh run download <run-id> --repo 1lck/Lithe-IDEA --pattern 'Lithe-macos-*'`
- `gh workflow run release-preview-windows.yml -f source_branch=<branch>`

Expand All @@ -163,6 +187,9 @@ Swift 测试已经编译完整 Lithe 目标。再生成两个 DMG 会在普通
- `.github/workflows/ci-macos.yml`
- `.github/workflows/ci-windows.yml`
- `scripts/classify-ci-changes.sh`
- `scripts/install-windows-frontend-dependencies.ps1`
- `scripts/invoke-windows-bun-install.ps1`
- `scripts/windows-frontend-install.test.ts`
- `scripts/test-classify-ci-changes.sh`
- `scripts/build-macos.sh`
- `scripts/build-official-plugins.sh`
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ jobs:
shell: pwsh
run: node .agents/skills/write-stable-tests/scripts/run-bun-tests-with-timing.mjs --working-directory frontend/editor --report .artifacts/test-stability/shared-editor.json

- name: Test Windows dependency install recovery
shell: pwsh
run: node .agents/skills/write-stable-tests/scripts/run-bun-tests-with-timing.mjs --working-directory . --max-ms 30000 --report .artifacts/test-stability/windows-dependency-install.json -- scripts/windows-frontend-install.test.ts

- name: Configure isolated dependency caches
shell: pwsh
run: |
Expand Down
7 changes: 7 additions & 0 deletions docs/ci-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ SHA-256;Cargo、SwiftPM 和 Bun 使用各自的 lockfile、版本与完整性
`.swift-version` 和 `.lithe-integrity.json` 校验。
- `.artifacts/bun-cache/`:Bun 下载缓存;按 `bun.lock`、Bun 版本和缓存完整性
清单校验。
Windows 的每次依赖安装在独立 worker 中执行;worker 在启动 Bun 前加入
Job Object(Windows 用于管理整棵子进程树的对象),退出时终止残留安装脚本。
每次安装默认有 300 秒本地期限,超时终止 worker 及其子进程;
安装失败后先释放子进程,再清理部分依赖与缓存,并只进行一次冷安装重试;
文件锁释放有 10 秒本地期限。`node_modules`、两个 workspace 的依赖目录和
`.artifacts/bun-tmp` 是安装过程的可变状态,不跨 worktree 复制;进程句柄只在
worker 内存中存活,不增加下载目录,不写发行资源,也不影响签名或增量更新。
- `.artifacts/jdtls-downloads/`:JDTLS、Lombok、Java Debug/Test 和 license。
- `.artifacts/jdk-downloads/`:各平台与架构的 bundled JDK 下载归档。
- `.artifacts/php-language-server-downloads/`:按
Expand Down
Loading
Loading