fix(coding-agent): corrected TTSR violations aborting subagent runs

- Fixed TTSR violations during subagent execution aborting the entire subagent run; `#waitForPostPromptRecovery()` now awaits agent idle after TTSR/retry gates resolve, preventing `prompt()` from returning while fire-and-forget `agent.continue()` is still streaming.
- Added comprehensive test case verifying `prompt()` blocks until TTSR continuation with tool calls completes, preventing premature session disposal.
This commit is contained in:
can1357
2026-02-28 05:27:45 +01:00
parent 18bcd28152
commit b0dc5f6869
3 changed files with 156 additions and 5 deletions
@@ -732,18 +732,31 @@ export class AgentSession {
}
/**
* Wait for both retry and TTSR resume to settle.
* Loops because a TTSR continuation can trigger a retry (or vice-versa).
* Wait for retry, TTSR resume, and any background continuation to settle.
* Loops because a TTSR continuation can trigger a retry (or vice-versa),
* and fire-and-forget `agent.continue()` may still be streaming after
* the TTSR resume gate resolves.
*/
async #waitForPostPromptRecovery(): Promise<void> {
while (this.#retryPromise || this.#ttsrResumePromise) {
while (true) {
if (this.#retryPromise) {
await this.#retryPromise;
continue;
}
if (this.#ttsrResumePromise) {
await this.#ttsrResumePromise;
continue;
}
// A TTSR continuation (fire-and-forget agent.continue()) may still be
// streaming after the resume gate resolved on its first assistant
// message_end. Without this check, prompt() returns while the agent
// is still processing tool calls, causing subagent executors to hit
// AgentBusyError and dispose the session prematurely.
if (this.agent.state.isStreaming) {
await this.agent.waitForIdle();
continue;
}
break;
}
}