Skip to content

修复(OMP):终端原生 Ask 与 CodeIsland 并行回答#264

Open
haixing23 wants to merge 5 commits into
wxtsky:mainfrom
haixing23:fix/omp-native-ask-race
Open

修复(OMP):终端原生 Ask 与 CodeIsland 并行回答#264
haixing23 wants to merge 5 commits into
wxtsky:mainfrom
haixing23:fix/omp-native-ask-race

Conversation

@haixing23

@haixing23 haixing23 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

关联

问题背景

#244 已支持从 CodeIsland 回填 OMP ask 的答案,但旧实现会在 tool_call handler 中阻塞等待 CodeIsland。等待期间 OMP 原生终端选择框尚未打开,因此用户只能在 CodeIsland 回答;若问题卡未展开,就会出现双方都无法操作的状态。

本 PR 改为真正的双入口竞速:终端原生 Ask 与 CodeIsland 同时可答,先完成的一端生效并取消另一端。

修改内容

1. 原生 Ask 与 CodeIsland 并行竞速

  • 扩展注册同名 ask,同时调用 OMP 内置 AskTool 和 CodeIsland bridge;
  • 复用原生终端渲染、多问题导航、超时和推荐项;
  • first-writer-wins settlement 幂等处理相邻 microtask 完成,避免双重回调;
  • 终端 Esc、CodeIsland 跳过、外部取消或任一端失败都会清理另一端,不再留下 24 小时等待;
  • CodeIsland/bridge 不可用或返回畸形答案时保留原生 TUI,问题不会丢失。

2. 严格校验并结构化回填答案

  • 仅接受覆盖本次所有预期 answer key 的有效回答;错 key、部分回答、空回答和非字符串数组均降级到原生 TUI;
  • 分别保留 selectedOptionscustomInput 与多选结果;
  • 问题标题优先使用 OMP header,缺失时回退到必填 id

3. Smart Suppress 与旧入口兼容

  • 仅带 _codeisland_native_ask_racing: true 标记的新 OMP 请求允许 Smart Suppress 折叠;
  • Pi 和旧版 OMP 仍强制展开,避免没有原生并行 Ask 时的问题卡死锁;
  • 队列提升时重新计算展示状态,不覆盖用户已打开的 session list。

4. 自动升级 extension

OMP extension 升级到 v6。CodeIsland 会把已安装的 v2v5 自动覆盖为当前版本;测试验证旧文件确实被重写。

5. 共享 UI 与事件关联修复

  • multiSelect=true 且无预设选项时显示可用的纯文本提交按钮;
  • HookEvent.toolUseId 增加 _pi_tool_call_id,同时保留上游 ZCode 的 toolCallId

降级行为

场景 结果
CodeIsland 未运行 / bridge 不可用 OMP 原生 Ask 正常工作
用户先在终端回答 取消 CodeIsland 等待,终端答案返回 agent
用户先在 CodeIsland 回答 取消原生 Ask,结构化答案返回 agent
CodeIsland 返回空、错 key 或部分答案 忽略无效结果,继续等待原生 TUI
Pi / 旧版 OMP 继续强制展开 CodeIsland 问题卡

验证

  • Swift 定向回归:94/94 通过(21 + 64 + 9)
  • Bun OMP race 回归:7/7 通过,18 个断言
  • TypeScript tsc --noEmit 类型检查:通过
  • TypeScript bundle/语法检查:通过
  • release app 构建:通过
  • 真实 OMP 17.0.4 双入口冒烟:
    • CodeIsland 停止时,终端选择 Beta,得到 FINAL_TUI_V2=Beta
    • CodeIsland 运行时,问题卡选择 Beta,OMP 得到 FINAL_ISLAND_V2=Beta
    • 问题卡显示缺省 header 回退后的 final_island_v2
  • 独立代码复审:无剩余 blocking / important finding。
swift test --scratch-path /tmp/codeisland-swift-tests \
  --filter 'AppStateQuestionFlowTests|ConfigInstallerTests|HookEventToolUseIdTests' \
  -Xswiftc -Xfrontend -Xswiftc -enable-constraint-solver-performance-hacks

bun test Tests/CodeIslandOmpExtensionTests/codeisland-omp-race.test.ts

bun x tsc --noEmit --strict --skipLibCheck --moduleResolution bundler \
  --module esnext --target esnext --types node --lib esnext,dom \
  Sources/CodeIsland/Resources/codeisland-omp.ts

