Fix nested Claude Code session detection and centralize provider availability checks

Strip parent Claude Code session env vars (CLAUDECODE, CLAUDE_CODE_ENTRYPOINT, etc.)
from child agent environments so spawned agents don't fail with "cannot be launched
inside another Claude Code session". Centralize isProviderAvailable to check both
binary and credential availability. Add red e2e test for send-during-tool-call bug
and force-cancel stale foreground turns in cancelAgentRun.
This commit is contained in:
Mohamed Boudra
2026-03-25 16:00:24 +07:00
parent 81ee887d03
commit c4782ec71c
14 changed files with 321 additions and 45 deletions
@@ -1388,6 +1388,28 @@ export class AgentManager {
await Promise.race([pendingRun.settledPromise, timeout]);
}
// If the foreground turn is still stuck after the timeout, force-dispatch a
// synthetic turn_canceled so the normal event pipeline cleans up
// activeForegroundTurnId, settles waiters, and unblocks the streamForwarder.
if (foregroundTurnId && agent.activeForegroundTurnId === foregroundTurnId) {
this.logger.warn(
{ agentId, foregroundTurnId },
"cancelAgentRun: foreground turn still active after timeout, force-canceling",
);
this.dispatchSessionEvent(agent, {
type: "turn_canceled",
provider: agent.provider,
reason: "interrupted",
turnId: foregroundTurnId,
});
// The synthetic event unblocks the streamForwarder generator, whose finally
// block settles the pending foreground run asynchronously. Wait for it.
const staleRun = this.getPendingForegroundRun(agentId);
if (staleRun && !staleRun.settled) {
await staleRun.settledPromise;
}
}
// Clear any pending permissions that weren't cleaned up by handleStreamEvent.
if (agent.pendingPermissions.size > 0) {
for (const [requestId] of agent.pendingPermissions) {