Skip to content

fix(desktop): 已建任务换模型不再被窗口闸误拦,同引擎轨钉死 Harness - #3917

Merged
MagicLizi merged 5 commits into
makecindy:mainfrom
zqchris:fix/model-picker-harness-lock
Sep 4, 2026
Merged

fix(desktop): 已建任务换模型不再被窗口闸误拦,同引擎轨钉死 Harness#3917
MagicLizi merged 5 commits into
makecindy:mainfrom
zqchris:fix/model-picker-harness-lock

Conversation

@zqchris

@zqchris zqchris commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

已建任务里点统一模型选择器,经常切不过去或思考档 / Fast 丢失。这次修两块:同引擎轨把 Harness 钉死在当前轨上,跨引擎确认成功后关选单、再打开停在正在跑的引擎;运行时 SET_MODEL 对未核实窗口 fail-open 热切,Pi / 远端回合中和核实过的危险缩窗改为延期登记,不再弹「当前状态下无法执行」。点选时的档位和 Fast 按原子快照写入,无档模型不再把 leftover high 写进运行时。

变更类型

  • fix 缺陷修复
  • feat 新功能
  • refactor / perf 重构或性能优化
  • docs / test / chore 文档、测试或工程维护
  • 其他:

范围

  • 关联 Issue / 需求:统一模型选择器已建任务换模型
  • 本 PR 包含:同引擎轨钉 Harness、跨引擎确认 / 关选单 / 胶囊「下条:」、运行时窗口闸 fail-open 与延期、点选原子快照
  • 明确不包含:整段 handleSetModel 假 session 注入、SSH / 旧被控端 / Orca Worker 专属切模、Mobile、样式 B、远端空闲危险缩窗 rebuild
  • 用户可见变化:同引擎轨不能改 Harness;浮层改为点「自定义」/ 右键 / ← 打开;跨引擎确认后选单关闭,胶囊标下一条才生效;跑着切 Cindy 打折 / 未核实窗口可以切过去
  • 是否存在 breaking change:无。SET_MODELselection.effort 允许 null(无档模型),仅 Desktop 内部 IPC

UI 变化

怎么验证的

自动验证

pnpm --filter desktop run typecheck
结果:通过

pnpm --filter @cindy/model-providers run --if-present typecheck
结果:通过(无独立 typecheck script 则跳过)

pnpm test:unit:related
结果:test:runner / desktop unit / mobile unit / model-providers unit 全绿

pnpm --filter desktop exec vitest run src/main/__tests__/makerSendToSessionOrdering.test.ts
结果:33 passed(该文件被默认 unit 排除,补跑)

手工验证

未在本轮实机点选。此前隔离 Desktop Global sandbox 验证过选择器 UX;本轮窗口闸改动只靠单测矩阵。界面证据为上述 HTML 预览,不是实机截图。

未执行的验证

  • 全量 pnpm test:unit(交给 CI)
  • 实机:跑着 Opus 5 → Cindy 打折 / Fable、Pi 轨钉死、跨引擎确认关选单
  • 实机 Light / Dark 目检

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:运行时切模闸从 fail-closed 改为 fail-open / 延期

影响与回滚

  • 影响范围:Desktop 已建任务统一模型选择器与 SET_MODELselection.effort: null 只在本机 preload/main;device-link 仍走既有 SET_MODEL。远端空闲核实缩窗仍拒绝。
  • 回滚 / 降级方式:整 PR revert。协议兼容:旧 renderer 仍传 effort: string,main 继续接受;新 renderer 对无档模型传 null

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s,见 DCO
  • UI 改动已在「UI 变化」注明引用的设计规范章节
  • 未提交凭证、令牌或授权文件
  • 已补充必要文档
  • 已确认测试结果或说明未执行原因

统一选择器同引擎轨不再被 leftover override 改道;跨引擎确认成功后关选单,
再打开停在 runtime。SET_MODEL 对未核实窗口 fail-open 热切,Pi/远端回合中
和危险缩窗改为延期而不是 PRECONDITION;点选档位/Fast 按原子快照写入。

Signed-off-by: Chris <4436110+zqchris@users.noreply.github.com>
@zqchris
zqchris marked this pull request as ready for review September 4, 2026 09:52
@zqchris
zqchris requested a review from a team as a code owner September 4, 2026 09:52
@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 调整 Desktop 已建任务的统一模型选择器和运行时 SET_MODEL:同引擎轨固定 Harness,跨引擎确认后关闭选单,窗口信息未知时允许热切,繁忙的远端、Pi 和危险缩窗切换则延期,并将 effort/Fast 作为原子快照传递。

  • 新增纯函数式运行时切模规划及延期结算测试矩阵。
  • 扩展 Desktop IPC,使无思考档模型可以传递 effort: null
  • 将配置浮层入口改为“自定义”、右键或键盘左箭头。
  • 当前仍有两处选择器状态不一致:意图期重开选单混用当前态与目标态,以及同引擎轨收藏行仍可切换 Harness。

