Skip to content

fix(desktop): 右栏 detached 队列改为每会话有序 intent 组,登记命令不被后到命令顶掉 (#2409) - #2491

Closed
gardenZzz wants to merge 4 commits into
makecindy:mainfrom
gardenZzz:fix/right-sidebar-deferred-intent-queue
Closed

fix(desktop): 右栏 detached 队列改为每会话有序 intent 组,登记命令不被后到命令顶掉 (#2409)#2491
gardenZzz wants to merge 4 commits into
makecindy:mainfrom
gardenZzz:fix/right-sidebar-deferred-intent-queue

Conversation

@gardenZzz

@gardenZzz gardenZzz commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

修复 #2409:右栏处于 detached 模式且侧栏窗口关闭 / 未 ready 时,同会话的「登记类」命令(如 open-subagents-tab 历史静默登记)可能被随后同会话的另一条 allowOpen: false 的命令顶掉,导致这次登记丢失。

原因:deferredCommandsMap<hostSessionId, RsbWindowCommand>,每个会话只保留一条;enqueueDeferredCommand 直接 set 覆盖(仅对 ensure-orca-workers-tab 无参重复帧做了去重豁免)。窗口再打开时只执行后到的那条。

变更类型

  • fix 缺陷修复

范围

  • 关联 Issue:修复 右栏 detached 队列:同会话 deferred 命令互相覆盖,登记类命令可能丢失 #2409
  • 本 PR 包含:
    • deferredCommands 改为 Map<hostSessionId, RsbWindowCommand[]>:每个 host session 保留一组有序 intent,不同语义命令保序追加、绝不互相覆盖;
    • Orca 页签单例 coalescing 保持旧语义:带定位的 ensure-orca-workers-tabfocusWorkerSessionId / searchJump)覆盖尾部 ensure(最新聚焦意图胜出);无定位 generic ensure 在尾部已是 ensure 时被吸收(等价重复,或不如尾部更具体的 worker/search intent,保护具体 intent 不被抹掉);尾部是 close-orca-workers-tab 等非 ensure 命令时照常追加(ensure 在 close 后有真实语义);
    • detached / attached 两条 flush 复用同一套 drainCurrentSessionDeferred,按序全部下发,避免路径分叉;
    • 保留既有 MAX_DEFERRED_SESSIONS 跨 session 淘汰逻辑(经查证经公开 API 实际不可达——setContext 切换 session 时已清掉其它会话桶,属防御性兜底,不改动)。
  • 明确不包含:不做每会话条数上限(维护者建议若引入需明确溢出策略,当前无溢出风险,YAGNI);不改 renderer 侧 openSubagentsTab 的 attached-only 裁决语义。
  • 多端结论(docs/dev-rules/remote-and-mobile-adaptation.md § PR 门禁):
    • SSH 远程工作区:不涉及。本改动只改 Desktop main 进程右栏窗口控制器内部队列,与 agent 进程 / 文件 / 会话数据的远程通道无关。
    • device-link / 远程控制:不涉及。packages/device-link 不承载 RSB command 通道,隧道不转发该队列。
    • mobile:不涉及。apps/mobile 无右栏子窗口。
  • 用户可见变化:detached 模式下同会话多个 deferred intent(如历史 Subagent 登记 + 随后的 Orca 命令)现在都会按序执行,登记不再丢失。
  • 是否存在 breaking change:无(纯 main 层队列内部实现,命令契约未变)。

UI 变化

不涉及:纯 main 层队列内部实现 + renderer 命令串行化,无视觉/交互/文案变化。

引用的设计规范:不涉及

怎么验证的

自动验证

pnpm --filter desktop exec vitest run src/main/right-sidebar-window/__tests__/controller.test.ts
结果:PASS(45 条,含新增 6 条 #2409 回归:同会话多命令按序 flush、切 attached 按序转交、登记不丢失、ensure 定位 last-write-wins、generic 不吸收 close、context 切换整组清理)

pnpm --filter desktop run typecheck
结果:PASS

手工验证

不涉及(无 UI 变化;全量 test:unit 交由 fork client-ci 验证)。

未执行的验证

无。

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:

影响与回滚

  • 影响范围:detached 右栏窗口的 deferred 命令队列(main 层)。
  • 回滚方式:revert 本 PR 即可。

Fixes #2409

@gardenZzz
gardenZzz requested a review from a team as a code owner August 12, 2026 04:18
@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 将 detached 右栏的单命令缓存改为按会话有序 intent 队列,并增加串行消费与 ACK 推进机制。

  • 同会话的不同 deferred intent 按顺序保留和下发
  • 为 Orca ensure 与 Subagent 静默登记增加尾部合并
  • attached 与 detached 路径分别采用整桶 drain 和逐条 ACK 推进
  • 新增 preload/IPC ACK 通道及相应回归测试

Confidence Score: 3/5

该 PR 暂不宜合并,因为 deferred 命令执行失败时仍会被确认并永久移除,而且切换宿主仍可重放已完成但 ACK 尚在途的命令。

先前关于重复执行的线程虽有“已在 5fe0721 修复”的回复,但当前 HEAD 在切回 attached 时重新转交包含未 ACK 桶头的整桶;同时 renderer 在命令 rejection 后仍于 finally 发送 ACK,使未完成的 open、close 或 focus intent 无法重试。

Files Needing Attention: apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx, apps/desktop/src/main/right-sidebar-window/controller.ts

Important Files Changed

Filename Overview
apps/desktop/src/main/right-sidebar-window/controller.ts 引入按会话队列和 ACK 驱动交付,但 detached→attached 的整桶重放仍会在完成至 ACK 的窗口内重复执行桶头。
apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx 改为串行执行后发送 ACK,但 finally 无条件确认失败命令,可能永久丢失未完成的 intent。
apps/desktop/src/renderer/features/right-sidebar/lib/executeSidebarCommand.ts 新增 Promise 链以保证 renderer 内命令严格串行,并保留单条命令的 rejection 给调用方。
apps/desktop/src/main/right-sidebar-window/ipc.ts 新增仅接受当前 sidebar webContents 的 ACK handler,并将确认转交 controller。
apps/desktop/src/main/right-sidebar-window/tests/controller.test.ts 覆盖队列保序、合并、切换会话和 ACK 推进,但未覆盖 renderer 执行失败后不应确认消费的场景。

Sequence Diagram

sequenceDiagram
  participant M as Main Controller
  participant S as Detached Renderer
  participant A as Attached Renderer
  M->>S: 发送 deferred 桶头
  S->>S: 串行执行命令
  alt 执行成功
    S->>M: ACK
    M->>M: shift 桶头
  else 执行失败
    S->>S: 记录错误
    S->>M: finally 仍发送 ACK
    M->>M: shift 未成功消费的桶头
  end
  opt ACK 到达前切回 attached
    M->>A: 重放包含桶头的整桶
  end
Loading
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx:117-123
**失败命令仍被确认消费**

当 deferred 命令在页签 hydration、创建、关闭或状态写入期间执行失败时,`catch` 只记录错误,而 `finally` 仍发送 ACK;main 随后移除尚未成功消费的桶头,导致对应的打开、关闭或聚焦 intent 永久丢失且无法在重开窗口后恢复。

---

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

Reviews (7): Last reviewed commit: "fix(desktop): 切 attach 时整桶含未 ack 桶头转交主窗,..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 66b0a617d7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts
@gardenZzz
gardenZzz force-pushed the fix/right-sidebar-deferred-intent-queue branch from 66b0a61 to f7ff206 Compare August 12, 2026 04:36

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7ff2063f2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts
@gardenZzz
gardenZzz force-pushed the fix/right-sidebar-deferred-intent-queue branch from f7ff206 to 3840a04 Compare August 12, 2026 04:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3840a0413b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts Outdated
Comment thread apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@gardenZzz 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/main/right-sidebar-window/controller.ts / apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

…akecindy#2409)

detached 且侧栏窗口关闭/未 ready 时,同会话的 deferred intent 只保留一条:
enqueueDeferredCommand 直接 set 覆盖,登记类命令(如 open-subagents-tab
历史静默登记)可能被随后同会话的另一条 allowOpen:false 命令顶掉,导致
这次登记丢失。Subagent 记录本身持久化在 SQLite,重进任务会重新登记,
所以是阶段性页签入口缺失,而非数据丢失。

改为 Map<hostSessionId, RsbWindowCommand[]>,每会话保留一组有序 intent:
- 不同语义命令保序追加,绝不互相覆盖;
- Orca 页签单例 coalescing 保持旧语义:带定位的 ensure(focus/searchJump)
  覆盖尾部 ensure(最新聚焦意图胜出),无定位 generic ensure 在尾部已是
  ensure 时被吸收(等价重复,或不如尾部更具体的 worker/search intent,
  保护具体 intent 不被抹掉),尾部是 close 等非 ensure 命令时照常追加;
- Subagent 静默登记合并:SUBAGENT_TAB_REGISTER_ONLY 是固定常量
  (revealSidebar=false、无 focus 参数)。生产路径 openSubagentsTab 用
  `?? null` 写 focus 字段、IPC 保留 null,故 null 与 undefined 都视为
  「无 focus」;detached 关窗期间每次 agent_task_update 都会再次入队,
  连续等价静默登记只保留一条,避免队列无限堆积、开窗时重复执行;带
  focus 的登记与静默登记语义不同,保序保留;
- detached / attached 两条 flush 复用同一套 drainCurrentSessionDeferred
  按序全部下发,避免路径分叉。

renderer 侧串行消费:main 批量下发的 deferred intent 带顺序语义(如 close
后接 generic ensure),但 MainLayout / SidebarWindowLayout 的 onCommand
若以 void executeSidebarCommand 并发启动,close 在真正删除页签前让出
执行权、后到的 ensure 会看到旧页签直接返回,最终状态违背最新 intent。
新增 enqueueSidebarCommand:单条 promise 链把命令排成严格串行,同一
renderer 内按到达顺序逐条完成;两个 onCommand 消费点改用它。同步更新
orcaRemoteRoutingInvariants 不变量断言到 enqueueSidebarCommand。

现有 MAX_DEFERRED_SESSIONS 跨 session 淘汰保留(经查证经公开 API 实际
不可达——setContext 切换 session 时已清掉其它会话桶,属防御性兜底)。

测试:48 条 controller 单测 + 2 条 executeSidebarCommand 串行消费测试 +
orcaRemoteRoutingInvariants 全过;desktop typecheck 通过。全量 test:unit
交由 fork client-ci。

Signed-off-by: GardenX <20606485+gardenZzz@users.noreply.github.com>
@gardenZzz
gardenZzz force-pushed the fix/right-sidebar-deferred-intent-queue branch from 3840a04 to a1061e4 Compare August 12, 2026 05:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1061e4795

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts
@MagicLizi

Copy link
Copy Markdown
Contributor

此 PR 命中产品 UI 路径(MainLayout / SidebarWindowLayout / executeSidebarCommand)及核心架构路径,已自动创建维护者确认流程。

当前状态:⏳ 等待维护者确认

维护者确认方式:直接在 PR 上 Approve 即放行;如需修改请用 Request Changes,作者修改后重新 Approve 即可。

关联讨论:见下方讨论 issue。

讨论 issue:#2500

…2491)

Codex P1:drain 先删整桶再 IPC 时,串行消费者只启动首条;关窗销毁
BrowserWindow 会让未开始的尾部 intent 永久丢失。

改为 detached 路径一次只下发桶头、ack 后才 shift;关窗仅清在途标记,
桶内未确认 intent 可在重开后继续交付。attached 路径仍整桶 drain(主
renderer 常驻)。补两条关窗/重开回归与既有多命令 flush 的 ack 断言。

Signed-off-by: GardenX <20606485+gardenZzz@users.noreply.github.com>
Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c0119c9e8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts
- setDetached(false):drop 已下发未 ack 的桶头再 drain 剩余,避免子窗与主窗双执行
- routeCommand:同 session 有 deferred 在途/尾部时直播命令入同一桶,避免无参 ack 误推进
- 补两条回归:切 attached 不重发桶头;A 在途时 B 排队、C 不被误 shift

Signed-off-by: GardenX <20606485+gardenZzz@users.noreply.github.com>
Comment thread apps/desktop/src/main/right-sidebar-window/controller.ts Outdated
子窗即将销毁,其 store 与未完成 commandChain 不作数;在途未 ack 桶头
也必须 drain 给主 host,不能 drop。保留「deferred 在途时直播入桶」防
无参 ack 误推进。

Signed-off-by: GardenX <20606485+gardenZzz@users.noreply.github.com>
Comment on lines +117 to +123
void enqueueSidebarCommand(cmd)
.catch((err) => log.warn('sidebar command failed', err))
.finally(() => {
void window.electronAPI.rightSidebarWindow.ackCommand().catch((err) => {
log.warn('sidebar command ack failed', err);
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 失败命令仍被确认消费

当 deferred 命令在页签 hydration、创建、关闭或状态写入期间执行失败时,catch 只记录错误,而 finally 仍发送 ACK;main 随后移除尚未成功消费的桶头,导致对应的打开、关闭或聚焦 intent 永久丢失且无法在重开窗口后恢复。

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx
Line: 117-123

Comment:
**失败命令仍被确认消费**

当 deferred 命令在页签 hydration、创建、关闭或状态写入期间执行失败时,`catch` 只记录错误,而 `finally` 仍发送 ACK;main 随后移除尚未成功消费的桶头,导致对应的打开、关闭或聚焦 intent 永久丢失且无法在重开窗口后恢复。

---

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11563be021

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const isGeneric = command.focusWorkerSessionId === undefined && command.searchJump === undefined;
if (last?.type === 'ensure-orca-workers-tab') {
if (isGeneric) return;
bucket[bucket.length - 1] = command;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 不要用新 ensure 覆盖在途桶头

当 detached 子窗已经收到桶内唯一的 ensure-orca-workers-tab A、但尚未 ack 时,用户再触发带 worker/search 定位的 ensure B 会因 hasDetachedDeferredPending 被送到这里;此时桶仍只含作为在途头部的 A,这行会把 A 替换成 B,随后 A 的 ack 直接 shift() 掉 B,导致最新的定位请求从未下发。请只合并尚未交付的尾部,若尾部就是在途桶头则追加 B。

Useful? React with 👍 / 👎.

ipcMain.handle(MAKER_INVOKE.RSB_WINDOW_ACK_COMMAND, (event) => {
// 仅子窗口可确认 detached deferred 消费;主窗误调忽略。
const sidebarWc = controller.getSidebarWebContents();
if (!sidebarWc || event.sender !== sidebarWc) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 同时校验 ACK 的顶层 senderFrame

这个新增 IPC 只比较 event.sender,因此来自同一 sidebar WebContents 的非顶层 frame 也会被当作合法确认;一旦该 frame 能触发此通道,就可提前推进桶头并让尚未消费的 deferred intent 永久丢失。请同时要求 event.senderFrame === sidebarWc.mainFrame(或复用仓库的顶层 Renderer guard),并补充子 frame 被拒绝的测试。

AGENTS.md reference: AGENTS.md:L30-L31

Useful? React with 👍 / 👎.

@MagicLizi

Copy link
Copy Markdown
Contributor

@gardenZzz 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/renderer/components/layout/SidebarWindowLayout.tsx / apps/desktop/src/main/right-sidebar-window/controller.ts / apps/desktop/src/main/right-sidebar-window/ipc.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。

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

@gardenZzz

Copy link
Copy Markdown
Contributor Author

upstream/main 已合入等价修复:#2511fico-hub,merged 2026-08-12,关闭 #2409)。

本 PR 的核心目标(deferredCommands 从单条改为每会话有序 intent 组、登记类命令不再被后到 passive 覆盖)已由 #2511 落地;后续本 PR 上的 ack-before-shift / attach handoff 等 review 迭代不再单独推进。

关闭本 PR,避免与 main 重复/冲突。

@gardenZzz gardenZzz closed this Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-discussion 等待维护者讨论(review-pr) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

右栏 detached 队列:同会话 deferred 命令互相覆盖,登记类命令可能丢失

2 participants