fix: 修复手动停止后立即继续导致双 session 并发运行的竞态 bug#196
Merged
ErlichLiu merged 2 commits intoErlichLiu:mainfrom Apr 7, 2026
Merged
Conversation
通过 generation 时间戳区分同一会话的不同运行轮次,解决旧流的 STREAM_COMPLETE 和 finally 清理误伤新流状态的竞态问题。
Agent/SubAgent 的 cwd 是会话目录而非项目源码目录,导致使用 Glob/Grep 等工具时 若用相对路径会在第一次调用失败,然后 fallback 到 Bash 命令浪费一轮调用。 在工具使用指南中增加路径规则提醒,要求操作附加工作目录时必须使用绝对路径。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
问题
手动停止正在运行的任务后,立即发送"继续"消息,会导致两个 session 同时在后端运行,表现为每次发送消息都同时触发两个会话。
日志审查发现
通过分析会话
50c759b0的 JSONL 日志,确认了双流并发的实际证据:根因
两个竞态条件叠加导致:
前端竞态:
handleStop立即将running设为false,用户发"继续"触发新流(running=true)。旧流 abort 后的STREAM_COMPLETE延迟到达前端,无条件将running重置为false—— 把新流的状态打掉了。前端误认为"已完成",用户再次操作即可触发第三个流。后端竞态:旧流的
finally块执行activeSessions.delete(sessionId),误删了新流刚注册的条目,导致后端并发守卫(activeSessions.has(sessionId))失效。修复
核心思路:给每次
sendMessage调用分配一个 generation 时间戳,前后端都用它区分新旧流。后端(agent-orchestrator.ts)
activeSessions从Set<string>改为Map<string, number>,value 为 generation 时间戳finally块只在 generation 匹配时才清理,防止旧流误删新流的注册onComplete回调传递startedAt: runGenerationIPC 层(agent-service.ts)
runAgent和runAgentHeadless的onComplete都转发startedAt到前端前端(useGlobalAgentListeners.ts)
STREAM_COMPLETEhandler 通过比较startedAt区分新旧流startedAt比 complete 事件的更新,说明是旧流的 complete,忽略不处理类型(@proma/shared agent.ts)
AgentStreamCompletePayload增��startedAt?: number字段附加修复:SubAgent 首次工具调用路径错误
问题
Agent/SubAgent 启动后,首次使用 Glob/Grep 等工具搜索附加工作目录中的文件时,经常因使用相对路径而失败(cwd 是会话目录而非项目源码目录),然后 fallback 到 Bash 命令用绝对路径重试,浪费一轮工具调用。
修复
在
agent-prompt-builder.ts的工具使用指南中增加一条路径规则提醒,明确告知 Agent:cwd 是会话目录,操作附加工作目时必须使用绝对路径。代码审查
activeSessions用法与Map兼容(has/delete/size/clear签名一致)callbacks.onComplete调用均已传递startedAtstartedAt防护条件做了兜底:即使data.startedAt缺失(未来遗漏路径),只要当前流有startedAt也能防护影响范围
5 个文件,27 行新增 / 14 行删除。竞态保护逻辑不影响正常的发送、停止、流式推送等功能;提示词改动仅影响 Agent 工具调用行为。