Confidence Score: 3/5

当前不宜合并;跨引擎意图期的选择器状态会错位,且同引擎轨中的收藏仍能绕过 Harness 锁定。

两个可达的选择器路径违背本次变更的核心行为:重开选单时混合下一条目标模型与当前运行来源/引擎,收藏行则可直接绕过同引擎轨锁定。两处都应在合并前修复。

Files Needing Attention: apps/desktop/src/renderer/components/new-chat/ChatInput.tsx, apps/desktop/src/renderer/components/new-chat/UnifiedModelPanel.tsx

Important Files Changed

Filename Overview
apps/desktop/src/main/maker-ipc/register.ts 将运行时切模接入热切、延期和核实窗口重试规划,并保存点选时的 effort/Fast 快照。
apps/desktop/src/shared/runtimeModelSwitchGate.ts 新增纯函数切模闸门、延期 profile 和窗口确认重试逻辑,测试矩阵覆盖较完整。
apps/desktop/src/renderer/components/new-chat/ChatInput.tsx 接入原子模型配置及当前运行引擎展示,但意图期向选择器传入了模型、来源和引擎口径不一致的状态。
apps/desktop/src/renderer/components/new-chat/UnifiedModelPanel.tsx 普通模型行已固定到同引擎轨,但收藏行被例外放行,仍可从该轨切换 Harness。
packages/model-providers/src/effortResolution.ts 新增原子选择归一化,无档模型输出 null effort,不支持 Fast 的模型强制关闭 Fast。

Sequence Diagram

sequenceDiagram
  participant U as 用户
  participant R as Desktop Renderer
  participant M as Desktop Main
  participant S as Session Runtime
  U->>R: 选择模型、effort 与 Fast
  R->>M: SET_MODEL 原子快照
  M->>M: 评估窗口与运行状态
  alt 可热切
    M->>S: setModel
    S-->>R: 已生效
  else 回合中或危险缩窗
    M->>M: 登记 pending profile
    M-->>R: deferred
    S-->>M: 回合结束
    M->>M: 携带核实窗口结算
    M->>S: 应用延期选择
  else 远端空闲且必须重建
    M-->>R: 拒绝不支持的重建
  end
Loading
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/renderer/components/new-chat/ChatInput.tsx:8702
**意图期选中态混用**

跨引擎切换意图登记后,`activeModel` 已是下一条消息的目标模型,但这里仍把当前运行来源 `selectedProviderId` 与它一起传给选择器,同时面板轨固定在当前运行引擎。用户确认切换后重新打开选单时,面板因此收到“目标模型 + 旧来源 + 当前引擎”的混合状态;当前行判定要求模型、来源和引擎同时匹配,所以可能没有正确的当前行或高亮错误配置,无法停在当前正在运行的 Harness / 模型。

### Issue 2
apps/desktop/src/renderer/components/new-chat/UnifiedModelPanel.tsx:1390-1394
**收藏绕过引擎锁定**

同引擎轨只锁定普通模型行,却在这里显式放行收藏行。收藏会出现在同引擎轨中,而未锁定的浮层会列出全部候选引擎;用户点击其他引擎后,未选中的收藏会被改到别的引擎并从当前轨消失,已选中的收藏还会进入跨引擎切换事务。这破坏了本次规定的“同引擎轨不提供 Harness 切换”行为。

