Skip to main content

codetether_agent/cli/
run_loop.rs

1//! Prompt execution loop for resumable `codetether run`.
2//!
3//! When `--auto-continue-until N` is set, the loop will attempt up to `N`
4//! resume cycles after the step budget is exhausted. `Some(1)` means the
5//! initial run plus one resume attempt; `None` (default) means no automatic
6//! resume.
7
8use crate::session::Session;
9use anyhow::Result;
10use std::path::Path;
11
12pub async fn execute_prompt_with_resume(
13    session: &mut Session,
14    message: &str,
15    max_steps: Option<usize>,
16    resume_attempts: Option<usize>,
17    workspace: &Path,
18) -> Result<crate::session::SessionResult> {
19    let mut prompt_text = message.to_string();
20    let mut resumes_left = resume_attempts.unwrap_or(0);
21    loop {
22        let before = session.messages.len();
23        let result = session.prompt(&prompt_text).await?;
24        if !crate::session::step_limit::was_budget_exhausted() {
25            session.clear_run_checkpoint().await?;
26            return Ok(result);
27        }
28        let budget = max_steps.unwrap_or(crate::session::DEFAULT_MAX_STEPS);
29        if super::run_checkpoint::should_checkpoint(before, session, budget) {
30            super::run_checkpoint::persist_exhaustion_checkpoint(
31                session, message, budget, workspace,
32            )
33            .await?;
34        }
35        if resumes_left == 0 {
36            return Ok(result);
37        }
38        resumes_left -= 1;
39        let Some(plan) = super::run_checkpoint::resume_plan(session, resumes_left).await? else {
40            return Ok(result);
41        };
42        session.max_steps = Some(budget);
43        prompt_text = plan.prompt;
44    }
45}