Files
ycode/docs/对话区模型选择器对齐-2026-10-16.md
T

13 KiB
Raw Blame History

对话区模型选择器:源码级恢复与验收(2026-10-16)

对话区的模型列表已从 YCode 自写下拉换成 REA 恢复的 WorkBuddy 5.8.2 当前 cr ModelSelector。原版触发按钮、Popover、列表、分组、子菜单与键盘行为由恢复体自身所有,YCode 只提供模型目录并执行真实写入。已构建并更新用户 YCode;实窗停在原会话、选中 gpt-6-luna、草稿为空。

原版来源

WorkBuddy 5.8.2,安装包根 SHA-256 035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918。全部原版脚本、CSS 与画面经 REA 固定导出读取,未直接访问原版文件系统,未运行原 bundle。

证据 内容
ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb 固定运行脚本,.tmp/rea-runtime-scripts.json
ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94 固定 CSS 与 token,.tmp/rea-css-recovered/
ev_1c3853a9a4dd6f99cf76d1874ad57af7ad6fb56c33e6b4e5c2a2e770f91f462e 1336×901 原版模型菜单展开态:触发按钮计算样式、340×368 菜单、选中行
ev_330f3e738f84f51e0bc5beb5a2ee5647a8bd567407048d1ff239384929ba324f 同版本第二次触发按钮计算样式(用于交叉核对)

关键源 SHA-256:src-DbE1_mgM.js(对话面板 chunk)6c6ce63c93854783270e855572797d75e536e3b8d4548410e31fe9d147e1feb4;src-DPDj7_qD.js(WB 原语)747e41d215375e1214c366213aea7e077d85421923029c61cbb6e9562be58de0;src-CyXHA0IC.css a5e26b537bb50323aefbf25abddad52e288dd3868598be8d255d70886fe77cfe;src-CBaV_A3S.css 2090ed21045c8f8b0fc388d76424c8751bf18fcd065cbbd5d0ef485163a2e36c;src-Bh3YZ35H.css 88dbdc1cd3f59d0e8b75824512a465a2be714bc7af481d790fe3a9484f85e01a;contexts-BkjwYSZT.css 50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380。

恢复范围

scripts/rea/recover-composer-model-selector.mjs 从固定导出抽取 192 个正文定义(含 UTF-16 区间与 SHA)与 7 份源文件,写出 source.mjs / source.d.mts / source.css / manifest.json,并对 3665 处标识符引用做未绑定审计(0 处未解析)。--check 幂等通过。

恢复体包含:ModelSelectorImpl、ModelSelectPopover、ModelSubMenu、ModelItem、ModelGroupMenuItem、ModelTierBadge、ModelBadge、OverflowTitleSpan、ReasoningEffortPanel、ContextWindowPanel、collectModelOptions、resolveSelectedModelId/Label、buildGroupedModels、getDefaultIsThinking、isReasoningConfigurable、formatCredits、formatContextWindow、getSupportedContextWindows、createModelSelection、resolveModelIcon / getModelIconByName 及 14 个厂商图标、所需 Menu/MenuGroup/MenuItem/SubMenu/Popover/Tooltip/ScrollArea/WB Switch 原语。

6 处宿主接缝(逐条记于 manifest adaptations,不是自造组件):输入框 store/selector、渲染诊断 sink、cr 配置 Context(从约 250 KB 各语言表裁到 prefixCls/mode/locale/t)、FloatingUI 走宿主固定版本 @floating-ui/react 0.27.20、DOMPurify 走宿主 3.4.17(原包内嵌 3.4.11,sanitize 配置逐项保留)、FloatingPortal 主题包装。

文案取自 src-DbE1_mgM.js UTF-16 offset 172945 的 zh-CN locale 字面量,26 条 chatInput.modelSelector.* 逐条解码。复核确认解码结果全为简体(思考强度/开启/极致),恢复器早先注释称其为繁体有误,已更正。

生产接线

新增 src/renderer/src/workbuddy/composer/model-selector/:

  • SourceModelSelector.tsx:把 YCode CustomModelProfile[] 映射为源 provider 契约,并实现真实 onSelect / onManage。恢复体一次选择会同时调用 store 与 host onChange,适配层只让 store 做投影、由 onChange 执行写入,避免重复提交。
  • source-adapter.css:唯一一处宿主适配。WorkBuddy 文档没有全局 button 字体重置,触发按钮沿用 UA 默认 Arial;YCode app.css 的 button{font-family:inherit} 会让标签继承 PingFang SC 并改变度量,因此用 font-family:revert 还原到 UA 默认,而不是写死某个平台字体。
  • 类别图标不再强行套 provider 图标:不传 icon/iconUrl 时恢复体按模型名走品牌图标表(与截图一致)。

推理强度子菜单已接线:源实现在 supportsReasoning 时显示思考开关与强度档位。YCode 侧新增可持久化的会话级 thinkingLevel(off|low|medium|high|xhigh|max,见 src/shared/workspaces.ts),主进程经 session:create / session:update-context 透传,OMP 回合在 setHostTools 之后调用内核 RPC set_thinking_level(每回合应用,无需重启内核)。适配层把模型档案映射为源 provider 契约的 supportsReasoning / onlyReasoning / canDisableThinking / defaultEffort / supportedEfforts,源组件自身的开关与档位面板负责交互,写入由 onChange 上报后落到会话上下文。写入链路已端到端验证;set_thinking_level 到模型的真实推理档位变化属 OMP 内核行为,本轮只核到命令接线与 OMP 自身支持,未做真实回合的档位效果比对。

适配层对强度做逐项校验而非直接 ?? 回退:模型从未设置默认强度时档案里是 defaultEffort: '',空串既不是合法档位、也会被主进程拒绝,因此只有落在五档白名单内的值才参与回退,最终回退顺序是「本次上报值 → 模型默认 → 模型支持档位首项 → high」。开启思考时源实现不携带强度(强度保存在它自己的按模型偏好里),此时回退到模型默认档位;若解析结果与当前持久化值相同则短路,重选已选中的行仍是空操作。

共享 cr 样式还依赖三条 shell 规则,已一并恢复并记录:.wb-icon 的 flex 基线、.wb-home-composer__input-slot [class*=icon] 的 50% 圆角、.wb-home-composer__input-slot .cr-input-toolbar 的 --cr-text-primary 桥接。前两条按后代关系落到 scope;第三条目标在 composer 工具栏(scope 的祖先),按 \.cr-input-toolbar .yc-source-model-selector 保留原元素关系。另修正 CSS 过滤器:此前漏掉裸 .cr-menu-item__icon/__content/__extra,导致 footer 图标没有 16px 盒与 8px 右边距。

dompurify 原为 mermaid 的传递依赖,已显式声明为 3.4.17 根依赖。package.json/package-lock.json 相应更新;npm install 在本仓库因既有 vite 8 与 electron-vite peer 冲突失败,属于既有问题,未用 --force 绕过。

验证

检查 结果
恢复幂等 node scripts/rea/recover-composer-model-selector.mjs --check → PASS(7 sources / 192 bodies / 0 未解析)
组件原生(隔离 Electron) 73/73,.tmp/model-selector-native-pTsrpd/report.json:新增 1336×901/DPR1 打开态与 hover 态逐元素 bbox/计算样式采样,含 popover、菜单、滚动列表、全部模型行/图标/文本 Range、footer;截图为 open.png / hovered.png
触发按钮 108 项计算属性 对 ev_1c3853a9… 原版节点逐项比对,0 差异
真实应用 product flow 两阶段 PASS,.tmp/product-flows-0r0i1O/:UI→preload→IPC→真实 OMP 创建/编辑模型、主界面选择与持久化、重启恢复
真实应用推理强度写入 三连切换往返一致(off → max → off → max 落库),.tmp/verify-live-thinking-write.mjs;切换中会话与草稿均未变
用户实窗 340×91 菜单、行高 32、选中 gpt-6-luna、Escape 关闭(150ms 退场后卸载)、会话与草稿未变

实窗检查发送 0 条消息、增删 0 个模型。进程替换后 PID 69300,原会话 c261f03b-2efa-4816-b07f-9245f8f7e2c7 恢复、草稿为空。

打开态逐属性核对(2026-10-16)

YCode 隔离 Electron fixture 已按原版视口 1336×901、devicePixelRatio=1 采样。每次运行会在 .tmp/model-selector-native-*/report.json 保存 openState、hoverState 的计算样式、元素框与文字 Range 框,并保存 open.png / hovered.png。这次报告是 .tmp/model-selector-native-pTsrpd/,73 项通过。恢复 CSS 与 token 的依据为 WorkBuddy 5.8.2 的 REA Evidence ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94;既有开态截图帧来自 ev_1c3853a9a4dd6f99cf76d1874ad57af7ad6fb56c33e6b4e5c2a2e770f91f462e 的 visual probe(帧 SHA-256 ee80b6f2aee823de4ed48f7d7788ad01be059bdde981d51428c19fc3878da991)。

本轮尝试对当前 WorkBuddy 窗口取新开态证据时,REA list_electron_targets 对 http://127.0.0.1:9223 返回 provider_unavailable / endpoint_unreachable;REA 原生窗口观察与场景操作返回 target_unavailable。因此没有在 WorkBuddy 中执行点击,也没有改变其窗口状态。现存 Evidence 的 viewport 为 1336×901,配套截图像素也为 1336×901(DPR 1 是据此推断);但它的最终 layout 在点击 footer 后采集,模型菜单已关闭,只含触发按钮的节点样式。下面的“原版”列将 REA 恢复的 CSS/token 与此前截图几何分开标记;它不代表本轮在原版打开态下取到了逐节点的运行时 computed style。

