fix(hive-claude): report Progress.created on first-turn overflow, compacted only when compact succeeded
This commit is contained in:
parent
216eb8ae9b
commit
dd51d02bc2
1 changed files with 32 additions and 16 deletions
|
|
@ -66,19 +66,25 @@ impl<P: CompactionPolicy> InfiniteSession<P> {
|
|||
/// [`Error::PromptTooLong`]; rate-limit / auth / hard failures propagate
|
||||
/// unchanged for the caller to handle.
|
||||
pub async fn run(&self, config: &Config, prompt: &str, sink: &impl Sink) -> Result<Progress> {
|
||||
// Resolve resume-vs-create once, up front, so `created` reflects the
|
||||
// session state at the START of the run: the reactive-retry path can't
|
||||
// read it from the retry (the session exists by then).
|
||||
let existed = self.store.find_by_title(&self.name).is_some();
|
||||
let meter = TelemetrySink::new(sink);
|
||||
let created = match self.attempt(config, prompt, &meter).await {
|
||||
let created = match self.attempt(config, prompt, &meter, existed).await {
|
||||
Ok(created) => created,
|
||||
Err(Error::PromptTooLong) => {
|
||||
// The session is already past the window — no turn can run on
|
||||
// it and the detail is gone (no checkpoint possible). Compact,
|
||||
// then retry the same prompt once; the retry is the answering
|
||||
// turn, so its telemetry is what we report.
|
||||
// turn, so its telemetry is what we report. The failed attempt
|
||||
// created/resumed the session, so the retry resumes it, and
|
||||
// `created` still reflects the pre-run state.
|
||||
self.compact(config, sink).await?;
|
||||
let retry = TelemetrySink::new(sink);
|
||||
let created = self.attempt(config, prompt, &retry).await?;
|
||||
self.attempt(config, prompt, &retry, true).await?;
|
||||
return Ok(Progress {
|
||||
created,
|
||||
created: !existed,
|
||||
compacted: true,
|
||||
telemetry: retry.snapshot(),
|
||||
});
|
||||
|
|
@ -91,12 +97,15 @@ impl<P: CompactionPolicy> InfiniteSession<P> {
|
|||
// says it's due, checkpoint (best-effort) then compact.
|
||||
if self.policy.should_compact(telemetry.usage()) {
|
||||
if let Some(checkpoint) = self.policy.checkpoint_prompt() {
|
||||
let _ = self.attempt(config, checkpoint, sink).await;
|
||||
let _ = self.attempt(config, checkpoint, sink, true).await;
|
||||
}
|
||||
let _ = self.compact(config, sink).await;
|
||||
// Only claim a compaction if it actually succeeded — the flag feeds
|
||||
// stats + the auto-reset watermark, so a failed best-effort
|
||||
// `/compact` must not report that the context shrank.
|
||||
let compacted = self.compact(config, sink).await.is_ok();
|
||||
return Ok(Progress {
|
||||
created,
|
||||
compacted: true,
|
||||
compacted,
|
||||
telemetry,
|
||||
});
|
||||
}
|
||||
|
|
@ -121,22 +130,29 @@ impl<P: CompactionPolicy> InfiniteSession<P> {
|
|||
}
|
||||
}
|
||||
|
||||
/// One resume-or-create turn. Uses the store to pick resume vs. create up
|
||||
/// front (avoiding a wasted resume-miss spawn), and still self-heals if the
|
||||
/// backing file vanished between the check and the run. Returns whether a
|
||||
/// fresh session was created.
|
||||
async fn attempt(&self, config: &Config, prompt: &str, sink: &impl Sink) -> Result<bool> {
|
||||
let exists = self.store.find_by_title(&self.name).is_some();
|
||||
let attach = if exists {
|
||||
/// One resume-or-create turn. `existed` is the caller's up-front
|
||||
/// resume-vs-create decision (whether the titled session was on disk before
|
||||
/// the run) — passing it in rather than re-checking keeps `created`
|
||||
/// reporting consistent across the reactive-retry path. Still self-heals if
|
||||
/// the backing file vanished between the check and the run. Returns whether
|
||||
/// a fresh session was created.
|
||||
async fn attempt(
|
||||
&self,
|
||||
config: &Config,
|
||||
prompt: &str,
|
||||
sink: &impl Sink,
|
||||
existed: bool,
|
||||
) -> Result<bool> {
|
||||
let attach = if existed {
|
||||
Attach::Resume(self.name.clone())
|
||||
} else {
|
||||
Attach::Create(self.name.clone())
|
||||
};
|
||||
match Claude::run(config, &attach, prompt, sink).await {
|
||||
Ok(()) => Ok(!exists),
|
||||
Ok(()) => Ok(!existed),
|
||||
// We thought it existed but the resume missed (raced an archive) —
|
||||
// self-heal by creating.
|
||||
Err(Error::SessionNotFound) if exists => {
|
||||
Err(Error::SessionNotFound) if existed => {
|
||||
Claude::run(config, &Attach::Create(self.name.clone()), prompt, sink).await?;
|
||||
Ok(true)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue