diff options
| author | soryu <soryu@soryu.co> | 2026-02-06 21:43:21 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-06 21:43:21 +0000 |
| commit | cececbf326e258211ceae7afce716a5d1e46014f (patch) | |
| tree | a10db0b7e26908b043fa9b9b065be5d5c94bbd67 | |
| parent | 1b692b8cde4a888c8a35af69231f181b57bf5619 (diff) | |
| download | soryu-cececbf326e258211ceae7afce716a5d1e46014f.tar.gz soryu-cececbf326e258211ceae7afce716a5d1e46014f.zip | |
Fix: Link directives and contracts
| -rw-r--r-- | makima/src/orchestration/engine.rs | 51 | ||||
| -rw-r--r-- | makima/src/orchestration/mod.rs | 2 | ||||
| -rw-r--r-- | makima/src/server/handlers/directives.rs | 68 |
3 files changed, 114 insertions, 7 deletions
diff --git a/makima/src/orchestration/engine.rs b/makima/src/orchestration/engine.rs index 470db40..9f7c3b1 100644 --- a/makima/src/orchestration/engine.rs +++ b/makima/src/orchestration/engine.rs @@ -99,6 +99,20 @@ pub enum EngineEvent { }, } +/// Result from starting a directive, containing info needed for auto-start. +pub struct PlanningStartResult { + /// The planning task ID that needs to be started on a daemon + pub task_id: Uuid, + /// The owner ID for finding available daemons + pub owner_id: Uuid, + /// The planning task details needed for the SpawnTask command + pub task_name: String, + pub plan: String, + pub contract_id: Uuid, + pub repository_url: Option<String>, + pub base_branch: Option<String>, +} + /// Main orchestration engine for directives. pub struct DirectiveEngine { pool: PgPool, @@ -134,7 +148,8 @@ impl DirectiveEngine { // ======================================================================== /// Start a directive: spawn a planning contract+task to generate the chain. - pub async fn start_directive(&self, directive_id: Uuid) -> Result<(), EngineError> { + /// Returns a `PlanningStartResult` so the caller can auto-start the task on a daemon. + pub async fn start_directive(&self, directive_id: Uuid) -> Result<PlanningStartResult, EngineError> { let directive = repository::get_directive(&self.pool, directive_id) .await? .ok_or(EngineError::DirectiveNotFound(directive_id))?; @@ -201,17 +216,18 @@ impl DirectiveEngine { let plan = self.build_planning_task_instructions(&directive); // Create the planning task - let _task = repository::create_task_for_owner( + let task_name = format!("{} - Planning", directive.title); + let task = repository::create_task_for_owner( &self.pool, directive.owner_id, CreateTaskRequest { contract_id: Some(contract.id), - name: format!("{} - Planning", directive.title), + name: task_name.clone(), description: Some(format!( "Plan the execution chain for directive: {}", directive.goal )), - plan, + plan: plan.clone(), parent_task_id: None, is_supervisor: true, priority: 5, @@ -234,6 +250,22 @@ impl DirectiveEngine { EngineError::ContractCreation(format!("Failed to create planning task: {}", e)) })?; + // Link the supervisor task to the contract + if let Err(e) = repository::update_contract_supervisor( + &self.pool, + contract.id, + task.id, + ) + .await + { + tracing::warn!( + contract_id = %contract.id, + task_id = %task.id, + error = %e, + "Failed to link supervisor task to planning contract" + ); + } + // Link the planning contract to the directive repository::set_directive_orchestrator_contract( &self.pool, @@ -248,13 +280,22 @@ impl DirectiveEngine { "info", serde_json::json!({ "contract_id": contract.id, + "task_id": task.id, "message": "Planning task spawned, waiting for chain generation", }), "system", ) .await?; - Ok(()) + Ok(PlanningStartResult { + task_id: task.id, + owner_id: directive.owner_id, + task_name, + plan, + contract_id: contract.id, + repository_url: directive.repository_url.clone(), + base_branch: directive.base_branch.clone(), + }) } /// Pause a directive. diff --git a/makima/src/orchestration/mod.rs b/makima/src/orchestration/mod.rs index 8c21089..8fca5ba 100644 --- a/makima/src/orchestration/mod.rs +++ b/makima/src/orchestration/mod.rs @@ -18,7 +18,7 @@ mod engine; mod planner; mod verifier; -pub use engine::{DirectiveEngine, EngineError}; +pub use engine::{DirectiveEngine, EngineError, PlanningStartResult}; pub use planner::{ChainPlanner, GeneratedSpec, PlannerError}; pub use verifier::{ auto_detect_verifiers, CompositeEvaluator, ConfidenceLevel, EvaluationResult, Verifier, diff --git a/makima/src/server/handlers/directives.rs b/makima/src/server/handlers/directives.rs index 52422cd..9c65c5e 100644 --- a/makima/src/server/handlers/directives.rs +++ b/makima/src/server/handlers/directives.rs @@ -292,7 +292,73 @@ pub async fn start_directive( // Start directive via orchestration engine let engine = crate::orchestration::DirectiveEngine::new(pool.clone()); match engine.start_directive(id).await { - Ok(()) => { + Ok(planning) => { + // Auto-start the planning task on an available daemon + if let Some(daemon_id) = state.find_alternative_daemon(auth.owner_id, &[]) { + // Update task status to "starting" and assign daemon + let update_req = crate::db::models::UpdateTaskRequest { + status: Some("starting".to_string()), + daemon_id: Some(daemon_id), + ..Default::default() + }; + if let Err(e) = repository::update_task_for_owner( + pool, + planning.task_id, + auth.owner_id, + update_req, + ) + .await + { + tracing::warn!("Failed to update planning task status: {}", e); + } + + let command = crate::server::state::DaemonCommand::SpawnTask { + task_id: planning.task_id, + task_name: planning.task_name, + plan: planning.plan, + repo_url: planning.repository_url, + base_branch: planning.base_branch, + target_branch: None, + parent_task_id: None, + depth: 0, + is_orchestrator: false, + target_repo_path: None, + completion_action: Some("none".to_string()), + continue_from_task_id: None, + copy_files: None, + contract_id: Some(planning.contract_id), + is_supervisor: true, + autonomous_loop: false, + resume_session: false, + conversation_history: None, + patch_data: None, + patch_base_sha: None, + local_only: false, + auto_merge_local: false, + supervisor_worktree_task_id: None, + }; + + if let Err(e) = state.send_daemon_command(daemon_id, command).await { + tracing::warn!( + "Failed to auto-start planning task on daemon {}: {}", + daemon_id, + e + ); + } else { + tracing::info!( + "Auto-started planning task {} on daemon {} for directive {}", + planning.task_id, + daemon_id, + id + ); + } + } else { + tracing::warn!( + "No daemon available to auto-start planning task for directive {}", + id + ); + } + // Return the updated directive with progress match repository::get_directive_with_progress(pool, id, auth.owner_id).await { Ok(Some(directive)) => Json(directive).into_response(), |
