App 界面在 Cordy 设计系统上重建:生产界面改由设计令牌与自有组件承担,不再使用 Material 3。
新增
- Cordy 设计系统模块(
:core:designsystem):颜色、字体、尺寸与动效令牌,以及 一整套组件——按钮、输入框、行、文本、图标、菜单、底部面板、对话框、状态、 顶栏、开关、按压反馈、触感与页面转场。 - 设置中新增外观偏好——跟随系统、浅色或深色。选择会被持久化,并在首帧之前解析 完成,冷启动不再闪现错误的主题。
- 统一的动效策略贯穿所有界面,并遵循系统的「减弱动态效果」设置。
- 触感只留给确认时刻:发送、停止生成、确认破坏性操作、错误出现。普通按压、 导航与打开面板不再震动。
- 设计法则一致性测试:覆盖对比度、圆角形状、尺寸、字体、动效与转场,并为每个 组件配备独立的法则用例。
变更
- 仓库导航明确区分当前设计说明、入库证据与历史评审或原型;原始截图和构建产物
统一存放在被忽略的
artifacts/路径下。 - 28 条 Maestro 流程按六类场景分组;既有标签契约改为递归扫描,文档链接和截图 输出位置同步到新的目录结构。
- 回复流式生成期间,输入框保持可编辑。再次发送消息会取消当前请求,完成被中断 回合的保存后,再启动新请求。
- 上下文保留被中断回复中的非空正文,跳过空白或只有思考内容的助手回合,并按完整 用户回合裁剪历史。提交前按系统提示和回复预留预算检查最新输入。
- 聊天、设置与用量界面迁移至设计系统,这些界面已无 Material 3 组件。唯一有意 保留的例外是模态底部面板容器,因为拖拽、遮罩、预测式返回与焦点收拢属于平台 行为。
- 聊天界面:输入区改为扁平停靠栏,横幅与会话库去掉卡片底面,状态由胶囊标签 改为字形图标。
- 会话库每行是单一点击目标;重命名与删除从行内图标按钮移到长按操作集,并提供 长按标签,读屏软件会朗读可用操作。
- 根界面转场改为按粗粒度阶段做交叉淡入淡出,流式 token 与切换会话不会再重新 触发转场。
- 依赖升级至各自最新稳定版:Koog 1.1.1、Ktor 3.5.2、Android Gradle Plugin 9.3.1、AppCompat 1.8.0。Koog 1.1.1 的 Android 制品已按 minSdk 23 发布, 因此为对抗 Koog 1.0.0 的 minSdk 35 基线、用来保住 API 24–34 设备的清单覆盖 声明不再需要,已移除。
- CI 改为运行完整的共享测试套件,不再依赖手写的模块清单。旧清单里仍写着随 Cordy Remote 一起删除的模块,导致自 2026-08-10 起每次推送必红;同时它还 漏掉了五个确实有测试的模块。
- 思考过程与正文走同一条渲染管线。 思考块从前是一个随每次 40ms 发布整段 重排的裸文本节点;现在它经过正文那一套揭示引擎——帧时钟节拍器、抖动缓冲、 append-only 的增量 markdown 解析、活过折叠的台账、以及落定时的同步解析—— 以 caption 字号渲染,标题阶梯压平。头部在推理进行中显示「思考中」,结束后 显示「已思考 N 秒」;时长存在块上,历史记录因此也保留它。答案一开始,思考 过程随即收起,之后无论滚动还是折叠都停在读者最后放的位置。那条 2dp 竖线改为 绘制而非布局,去掉了每次发布多出的一遍测量。
- 落定的 markdown 与代码高亮缓存在消息列表之上,并为最新几轮在主线程外 预热:一行重新滚回视口时,不再重新解析 markdown、也不再重新做代码围栏的 词法分析。渲染仍然从已解析好的状态同步绘制——不可能出现占位空帧。语法高亮 的上限从 200 行降到 100 行,因为其开销随长度超线性增长。列表在视口周围保留 一圈行,而不是把离开视口的行全部销毁;不可编辑的行不再套着编辑转场容器。
- 揭示台账为活草稿的每个块各记一本账,并自己持有帧循环;行只读它。流键按块 种类而不是块下标拼。
- E2E 假运行时可以发出推理增量(
cordy.e2e.thinking),其长回复带有代码围栏, 新增两条 Maestro flow 分别覆盖重历史滚动与思考揭示。仓库级扫描 (CordyMotionLawTest)现在强制执行「无无限动画」法则。 - 输入区下方的 AI 免责声明只在会话为空时显示:第一条消息落地即消失,此后该会话 不再出现;新建会话会重新显示,从会话库打开的旧会话则始终不显示。它此前是常驻 页脚,等于把一句免责声明压在读者滚过的每一条回复下面。
- 冷启动落在空白首会话时,输入框自动获得焦点并唤起键盘——每次启动只做一次,且 绝不会在首次引导面板、抽屉或任何其他覆盖层之下弹出。
修复
回到底部按钮改为根据视口下方实际存在的消息内容显示,尾部布局留白不再让短回复 提前出现该按钮。
草稿只在对应的发送被接收后清空;发送被拒绝或回执延迟时,保留正在编辑的文字 和附件。
快速滚动长历史时的卡顿减轻。 从前每一条落定的行在每次滚动重新挂载时都 在主线程上重新解析 markdown、重新为代码围栏分词。在 Pixel_9 模拟器上实测 (debug 构建,冷启动,HEAD 与本树交替安装,逐字节相同的 18 × 40 段历史): 超过 16.6ms 预算的帧从 10.9% 降到 2.1%(Perfetto 帧时间线),
gfxinfo卡顿率 从 8.0% 降到 6.0%,99 分位帧时长从 44.7ms 降到 38.0ms。大段文本行的布局与绘制 仍是这台模拟器上的地板;见docs/testing/performance-baseline-2026-08-13.md。流式回答每次发布都重跑整棵 markdown 子树。 markdown 渲染器的默认
imageTransformer每次组合都是一个新实例,被提供进一个静态 CompositionLocal, 于是其下所有内容的 Compose 跳过失效——每个已稳定的段落每秒重建约 25 次 span。 现在在每个调用点传入同一个提升出来的实例,并由源码契约测试钉住。收尾中的行被滚出视口时,揭示可能卡死。 帧循环从前住在行里,生成结束后 约 0.9 秒的收尾窗口里一次甩动就会把它取消,而揭示尚未完成:位置弹簧在整个 会话里保持冻结,尾条的操作行永远不出现。循环现在住在列表之上,释放不再取决于 哪些行被挂载。
节拍器的第一帧可能把整个词一直揭到网络切点再停顿;现在与其他每一帧一样受 抖动缓冲上限约束。
答案已经开始后才到达的推理块会让答案的揭示从零重来。
展开的思考过程在折叠那一帧无弹簧地消失;读者手动展开的过程在每次滚动复用后 又自动合上。
OpenAI 兼容通道的推理分块每个 token 解析两次;仅支持 Responses 接口的模型 现在会得到明确的错误而不是 404。
所有 OpenAI 兼容服务商终于能连上接口。 聊天请求被发往重复的版本段——
…/api/v1/v1/chat/completions——一律返回 404,于是 OpenRouter、OpenAI、 Vercel AI Gateway 与火山方舟 Ark 全都无法聊天,而模型列表却能正常加载, 让配置看起来一切正常。此前只有 Anthropic 原生通道可用。现在 Cordy 的baseUrl在各处都被明确定义并统一对待为含版本段的 API 根地址, 拼接在其后的接口路径不再自带版本段。被截断的回复不再被当作完成的回复保存。 OpenAI 兼容适配器把响应流的结束 当成了回答的结束,于是被代理超时或连接中断截断的回复会以「已完成」落库—— 没有失败状态、没有重试入口,用户也无从知道答案缺了结尾。现在改以服务端自己 给出的结束信号为准。
首次运行重新能选出模型。 在填入 API 密钥之前选择服务商,会抹掉内置模型 列表却仍报告成功,新用户面对的是一个空下拉框、没有任何提示、也没有出路。 现在内置列表会被保留,而一次什么都没取到的加载会如实说明。
冷启动时分享进来的图片不再被丢弃。 聊天仍在加载时到达的分享,恰好落在 两个组件都以为对方已接手的缝隙里。现在会先暂存,待聊天就绪后立即放入输入区。
失败的错误横幅不再比取代它的回答活得更久。 重新生成、编辑与重试都没有 清除上一次的错误,于是一条成功的回复可能出现在「这个对话太长了,请开始新 对话」下方。
同一毫秒内创建的两条消息可能以错误顺序存储,导致编辑问题时删掉更早的一条 回答。新一轮对话现在严格排在会话中已有全部消息之后。
无障碍:
userBubble/onUserBubble配色在浅色下实测为 4.23:1,低于 WCAG AA 的 4.5:1 门槛。该配色与其唯一使用方——用户消息的填充气泡——一并退役;用户消息 现改为强调色竖线,文字使用secondaryLabel直接落在界面底色上,该配色在深浅 两套外观下均已达到 AA。