Register a shadow 'ask' tool that concurrently starts OMP's built-in
AskTool (terminal rendering, navigation, timeout, multi-question wizard)
and a blocking CodeIsland AskUserQuestion. Whichever side returns a real
answer first wins; the loser is cancelled immediately.

This replaces the previous flow where the extension handler blocked
inside tool_call until CodeIsland answered, delaying the terminal dialog
(wxtsky#244 -> wxtsky#256). Users can now answer from either the terminal or the
CodeIsland/iPhone/Watch UI without waiting for a handler timeout.

Key changes:
- Shadow ask reuses pi.pi.AskTool for its executor and LLM-facing
  label/description, preserving OMP's behavioral guidance.
- Bridge request carries _codeisland_native_ask_racing so AppState can
  scope Smart Suppress: only OMP requests with this marker may stay
  collapsed when the terminal is frontmost. Pi and legacy OMP keep the
  forced-expand fallback from wxtsky#256.
- Genuine native AskTool failure cancels the island bridge and
  propagates immediately instead of waiting for a 24h island timeout.
- Structured answer details (selectedOptions, customInput) are passed
  back via _codeislandAnswerDetails, scoped to pi source + toolUseId.
- QuestionBar preserves selectedOptions/customInput for all sources;
  non-OMP paths still consume the original answer string unchanged.
- multiSelect=true with empty/no options now shows a usable Submit
  button for free-text input (shared fix).
- HookEvent parses _pi_tool_call_id for OMP tool call correlation.
- OMP extension version bumped v2 -> v4.
- Native AskTool reuse probe, 20 AppStateQuestionFlowTests, and 9
  HookEventToolUseIdTests all pass.
P1: When Smart Suppress kept the CodeIsland ask card collapsed, a native
TUI cancel (Esc) returned null but the gate still waited for the hidden
island bridge (24h timeout). Now any side finishing — answer, skip,
cancel, or failure — immediately cancels the other and settles. No more
per-side done/failed tracking; settle() is idempotent.

Smart Suppress: showNextPending() left an inherited .questionCard surface
expanded when the promoted OMP ask should be collapsed. Now folds it to
.collapsed (but never touches .sessionList).

Also: reuse native AskTool label/description instead of a one-liner;
remove dead tuiFailed/tuiError code paths; add regression test for
non-OMP -> OMP mixed-source queue promotion.
@haixing23
haixing23 marked this pull request as draft July 15, 2026 10:43
nguyenvanduocit pushed a commit to nguyenvanduocit/CodeIsland that referenced this pull request Jul 16, 2026
Upstream quiet since v1.0.30 (Jul 10). One new watch item:
- T-076: panel intermittently shifts from notch to upper-left corner
  on macOS 27.0 beta (issue wxtsky#263, M5 Pro, no upstream fix yet)

Skip: PR wxtsky#264 (OMP), PR wxtsky#262 (Cursor Tasks), issue wxtsky#265 (Cursor) —
all non-Claude CLIs or Cursor-specific.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P5RZPP2LLwKBjbXuqKxDjf
@wxtsky

wxtsky commented Jul 23, 2026

Copy link
Copy Markdown
Owner

方向确认:认可 racing 方案,「终端和 CodeIsland 同时可答、先答者生效」正是这里想要的终态,比 #256 的强制展开更贴合 Smart Suppress 的语义,不必等 OMP 官方扩展接口。

标 ready 前请确保三点:

  1. settle 幂等的并发测试——两端几乎同时返回时只有一个答案生效、另一端取消不抛错(PR 描述说已做,希望看到对应测试用例);
  2. 旧版扩展兼容——v2/v3 用户升级后自动重装到 v4 的路径已验证(版本 marker 检测逻辑这次改为读文件内容,需要测试覆盖「旧 marker → 触发重写」);
  3. pi(legacy) 阻塞行为不回归——你已经用 _codeisland_native_ask_racing 区分了,保持 pi 不 racing 的现状即可。

另外 normalizedSupportedSource 把 omp 归并进 "pi" 的前提下,AppState 里 source != "pi" 的判断对两者一起生效——如果未来 pi 本体也支持 racing,这个标志位设计是对的。期待标 ready。

@haixing23 haixing23 changed the title 修复(OMP):终端原生 Ask 与 CodeIsland 并行回答 修复(OMP):终端原生 Ask 与 CodeIsland 并行回答 Jul 23, 2026
@haixing23
haixing23 marked this pull request as ready for review July 23, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants