fix(acp): clear cronBusyGuard and status on sendMessage failure#1700
fix(acp): clear cronBusyGuard and status on sendMessage failure#1700piorpua merged 7 commits intoiOfficeAI:mainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
a405920 to
64feea7
Compare
7bffd5c to
456e511
Compare
Remove finish signal emission (covered by PR iOfficeAI#1709) and keep only the cronBusyGuard/status cleanup on sendMessage failure, which iOfficeAI#1709 does not address. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
456e511 to
54356eb
Compare
…p branches
Tests instantiate the real AcpAgentManager (with BaseAgentManager mocked to
avoid ForkTask process spawning) and verify that both sendMessage paths
(first-message and subsequent-message) correctly clear cronBusyGuard and set
status='finished' when agent.sendMessage() returns {success:false}.
Covers lines 645-648 and 657-660 added in the preceding commit to fix
the perpetual busy/running state on timeout.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
JiwaniZakir
left a comment
There was a problem hiding this comment.
The fix covers the !result.success return path, but the diff shows a catch (e) block immediately after the second cleanup — it's not visible whether that handler also calls cronBusyGuard.setProcessing(this.conversation_id, false) and resets this.status. If agent.sendMessage throws rather than returning {success: false}, the guard could still end up stuck, which is the same class of bug this PR is fixing.
The two new blocks are also identical — cronBusyGuard.setProcessing(this.conversation_id, false); this.status = 'finished'; — and a small private helper (e.g. private clearBusyState()) would reduce the duplication and make future changes (like adding telemetry or logging on failure) easier to apply consistently.
On the test side, the "subsequent-message path" comment says it's "triggered when msg_id is absent," but the production code distinction appears to be about isFirstMessage, not msg_id presence — the comment could mislead someone maintaining these tests later. It would also strengthen coverage to add a test asserting that a thrown exception from agent.sendMessage (not just a {success: false} return) still results in setProcessing(false) being called, assuming the catch block is intended to do that.
- Replace three identical cronBusyGuard/status cleanup blocks with a private clearBusyState() helper method - Fix misleading test comment: path is triggered by isFirstMessage, not msg_id absence - Add two tests covering the thrown-exception (catch) path to ensure setProcessing(false) and status='finished' are called on throws
|
Thanks for the detailed review, @JiwaniZakir! On the catch block: The catch block already had On duplication: Good call. I've extracted a private On the test comment: Fixed — updated to reference On throw-path test coverage: Added two new tests asserting that a thrown exception from |
…ath tests resolve
|
The fix looks correct — clearing |
|
Good questions — here's the breakdown: On the finally-style guarantee: The entire On second-message coverage: Added a new test ( |
|
The cleanup logic looks correct — resetting |
Code Review:fix(acp): clear cronBusyGuard and status on sendMessage failure (#1700)变更概述本 PR 修复了 方案评估结论:✅ 方案合理 提取 问题清单🟡 MEDIUM —
|
| # | 严重级别 | 文件 | 问题 |
|---|---|---|---|
| 1 | 🟡 MEDIUM | tests/unit/acpAgentTimeoutFinish.test.ts |
测试手写 stub 而非真实 AcpAgentManager,存在错误的覆盖信心 |
| 2 | 🔵 LOW | tests/unit/acpAgentManagerCronGuard.test.ts |
15 处 no-explicit-any / no-extraneous-class lint 警告 |
| 3 | 🔵 LOW | tests/unit/acpAgentTimeoutFinish.test.ts |
3 处 no-explicit-any / no-extraneous-class lint 警告 |
结论
clearBusyState() 的提取干净合理,acpAgentManagerCronGuard.test.ts 对真实类的测试质量良好。建议移除或修正 acpAgentTimeoutFinish.test.ts(MEDIUM 问题),并补充修复 lint 警告,之后可合并。
本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。
|
Good questions — here's the analysis: On race conditions: There is no async gap. JS's single-threaded event loop means that from the point On the assumption that
This means the catch block in |
|
The |
- Remove acpAgentTimeoutFinish.test.ts: tested a hand-written stub instead
of the real AcpAgentManager class, providing false coverage confidence
- Fix no-explicit-any lint warnings in acpAgentManagerCronGuard.test.ts:
replace `any` with `unknown`/precise types, use `as unknown as T` for
private property access, replace empty `class {}` mock with `vi.fn()`
Review follow-up for #1700
- Remove acpAgentTimeoutFinish.test.ts: tested a hand-written stub instead
of the real AcpAgentManager class, providing false coverage confidence
- Fix no-explicit-any lint warnings in acpAgentManagerCronGuard.test.ts:
replace `any` with `unknown`/precise types, use `as unknown as T` for
private property access, replace empty `class {}` mock with `vi.fn()`
Review follow-up for #1700
Problem
When
AcpAgent.sendMessage()fails (e.g. after a prompt timeout),AcpAgentManagernever clearedcronBusyGuardor resetthis.status. This left the conversation stuck in a perpetually "busy" state, causing:cronBusyGuardthinks the conversation is still processing)Fix
After
agent.sendMessage()returns{success: false}, immediately clearcronBusyGuardand resetstatusto'finished'at both call sites inAcpAgentManager.sendMessage().Test plan
tests/unit/acpAgentTimeoutFinish.test.ts🤖 Generated with Claude Code