-
Notifications
You must be signed in to change notification settings - Fork 0
Add --pause-after-step flag to implement workflow #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ pub enum SessionPhase { | |
| Implement, | ||
| Review, | ||
| FinalReview, | ||
| Paused, | ||
| Done, | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,6 +63,8 @@ pub struct BuildWorkflowState { | |
| pub reviews: Vec<ReviewState>, | ||
| #[serde(default)] | ||
| pub pending_feedback: Vec<String>, | ||
| #[serde(default)] | ||
| pub pause_after_step: bool, | ||
| } | ||
|
|
||
| impl Default for BuildWorkflowState { | ||
|
|
@@ -75,6 +77,7 @@ impl Default for BuildWorkflowState { | |
| checkpoint: None, | ||
| reviews: Vec::new(), | ||
| pending_feedback: Vec::new(), | ||
| pause_after_step: false, | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -107,10 +110,15 @@ impl BuildWorkflowState { | |
| } | ||
| } | ||
|
|
||
| pub fn initial_workflow_state(implementer_agent: String, steps: Vec<StepState>) -> Result<Value> { | ||
| pub fn initial_workflow_state( | ||
| implementer_agent: String, | ||
| steps: Vec<StepState>, | ||
| pause_after_step: bool, | ||
| ) -> Result<Value> { | ||
| let state = BuildWorkflowState { | ||
| implementer_agent, | ||
| steps, | ||
| pause_after_step, | ||
| ..BuildWorkflowState::default() | ||
| }; | ||
| encode_workflow_state(&state) | ||
|
|
@@ -285,10 +293,35 @@ pub fn get_wait_hint(state: &SessionState, agent: &str) -> Option<String> { | |
| None | ||
| } | ||
| } | ||
| SessionPhase::Paused => { | ||
| Some(format!( | ||
| "Session paused for user feedback after step {}. \ | ||
| Waiting for `rally build continue --session {}`.", | ||
| workflow_state.current_step_idx, state.name | ||
| )) | ||
| } | ||
| _ => None, | ||
| } | ||
| } | ||
|
|
||
| pub fn continue_session(state: &mut SessionState, feedback: Option<String>) -> Result<String> { | ||
| if state.phase != SessionPhase::Paused { | ||
| bail!("session is not paused (current phase: {:?})", state.phase); | ||
| } | ||
| let mut workflow_state = read_workflow_state(state)?; | ||
| if let Some(fb) = feedback { | ||
| workflow_state.pending_feedback.push(fb); | ||
| } | ||
| state.phase = SessionPhase::Implement; | ||
| write_workflow_state(state, &workflow_state)?; | ||
| let step_label = if let Some(step) = workflow_state.current_step() { | ||
| format!("step {}: {}", step.number, step.title) | ||
| } else { | ||
| "next step".to_string() | ||
| }; | ||
| Ok(format!("resumed; advancing to {step_label}")) | ||
| } | ||
|
|
||
| pub fn mark_done(state: &mut SessionState, _agent: &str) -> Result<String> { | ||
| match state.phase { | ||
| SessionPhase::Done => Ok("session already complete".to_string()), | ||
|
|
@@ -580,7 +613,11 @@ fn complete_step( | |
| } | ||
|
|
||
| workflow_state.current_step_idx += 1; | ||
| state.phase = SessionPhase::Implement; | ||
| state.phase = if workflow_state.pause_after_step { | ||
| SessionPhase::Paused | ||
| } else { | ||
| SessionPhase::Implement | ||
| }; | ||
| Ok(()) | ||
|
Comment on lines
615
to
621
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 The Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -126,6 +126,12 @@ pub struct CreateArgs { | |
| pub turn_timeout_secs: u64, | ||
| #[arg(long, default_value_t = 1200)] | ||
| pub review_timeout_secs: u64, | ||
| #[arg( | ||
| long, | ||
| default_value_t = false, | ||
| help = "Pause for user feedback after each step is approved" | ||
| )] | ||
| pub pause_after_step: bool, | ||
| } | ||
|
|
||
| #[derive(Args, Debug)] | ||
|
|
@@ -266,6 +272,16 @@ pub enum BuildSubcommand { | |
| Checkpoint(CheckpointArgs), | ||
| #[command(about = "Submit a review verdict")] | ||
| Review(ReviewArgs), | ||
| #[command(about = "Resume a paused session (advance to the next step)")] | ||
| Continue(ContinueArgs), | ||
| } | ||
|
Comment on lines
+275
to
+277
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update exit-code help text to include paused sessions. With [suggested update] 📝 Suggested doc patch- 2 session complete; stop working
+ 2 session complete or paused; stop working
@@
- long_about = "Block until you have work, then print instructions.\n\nExit codes:\n 0 instruction ready (printed to stdout)\n 1 timeout expired; retry later\n 2 session complete; stop working"
+ long_about = "Block until you have work, then print instructions.\n\nExit codes:\n 0 instruction ready (printed to stdout)\n 1 timeout expired; retry later\n 2 session complete or paused; stop working"🤖 Prompt for AI Agents |
||
|
|
||
| #[derive(Args, Debug)] | ||
| pub struct ContinueArgs { | ||
| #[arg(long)] | ||
| pub session: String, | ||
| #[arg(long, help = "Optional feedback to pass to the implementer for the next step")] | ||
| pub feedback: Option<String>, | ||
| } | ||
|
|
||
| #[derive(Args, Debug)] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,9 @@ use serde_json::{Value, json}; | |
|
|
||
| use crate::{ | ||
| cli::{ | ||
| AgreeArgs, ChainArgs, ChallengeArgs, CheckpointArgs, CreateArgs, DoneArgs, FileIssueArgs, | ||
| JoinArgs, NextArgs, ReviewArgs, ReviewVerdictArg, SessionTypeArg, StatusArgs, | ||
| WorkflowActionArgs, | ||
| AgreeArgs, ChainArgs, ChallengeArgs, CheckpointArgs, ContinueArgs, CreateArgs, DoneArgs, | ||
| FileIssueArgs, JoinArgs, NextArgs, ReviewArgs, ReviewVerdictArg, SessionTypeArg, | ||
| StatusArgs, WorkflowActionArgs, | ||
| }, | ||
| state::{ | ||
| AgentState, Config, SessionHandle, SessionPhase, SessionState, SessionType, | ||
|
|
@@ -84,6 +84,7 @@ pub fn create_with_registry(args: &CreateArgs, registry: &WorkflowRegistry) -> R | |
| Some(implement::initial_workflow_state( | ||
| args.implementer.clone(), | ||
| steps, | ||
| args.pause_after_step, | ||
| )?), | ||
| ) | ||
| } | ||
|
|
@@ -411,6 +412,17 @@ pub fn review_with_registry(args: &ReviewArgs, registry: &WorkflowRegistry) -> R | |
| Ok(()) | ||
| } | ||
|
|
||
| pub fn continue_session_with_registry(args: &ContinueArgs) -> Result<()> { | ||
| let handle = SessionHandle::open(&args.session)?; | ||
| let mut state = handle.load_state()?; | ||
|
|
||
| let msg = implement::continue_session(&mut state, args.feedback.clone())?; | ||
|
|
||
| handle.save_state(&state)?; | ||
| println!("{msg}"); | ||
| Ok(()) | ||
| } | ||
|
Comment on lines
+415
to
+424
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Status output should advertise Now that 📝 Suggested patch (in
|
||
|
|
||
| pub fn chain_with_registry(args: &ChainArgs, registry: &WorkflowRegistry) -> Result<()> { | ||
| let plan_session_dir; | ||
| loop { | ||
|
|
@@ -454,6 +466,7 @@ pub fn chain_with_registry(args: &ChainArgs, registry: &WorkflowRegistry) -> Res | |
| max_rounds: 4, | ||
| turn_timeout_secs: 300, | ||
| review_timeout_secs: 1200, | ||
| pause_after_step: false, | ||
| }; | ||
|
|
||
| let session_name = create_with_registry(&create_args, registry)?; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,7 +44,7 @@ impl RunCommand for ImplementRunCommand { | |
| } | ||
|
|
||
| fn usage(&self) -> &str { | ||
| "implement <todo-file> <role> [--reviewers N]" | ||
| "implement <todo-file> <role> [--reviewers N] [--pause-after-step]" | ||
| } | ||
|
|
||
| fn resolve(&self, args: &[String], workspace: &Path) -> Result<RunCommandResolution> { | ||
|
|
@@ -59,6 +59,7 @@ impl RunCommand for ImplementRunCommand { | |
| let role = &args[1]; | ||
|
|
||
| let mut reviewers = 1u32; | ||
| let mut pause_after_step = false; | ||
| let mut i = 2; | ||
| while i < args.len() { | ||
| if args[i] == "--reviewers" { | ||
|
|
@@ -72,6 +73,11 @@ impl RunCommand for ImplementRunCommand { | |
| i += 1; | ||
| continue; | ||
| } | ||
| if args[i] == "--pause-after-step" { | ||
| pause_after_step = true; | ||
| i += 1; | ||
| continue; | ||
| } | ||
| i += 1; | ||
| } | ||
|
|
||
|
|
@@ -109,6 +115,7 @@ impl RunCommand for ImplementRunCommand { | |
| max_rounds: 4, | ||
| turn_timeout_secs: 300, | ||
| review_timeout_secs: 1200, | ||
| pause_after_step, | ||
| }; | ||
|
|
||
| Ok(RunCommandResolution::Session { | ||
|
|
@@ -185,6 +192,7 @@ impl RunCommand for NegotiateRunCommand { | |
| max_rounds: 4, | ||
| turn_timeout_secs: 300, | ||
| review_timeout_secs: 1200, | ||
| pause_after_step: false, | ||
| }; | ||
|
|
||
| Ok(RunCommandResolution::Session { | ||
|
|
@@ -429,6 +437,15 @@ impl Workflow for BuildWorkflow { | |
| }); | ||
| } | ||
|
|
||
| if ctx.host.state.phase == SessionPhase::Paused { | ||
| return Ok(NextPollDispatch::Complete { | ||
| message: format!( | ||
| "session paused for user feedback; run `rally build continue --session {}` to advance", | ||
| ctx.host.state.name | ||
| ), | ||
| }); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Comment on lines
+440
to
+447
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Paused session's informative message is silently discarded; agent sees misleading "session complete; stop working" When a session enters the Code path that discards the messageIn NextPollDispatch::Complete { .. } => {
return Ok(2);
}Then in } else if code == 2 {
println!("session complete; stop working");
}Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| Ok(NextPollDispatch::Wait { | ||
| hint: implement::get_wait_hint(ctx.host.state, ctx.agent), | ||
| }) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Paused wait hint displays 0-based index instead of completed step's number
In
get_wait_hintfor thePausedphase, the message usesworkflow_state.current_step_idx(a 0-based vector index that has already been incremented to point to the next step) rather than the just-completed step's actual number. For a 2-step todo with sequential numbering (1, 2), completing step 1 setscurrent_step_idx = 1, so the message "paused after step 1" accidentally looks correct. However, if step numbers are non-sequential (e.g., steps numbered 5 and 10),current_step_idxwould be 1 after completing the first step, producing the misleading message "paused after step 1" instead of "paused after step 5". The correct value would beworkflow_state.steps[workflow_state.current_step_idx - 1].number.Was this helpful? React with 👍 or 👎 to provide feedback.