fix(pool): emit the quota/auth PAUSE notice once, not once per parallel agent

A single out-of-credit event (Anthropic's 400 "credit balance too low", which
is_exhaustion correctly classifies) made every in-flight parallel agent print
its own "PAUSED — /continue" line, flooding the console with identical notices.
Now only the agent that wins the paused false->true transition emits the notice;
the rest park quietly. Resume clears the flag so the next episode notices again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUPandClaude Opus 4.8 committed 2026-10-02 19:01:32 -03:00
1 parent efc687c1e4
commit 1bfaf1837c
1 file changed
+11 -1
+11 -1
View File
@@ -229,7 +229,16 @@ impl ModelPool {
/// emit a notice, and wait until the user runs `/continue` (or cancels).
/// Returns when the run should retry (pause cleared) or give up (cancelled).
async fn park_exhausted(&self, err: &anyhow::Error, is_auth: bool) {
self.paused.store(true, Ordering::Relaxed);
// Only the agent that actually flips the run into the paused state
// emits the notice. Without this, every in-flight parallel agent that
// hits the same exhaustion prints its own "PAUSED — /continue" line, so
// a single out-of-credit event floods the console with identical
// notices. The losers of the transition just wait quietly below.
let first = self
.paused
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.is_ok();
if first {
if let Some(tx) = self.progress() {
let msg = format!("{err:#}");
let short = msg.lines().next().unwrap_or(&msg);
@@ -247,6 +256,7 @@ impl ModelPool {
};
let _ = tx.send(notice).await;
}
}
while self.paused.load(Ordering::Relaxed) && !self.is_cancelled() {
let notified = self.resume.notified();
tokio::select! {