属性 WorkBuddy 5.8.2 的 REA 来源 YCode 打开态 fixture 差异与判定
viewport / DPR 截图与 CSS viewport 1336×901;DPR 1 由两者像素尺寸相同推断 1336×901,devicePixelRatio=1 对齐
Popover 容器 / 菜单高度 既有开态截图记录菜单 340×368px popover 与菜单实际 340×193px,max-height:368px,固定定位 translate(981px, 265px) 实际内容高度不同;YCode 当前 4 个模型,没有补造行来凑高度
菜单宽度 / 圆角 / 内衬 恢复 CSS:340px / 16px / 8px 340px / 16px / 8px 对齐恢复样式
菜单底色 / 边框 / 阴影 恢复的 light token:白底、#e6e6e6 边框、--wb-shadow-popover 为黑色 4% 的两层阴影 rgb(255,255,255)、1 device px 的 rgb(230,230,230)、相同的 4% 两层阴影 YCode 计算结果符合恢复 token;原版 open-state computed 值仍待 REA 动态采集
滚动列表 / 行 恢复 CSS:列表 gap 2px;行高32px、圆角8px、左右内衬8px 列表 322×134px、gap 2px;4 行均 322×32px、圆角8px、左右8px 几何样式符合恢复 CSS;行数是目录数据差异
模型图标 / 标签 恢复 CSS:图标16px;标签14px/22px,当前项600字重 4 个图标均16×16px;标签均14px/22px,选中项600;文字 Range 高19px 字体度量与恢复规则一致;每个文本宽度由本地模型名决定
Footer 恢复 CSS:32px 行高、圆角8px、14px/22px文字、16px图标和8px右边距 322×32px;16×16px图标、margin-right 8px;文本 Range 98×19px 对齐恢复样式
Hover 恢复 CSS 使用 light --cr-item-hover-bg(#f2f2f2) 悬停的选中思考模型行为 rgb(242,242,242) YCode 与恢复 token 一致;当前 WorkBuddy 的真实 hover 样式尚未采到

这轮没有发现能由 YCode 样式修复的偏差,所以没有改动恢复 CSS 或宿主样式;新增的采样与断言用于锁住菜单表面、边框/阴影、内衬、文字度量、图标、footer 和 hover 色。与 WorkBuddy 的菜单高度、模型名称/图标宽度、渠道分组、徽标、倍率和繁忙状态差异来自目录数据,保持为数据差异,不填造模型元数据。要完成原版逐像素验收,还需要 REA 能访问当前 WorkBuddy renderer 的打开态与 hover 态,并在菜单打开时返回 .cr-model-selector__popover、.cr-model-selector__menu、.cr-model-selector__list、每个 .cr-model-selector__item 及其图标/文字、footer 的 bbox 与 computed style。

未完成

  • 上下文窗口子菜单:恢复体自身逻辑已就位(getSupportedContextWindows 过滤排序 + ContextWindowPanel),但它要求选项带 supportedContextWindows 且 ≥2 项才渲染该行;YCode 模型档案只有单个 maxInputTokens,属数据形态差异,单窗口模型在原版同样不出现该行。要真正提供可切换窗口,还需先决定自定义模型如何声明窗口集合,并确认 OMP 侧是否存在运行时切换通道(RPC 命令表里未见 context-window 设置项,ACP 侧是 session/set_config_option)。
  • 推理强度未做像素验收:思考/强度面板的结构与行为已对齐(开关、档位列表、当前项标记、回调写入),但没有对原版该面板做逐像素计算属性比对,与触发按钮那 108 项同级的证据尚缺。
  • 分组与营销元数据:YCode 模型目录是本地自定义模型,没有 WorkBuddy 的渠道分组、折扣/企业徽标、倍率与繁忙度;恢复体对这些字段的支持已就位,但当前目录不产生这些行。因此菜单行数与内容天然不同,这部分是数据差异而非样式差异。
  • 原版打开态像素:YCode 侧现已采集打开态和 row hover 态逐元素数据;当前 WorkBuddy 的 REA target 不可达,缺少原版菜单每个节点的实时 bbox/computed style 与 hover 帧,因此还未完成两侧逐像素比较。
  • 暗色与动效全状态:仅验证 marker 与 Escape 退场路径,未做全状态像素比对。

可复现:

node scripts/rea/recover-composer-model-selector.mjs --check
node scripts/rea/test-model-selector-native.mjs
node scripts/verify-product-flows.cjs