```suggestion
                engineLocked={effectiveRail.kind === 'engine'}
                onEngineChange={(engine) => {
                  if (effectiveRail.kind === 'engine') return;
                  applyEngine(target.anchor, target.entry, config, engine);
                }}
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(desktop): 已建任务换模型不再被窗口闸误拦,同引擎轨钉死 Har..." | Re-trigger Greptile

Comment thread apps/desktop/src/renderer/components/new-chat/ChatInput.tsx Outdated
Comment thread apps/desktop/src/renderer/components/new-chat/UnifiedModelPanel.tsx Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@zqchris 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/renderer/components/new-chat/ChatInput.tsx / apps/desktop/src/renderer/components/new-chat/UnifiedModelPanel.tsx),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

跨引擎意图期内 ModelSelector 的 currentProviderId 与 activeModel 对齐;
null 仍表示跟随默认路由。无意图时回到会话 runtime 来源。

Signed-off-by: Chris <4436110+zqchris@users.noreply.github.com>
@MagicLizi MagicLizi added status:ci-failed CI 失败(review-pr 自动维护,仅展示) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) labels Sep 4, 2026
engine rail 下收藏与普通行共用 engineLocked;跨引擎仍走全部/供应商浮层。

Signed-off-by: Chris <4436110+zqchris@users.noreply.github.com>
@MagicLizi MagicLizi added touches:large-diff 改动量较大(review-pr 自动维护,仅展示) and removed status:ci-failed CI 失败(review-pr 自动维护,仅展示) labels Sep 4, 2026
@MagicLizi

Copy link
Copy Markdown
Contributor

命中 UI 路径(apps/desktop/src/renderer/components/new-chat/ChatInput.tsx / apps/desktop/src/renderer/components/new-chat/ModelConfigFlyout.tsx / apps/desktop/src/renderer/components/new-chat/ModelSelector.tsx 等)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范

明确标注不是实机截图,页面内可切 Light/Dark,供审查 UI 路径。

Signed-off-by: Chris <4436110+zqchris@users.noreply.github.com>
@zqchris

zqchris commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

已补改动后界面证据。这是 HTML 预览,不是实机截图或录屏;页面内可切 Light / Dark。

预览:https://htmlpreview.github.io/?https://raw.githubusercontent.com/zqchris/cindy/fix/model-picker-harness-lock/docs/design-previews/model-picker-harness-lock/index.html

源文件:https://github.com/zqchris/cindy/blob/fix/model-picker-harness-lock/docs/design-previews/model-picker-harness-lock/index.html

PR description「UI 变化」已写明:本轮未启动 Desktop,未做实机 Light/Dark 目检;未覆盖跑着 Opus 5 → Cindy 打折 / Fable、Pi 轨钉死、跨引擎确认关选单。

@MagicLizi MagicLizi added status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) and removed status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) labels Sep 4, 2026

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

独立审查未通过(0 P0 / 1 P1)。当前 head 6003e9909f9439a5ad72a962d4149f67b771ee9a 不能合。

  • [P1] apps/desktop/src/main/maker-ipc/register.ts:15729 — 本机已建任务切无思考档模型会被 SET_MODEL 在入闸处直接打回。renderer composeAtomicModelSelectionefforts.length === 0 时发 { effort: null, fastMode }handleSetModel 却只在 source !== 'user'、device-link、或带 confirmedContextWindow 时放行 effort: null。本机用户第一次点选三条都不占,直接 INVALID_PARAMS: selection must contain effort + fastMode。后面「user + null 且目录有档才拒」的 catalog 检查走不到。userRuntimeModelSwitchPlan 把「跑着切无思考档 → hot-apply / effort null」写成发布保证,sessionRuntimeControlWiring 又把「本机 user null 仅限换窗重试」锁死。请让本机用户点选无思考档模型能通过入闸(有档模型的 catalog 拒绝保持)。有档模型(Opus → Cindy 打折)不受影响。

SET_MODEL 入闸不再把 user + null 挡在 catalog 检查之前;有档模型仍按
catalog efforts 拒绝。

Signed-off-by: Chris <4436110+zqchris@users.noreply.github.com>
@zqchris

zqchris commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

已修好。本机用户 SET_MODEL 入闸现在接受 { effort: null, fastMode },无思考档模型可以进既有运行时规划;有档模型仍在 catalog 检查处拒绝 effort: null。device-link 与 confirmedContextWindow 分支未改。

sessionRuntimeControlWiring 已锁住:入闸 selectionEffort !== null 才当非法档;source === 'user' && effort === null && catalogModel.efforts.length > 0 仍拒绝。pnpm test:unit:related 与 desktop typecheck 已过。

@MagicLizi
MagicLizi dismissed their stale review September 4, 2026 17:23

这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

独立审查(standard)通过:当前 head 未发现 P0/P1。已建任务换模型在未知窗口 fail-open,同引擎轨钉死 Harness;effort:null / fastMode:false 与描述一致。全部 conversation 已 resolve。

@MagicLizi
MagicLizi merged commit 696b692 into makecindy:main Sep 4, 2026
10 checks passed
@MagicLizi

Copy link
Copy Markdown
Contributor

合了。换模型被窗口闸误拦这件事用过的人都踩过,现在同引擎轨钉死 Harness,下条消息终于跟你选的那条对得上。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:large-diff 改动量较大(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants