Run setup script in parallel with coding agent (vibe-kanban) (#1446)
* The implementation is complete. Here's a summary of all the changes made: ## Summary ### Files Created - `crates/db/migrations/20251206000000_add_parallel_setup_script_to_projects.sql` - Database migration ### Files Modified **Backend (Rust):** - `crates/db/src/models/project.rs` - Added `parallel_setup_script: bool` field to `Project`, `Option<bool>` to `CreateProject`/`UpdateProject`, updated all SQL queries - `crates/services/src/services/container.rs` - Modified `start_attempt()` to support parallel execution when `parallel_setup_script` is true - `crates/server/src/routes/projects.rs` - Updated create/update handlers to include new field - `crates/deployment/src/lib.rs` - Added field to auto-created projects **Frontend (TypeScript/React):** - `frontend/src/pages/settings/ProjectSettings.tsx` - Added checkbox UI for parallel setup script setting - `frontend/src/components/dialogs/projects/ProjectFormDialog.tsx` - Added field to create data - `frontend/src/components/tasks/TaskDetails/preview/NoServerContent.tsx` - Added field to update data **i18n:** - `frontend/src/i18n/locales/en/settings.json` - Added translation strings - `frontend/src/i18n/locales/es/settings.json` - Added Spanish translations - `frontend/src/i18n/locales/ja/settings.json` - Added Japanese translations - `frontend/src/i18n/locales/ko/settings.json` - Added Korean translations **SQLx Cache:** - `crates/db/.sqlx/` - Updated query cache files ### Behavior - When `parallel_setup_script` is `false` (default): Sequential execution (setup → coding agent → cleanup) - When `parallel_setup_script` is `true`: Setup script and coding agent start simultaneously, setup script failure does not stop the coding agent * update useConversationHistory to display multiple running conversation threads at once * The bug fix is complete. Here's a summary of the changes: ## Bug Fix Summary **Problem:** When running in parallel mode, if the setup script finishes before the coding agent, the task incorrectly moves to "InReview" status while the coding agent is still running. **Root Cause:** The `should_finalize()` method returned `true` when `next_action.is_none()`, which is the case for setup scripts in parallel mode. This caused premature task finalization. **Solution:** Modified `should_finalize()` to check if there are other running non-DevServer processes for the same task attempt before finalizing. ### Files Modified 1. **`crates/db/src/models/execution_process.rs`** - Added `has_running_non_dev_server_processes_excluding()` method that accepts an optional `exclude_id` parameter - Refactored existing `has_running_non_dev_server_processes()` to delegate to the new method 2. **`crates/services/src/services/container.rs`** - Changed `should_finalize()` from sync to async - Added check for other running processes before allowing finalization 3. **`crates/local-deployment/src/container.rs`** - Updated call site to use `.await` on the now-async `should_finalize()` * The bug fix is complete. Here's a summary of the changes: **Fixed files:** 1. **`crates/services/src/services/container.rs`** - Simplified `should_finalize()`: - Changed from `async fn` back to `fn` (non-async) - Removed the complex database check for other running processes - Added a simple check: if the run_reason is `SetupScript` AND `next_action.is_none()` (parallel mode), return `false` (don't finalize) 2. **`crates/local-deployment/src/container.rs`** - Removed `.await` from the `should_finalize()` call 3. **`crates/db/src/models/execution_process.rs`** - Cleaned up by removing the unused `has_running_non_dev_server_processes_excluding()` function and simplifying `has_running_non_dev_server_processes()` back to its original form **How the fix works:** - In **parallel mode**: Setup scripts have `next_action: None`, so the new check catches this case and prevents finalization - In **sequential mode**: Setup scripts have `next_action: Some(coding_agent)`, so they pass this check but won't finalize anyway because `next_action.is_none()` returns `false`
This commit is contained in:
committed by
GitHub
parent
7da884bc3a
commit
76877ea631
@@ -123,14 +123,29 @@ pub trait ContainerService {
|
||||
/// A context is finalized when
|
||||
/// - Always when the execution process has failed or been killed
|
||||
/// - Never when the run reason is DevServer
|
||||
/// - Never when a setup script has no next_action (parallel mode)
|
||||
/// - The next action is None (no follow-up actions)
|
||||
fn should_finalize(&self, ctx: &ExecutionContext) -> bool {
|
||||
// Never finalize DevServer processes
|
||||
if matches!(
|
||||
ctx.execution_process.run_reason,
|
||||
ExecutionProcessRunReason::DevServer
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Never finalize setup scripts without a next_action (parallel mode).
|
||||
// In sequential mode, setup scripts have next_action pointing to coding agent,
|
||||
// so they won't finalize anyway (handled by next_action.is_none() check below).
|
||||
let action = ctx.execution_process.executor_action().unwrap();
|
||||
if matches!(
|
||||
ctx.execution_process.run_reason,
|
||||
ExecutionProcessRunReason::SetupScript
|
||||
) && action.next_action.is_none()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always finalize failed or killed executions, regardless of next action
|
||||
if matches!(
|
||||
ctx.execution_process.status,
|
||||
@@ -138,12 +153,9 @@ pub trait ContainerService {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, finalize only if no next action
|
||||
ctx.execution_process
|
||||
.executor_action()
|
||||
.unwrap()
|
||||
.next_action
|
||||
.is_none()
|
||||
action.next_action.is_none()
|
||||
}
|
||||
|
||||
/// Finalize task execution by updating status to InReview and sending notifications
|
||||
@@ -670,32 +682,74 @@ pub trait ContainerService {
|
||||
|
||||
let prompt = task.to_prompt();
|
||||
|
||||
let cleanup_action = self.cleanup_action(project.cleanup_script);
|
||||
let cleanup_action = self.cleanup_action(project.cleanup_script.clone());
|
||||
|
||||
// Choose whether to execute the setup_script or coding agent first
|
||||
let execution_process = if let Some(setup_script) = project.setup_script {
|
||||
let executor_action = ExecutorAction::new(
|
||||
ExecutorActionType::ScriptRequest(ScriptRequest {
|
||||
script: setup_script,
|
||||
language: ScriptRequestLanguage::Bash,
|
||||
context: ScriptContext::SetupScript,
|
||||
}),
|
||||
// once the setup script is done, run the initial coding agent request
|
||||
Some(Box::new(ExecutorAction::new(
|
||||
if project.parallel_setup_script {
|
||||
// PARALLEL EXECUTION: Start setup script and coding agent independently
|
||||
// Setup script runs without next_action (it completes on its own)
|
||||
let setup_action = ExecutorAction::new(
|
||||
ExecutorActionType::ScriptRequest(ScriptRequest {
|
||||
script: setup_script,
|
||||
language: ScriptRequestLanguage::Bash,
|
||||
context: ScriptContext::SetupScript,
|
||||
}),
|
||||
None, // No chaining - runs independently
|
||||
);
|
||||
|
||||
// Start setup script (ignore errors - coding agent will start regardless)
|
||||
if let Err(e) = self
|
||||
.start_execution(
|
||||
&task_attempt,
|
||||
&setup_action,
|
||||
&ExecutionProcessRunReason::SetupScript,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(?e, "Failed to start setup script in parallel mode");
|
||||
}
|
||||
|
||||
// Start coding agent independently with cleanup as next_action
|
||||
let coding_action = ExecutorAction::new(
|
||||
ExecutorActionType::CodingAgentInitialRequest(CodingAgentInitialRequest {
|
||||
prompt,
|
||||
executor_profile_id: executor_profile_id.clone(),
|
||||
}),
|
||||
cleanup_action,
|
||||
))),
|
||||
);
|
||||
);
|
||||
|
||||
self.start_execution(
|
||||
&task_attempt,
|
||||
&executor_action,
|
||||
&ExecutionProcessRunReason::SetupScript,
|
||||
)
|
||||
.await?
|
||||
self.start_execution(
|
||||
&task_attempt,
|
||||
&coding_action,
|
||||
&ExecutionProcessRunReason::CodingAgent,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
// SEQUENTIAL EXECUTION: Setup script runs first, then coding agent
|
||||
let executor_action = ExecutorAction::new(
|
||||
ExecutorActionType::ScriptRequest(ScriptRequest {
|
||||
script: setup_script,
|
||||
language: ScriptRequestLanguage::Bash,
|
||||
context: ScriptContext::SetupScript,
|
||||
}),
|
||||
// once the setup script is done, run the initial coding agent request
|
||||
Some(Box::new(ExecutorAction::new(
|
||||
ExecutorActionType::CodingAgentInitialRequest(CodingAgentInitialRequest {
|
||||
prompt,
|
||||
executor_profile_id: executor_profile_id.clone(),
|
||||
}),
|
||||
cleanup_action,
|
||||
))),
|
||||
);
|
||||
|
||||
self.start_execution(
|
||||
&task_attempt,
|
||||
&executor_action,
|
||||
&ExecutionProcessRunReason::SetupScript,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
} else {
|
||||
let executor_action = ExecutorAction::new(
|
||||
ExecutorActionType::CodingAgentInitialRequest(CodingAgentInitialRequest {
|
||||
|
||||
Reference in New Issue
Block a user