feat(web_ui): defer operator /compact to turn end, run when idle too
This commit is contained in:
parent
80d819e444
commit
faa7f982af
5 changed files with 77 additions and 79 deletions
|
|
@ -150,8 +150,9 @@ pub enum TurnOutcome {
|
|||
/// as `result_kind = "compacted"` in turn stats so the stats page can
|
||||
/// distinguish normal turns from turns that triggered a compaction.
|
||||
Compacted,
|
||||
/// claude saw "Prompt is too long" — the session needs compacting.
|
||||
/// Run `compact_session()` then retry the same wake-up prompt.
|
||||
/// claude saw "Prompt is too long" and even a reactive compact + retry
|
||||
/// (inside [`InfiniteSession::run`]) couldn't bring it back under the
|
||||
/// window. Rare; the serve loop treats it like `Ok` (acks the turn).
|
||||
PromptTooLong,
|
||||
/// The Anthropic API refused the request due to a rate limit, per-account
|
||||
/// usage cap, or exhausted credit balance. The serve loop should park for
|
||||
|
|
@ -282,7 +283,7 @@ pub async fn drive_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutco
|
|||
});
|
||||
result = session.run(&config, prompt, &sink).await;
|
||||
}
|
||||
match result {
|
||||
let outcome = match result {
|
||||
Ok(progress) => {
|
||||
if progress.created {
|
||||
// Fresh session minted this turn → flag it so the bin loop
|
||||
|
|
@ -299,7 +300,19 @@ pub async fn drive_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutco
|
|||
}
|
||||
}
|
||||
Err(e) => error_to_turn(e),
|
||||
};
|
||||
// Operator `/compact` (`POST /api/compact`) deferred to the turn boundary:
|
||||
// run it now that the turn is done, so it works mid-turn rather than only
|
||||
// when the agent is idle. Only on a healthy turn — no point spawning a
|
||||
// compaction after a rate-limited / auth-failed / crashed one.
|
||||
if bus.take_compact() && matches!(outcome, TurnOutcome::Ok | TurnOutcome::Compacted) {
|
||||
bus.emit(LiveEvent::Note {
|
||||
text: "operator: /compact — running at turn end".into(),
|
||||
});
|
||||
let _ = session.compact(&config, &sink).await;
|
||||
return TurnOutcome::Compacted;
|
||||
}
|
||||
outcome
|
||||
}
|
||||
|
||||
/// Pre-turn auto-reset check. If context is large AND the prompt cache has
|
||||
|
|
@ -377,30 +390,32 @@ pub fn emit_turn_end(bus: &Bus, outcome: &TurnOutcome) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Operator-initiated `/compact` on the durable session (from the web UI).
|
||||
/// Resume-only via [`InfiniteSession::compact`]: a missing session is a
|
||||
/// harmless no-op (never mints an empty session just to compact it). Surfaces
|
||||
/// the result as a Note and the usual `TurnOutcome`.
|
||||
pub async fn compact_session(files: &TurnFiles, bus: &Bus) -> TurnOutcome {
|
||||
/// Service a pending operator `/compact` (`Bus::request_compact`) while the
|
||||
/// agent is idle — the serve loop calls this when a `recv` returns no message,
|
||||
/// so a queued `/compact` runs even when no turn is driving. (The in-flight
|
||||
/// case is handled at the end of [`drive_turn`].) Resume-only via
|
||||
/// [`InfiniteSession::compact`]: a missing session is a harmless no-op. Returns
|
||||
/// `true` if a compaction ran.
|
||||
pub async fn run_pending_compact(files: &TurnFiles, bus: &Bus) -> bool {
|
||||
if !bus.take_compact() {
|
||||
return false;
|
||||
}
|
||||
bus.emit(LiveEvent::Note {
|
||||
text: "running /compact on the session".into(),
|
||||
text: "operator: /compact — running on idle session".into(),
|
||||
});
|
||||
bus.set_state(crate::events::TurnState::Compacting);
|
||||
let config = claude_config(bus, files);
|
||||
let sink = BusSink::new(bus);
|
||||
match infinite_session(bus).compact(&config, &sink).await {
|
||||
Ok(()) => {
|
||||
bus.emit(LiveEvent::Note {
|
||||
text: "/compact done".into(),
|
||||
});
|
||||
TurnOutcome::Compacted
|
||||
}
|
||||
Err(e) => {
|
||||
bus.emit(LiveEvent::Note {
|
||||
text: format!("/compact failed: {e}"),
|
||||
});
|
||||
error_to_turn(e)
|
||||
}
|
||||
Ok(()) => bus.emit(LiveEvent::Note {
|
||||
text: "/compact done".into(),
|
||||
}),
|
||||
Err(e) => bus.emit(LiveEvent::Note {
|
||||
text: format!("/compact failed: {e}"),
|
||||
}),
|
||||
}
|
||||
bus.set_state(crate::events::TurnState::Idle);
|
||||
true
|
||||
}
|
||||
|
||||
/// The constant session title for this agent. `HIVE_SESSION_TITLE` overrides
|
||||
|
|
|
|||
Loading…
Reference in a new issue