turn: propagate auth_failed out of compact_session

This commit is contained in:
damocles 2026-05-25 21:59:11 +02:00
commit c8120f9edc

View file

@ -306,9 +306,13 @@ pub async fn drive_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutco
maybe_auto_reset(bus);
let outcome = match run_turn(prompt, files, bus).await {
TurnOutcome::PromptTooLong => {
if let Err(e) = compact_session(files, bus).await {
tracing::warn!(error = %format!("{e:#}"), "compact failed");
return TurnOutcome::Failed(e);
match compact_session(files, bus).await {
Ok(true) => return TurnOutcome::AuthFailed,
Ok(false) => {}
Err(e) => {
tracing::warn!(error = %format!("{e:#}"), "compact failed");
return TurnOutcome::Failed(e);
}
}
run_turn(prompt, files, bus).await
}
@ -370,11 +374,17 @@ async fn maybe_checkpoint_and_compact(files: &TurnFiles, bus: &Bus) -> bool {
text: format!("checkpoint turn failed ({e:#}) — compacting anyway"),
}),
}
if let Err(e) = compact_session(files, bus).await {
tracing::warn!(error = %format!("{e:#}"), "post-checkpoint compact failed");
bus.emit(LiveEvent::Note {
text: format!("/compact after checkpoint failed: {e:#}"),
});
match compact_session(files, bus).await {
Ok(true) => bus.emit(LiveEvent::Note {
text: "/compact hit 401 — next turn will trigger the re-login flow".into(),
}),
Ok(false) => {}
Err(e) => {
tracing::warn!(error = %format!("{e:#}"), "post-checkpoint compact failed");
bus.emit(LiveEvent::Note {
text: format!("/compact after checkpoint failed: {e:#}"),
});
}
}
true
}
@ -506,19 +516,31 @@ pub async fn run_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutcome
/// compact state matches a normal turn's. Only the prompt over stdin
/// differs (`/compact` vs the wake-up payload).
///
/// Returns `true` if claude reported a 401 mid-compact — the caller
/// should bail into the re-login flow instead of treating compaction
/// as succeeded. (`prompt_too_long` / `rate_limited` are unlikely on
/// a slash command and are folded into the boolean by being ignored
/// — the next real turn surfaces them through the normal path.)
///
/// # Errors
///
/// Returns an error if the `claude --print /compact` invocation fails
/// (non-zero exit or I/O error).
pub async fn compact_session(files: &TurnFiles, bus: &Bus) -> Result<()> {
pub async fn compact_session(files: &TurnFiles, bus: &Bus) -> Result<bool> {
bus.emit(LiveEvent::Note {
text: "context overflow — running /compact on the persistent session".into(),
});
let (_, _, _) = run_claude("/compact", files, bus).await?;
bus.emit(LiveEvent::Note {
text: "/compact done".into(),
});
Ok(())
let (_, _, auth_failed) = run_claude("/compact", files, bus).await?;
if auth_failed {
bus.emit(LiveEvent::Note {
text: "/compact hit 401 — bubbling up for re-login flow".into(),
});
} else {
bus.emit(LiveEvent::Note {
text: "/compact done".into(),
});
}
Ok(auth_failed)
}
#[allow(clippy::too_many_lines)]