Conversation
- 修复 usePermissionHandler 的权限与提问回复回调:空依赖数组把 serverId 冻结在首次渲染的值上,切换服务器后回复被发到旧服务器,表现为弹窗消失又复现、对话不前进 - 补齐 useChatSession 中 paneServerId 依赖:SSE 回调、agents 列表、@ 目录与斜杠命令预取、待处理请求刷新、发送消息、fork、中止、命令执行、归档 - 补齐其余服务器作用域单元的 serverId 依赖:useFileExplorer、BottomPanel、RightPanel、SessionChangesPanel、Terminal、ProjectDialog、SessionChildrenSlot - 新增回归测试:断言面板切换服务器后权限与提问回复打到当前服务器;该测试在修复前会失败 - 校验:typecheck、eslint src、vitest --dir src(92 文件 / 596 用例)、build 全部通过
task 工具匹配子/孙 session 的权限与提问卡片时,把消息 metadata 里的原始 session id 交给 splitSessionKey;该函数遇到不带 :: 前缀的 id 会回退到全局 活动服务器。多服务器 / WSL 场景下面板绑定的服务器与活动服务器不是同一台, 孙层请求因此永远匹配不上,卡片点不动。 - InlineToolRequestContext: 新增 TaskChildSessionRef(子 session key + 权威 serverId),context 值补必填 serverId,复合 key 由它合成,不再猜服务器 - ChatPane: 把 paneServerId 发布进 context,并补进 memo 依赖 - ToolPartView / MessageRenderer: 调用点透传 serverId - 新增契约测试:活动服务器为 local、面板绑定 wsl:Ubuntu 时,孙层的权限与 提问必须能命中
该用例挂载完整 ConfigSettings 与配置编辑器弹窗,是 jsdom 下最重的路径之一: 单跑 0.5 秒通过,但全量并发跑会超过 5 秒默认 testTimeout 被误判为失败。 给它单独设 20 秒并写明原因,断言与流程都未改动。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
起因
我在 Windows 上主力用 WSL 跑 opencode,也在做 WSL 服务器管理那个 PR(#164)。用着用着发现一个很别扭的问题:在 WSL 的对话里,模型一提问(带选项的卡片),卡片能正常显示,但不管我选选项、输入自己的回答还是跳过,都点不动——点完卡片会消失一下(像发送成功了),过一会儿又冒出来,对话也不往前走。权限确认弹窗其实也一样,只是我没第一时间反应过来是同一回事。
排查过程
我让 AI 排查了这个问题,重点是「面板绑定的服务器」这条线:
paneServerId)在面板生命周期里会变——启动时活动服务器是 local,WSL sidecar 就绪后wslStore才把活动服务器切过去;切换会话当然也会变。而面板本身不会重挂(key 只是 paneId)。usePermissionHandler里三个回复回调(权限回复、提问回复、提问跳过)的依赖数组是空的[],serverId被冻在面板首次渲染时的值上。同一个 hook 里的refreshPendingRequests却是[serverId](每次拿新值)——这一新一旧的不对称,正好解释「卡片消失又回来」。renderHook,先local再rerender成wsl:Ubuntu,然后分别调用三个函数,把各自收到的 serverId 打出来):数据出来就对上了:卡片显示走 SSE(按服务器分别订阅,是对的),回复走 HTTP(用的是旧 serverId,发到 local 报错),于是 WSL 那条请求一直 pending,刷新一拉就"复活"。探针脚本用完删掉了。
react-hooks/exhaustive-deps扫全仓:同类漏声明serverId的地方一共 29 条告警(还有 1 处规则看不到但同样会漏:useChatSession的 SSE 回调)。逐个判断了哪些真会把请求打到旧服务器(被routeSessionId守卫的那几处不会,因为那种情况下paneServerId是它的纯函数),然后一起修掉。splitSessionKey,而这个函数碰到不带::前缀的 id 会直接回退到「全局活动服务器」。于是子 agent 再起一层子 session 时,只要活动服务器和面板绑定的服务器不是同一台,那张卡片就永远匹配不上——和前面是同一个根因,只是换了个入口。修法是把权威 serverId 从面板一路传下来,而不是让匹配器去猜。修复内容
usePermissionHandler:三个回复回调的依赖数组[]→[serverId],并在 hook 上写明约定「凡发起请求的回调都必须声明 serverId」useChatSession:补齐paneServerId依赖——SSE 回调、agents 列表、@ 目录与斜杠命令预取、待处理请求刷新、发送消息、fork、中止、执行命令、归档;同时把这条约定写进paneServerId定义处的注释(并标注例外:被routeSessionId守卫的单元)useFileExplorer(4)、BottomPanel(4)、SessionChangesPanel(3)、SessionChildrenSlot(3)、ProjectDialog(2)、RightPanel(1)、Terminal(1)InlineToolRequestContext新增TaskChildSessionRef(子 session key + 面板绑定的权威 serverId),context 值加上必填serverId,复合 key 用它合成,不再走splitSessionKey的「裸 id 回退活动服务器」;ChatPane把paneServerId发布进 context,ToolPartView/MessageRenderer跟着透传local切到wsl:Ubuntu后,回复与跳过必须打到wsl:Ubuntu;活动服务器是local而面板绑定wsl:Ubuntu时,子 agent 下一层会话的权限/提问卡片必须能匹配上。两条都是把修复回退就会红的(前者AssertionError: expected "vi.fn()" to be called with …,后者expected undefined to be { id: 'perm-1', … })验证
src下 0 错误 / 43 警告(与改动前基线一致);该类 serverId 漏声明告警 29 → 0question,点一个选项,看那条 POST 打到哪个端口——修复前是127.0.0.1:4096(local)并报错,修复后是 WSL sidecar 的随机端口且 200。子 agent 那条路径同理:在别的服务器上开会话跑一个会再下一层的 task,看孙层卡片能不能点动ConfigSettings.search.test.tsx挂了完整 ConfigSettings 和配置编辑器弹窗,单跑 0.5 秒,但全量并发跑会超过 5 秒默认testTimeout被误判超时(我这边一加测试文件就复现)。给它单独放宽到 20 秒并写了注释,断言没动。这一步是独立的 commit,跟上面的修复无关,觉得不合适可以只挑第一个小提示:我本机上有个未跟踪的
opencode/参考目录会被eslint .和 vitest 扫到(它只在 WSL 分支的 cfd5ce6 里被排除),所以本地验证用的是eslint src和vitest --dir src;CI 全新 clone 不受影响。说明
这个缺陷的引入点是 main 里已有的多服务器提交(
75a00b64),不是 #164 带来的,WSL 只是最容易触发它的场景(活动服务器是异步切过去的),所以我单独开了这个 PR,而不是塞进 #164。Fixes #168