diff options
| author | soryu <soryu@soryu.co> | 2026-02-12 02:29:45 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-12 02:29:45 +0000 |
| commit | 355f10964c4dbec24a244a00caba5c17ed23fc65 (patch) | |
| tree | 6fdc998e6b95948e80a87a962acd58acf79d5b98 /makima/src/orchestration/directive.rs | |
| parent | 9bd6eacaa9ebe860842b5d5cfbf2b7d2d0293ab1 (diff) | |
| download | soryu-355f10964c4dbec24a244a00caba5c17ed23fc65.tar.gz soryu-355f10964c4dbec24a244a00caba5c17ed23fc65.zip | |
makima: Add an optional memory system for directives (#59)
* feat: makima: Add an optional memory system for directives: Add directive_memories database table and migration
* feat: makima: Add an optional memory system for directives: Update directive skill documentation with memory commands
* feat: makima: Add an optional memory system for directives: Add repository functions for directive memory CRUD
* feat: makima: Add an optional memory system for directives: Add frontend API functions and types for directive memory
* feat: makima: Add an optional memory system for directives: Add Rust models for directive memory
* WIP: heartbeat checkpoint
* WIP: heartbeat checkpoint
* WIP: heartbeat checkpoint
* WIP: heartbeat checkpoint
* feat: makima: Add an optional memory system for directives: Add memory panel to frontend DirectiveDetail component
* Merge remote-tracking branch 'origin/makima/makima--add-an-optional-memory-system-for-directiv-5de1e06d' into combined branch
* Merge remote-tracking branch 'origin/makima/makima--add-an-optional-memory-system-for-directiv-c8298c6c' into combined branch
* feat: makima: Add an optional memory system for directives: Create useMultiTaskSubscription hook for multi-output WebSocket streaming
* feat: makima: Add an optional memory system for directives: Create DirectiveLogStream component for stern-like multi-task output viewing
* feat: makima: Add an optional memory system for directives: Integrate log stream panel into directive detail page
Diffstat (limited to 'makima/src/orchestration/directive.rs')
| -rw-r--r-- | makima/src/orchestration/directive.rs | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/makima/src/orchestration/directive.rs b/makima/src/orchestration/directive.rs index 15cc7ed..cb3983a 100644 --- a/makima/src/orchestration/directive.rs +++ b/makima/src/orchestration/directive.rs @@ -9,7 +9,7 @@ use sqlx::PgPool; use uuid::Uuid; -use crate::db::models::{CreateTaskRequest, UpdateTaskRequest}; +use crate::db::models::{CreateTaskRequest, DirectiveMemory, UpdateTaskRequest}; use crate::db::repository; use crate::server::state::{DaemonCommand, SharedState}; @@ -44,7 +44,24 @@ impl DirectiveOrchestrator { "Directive needs planning — spawning planning task" ); - let plan = build_planning_prompt(&directive, &[], 1); + // Load memories if memory is enabled for this directive + let memories = if directive.memory_enabled { + match repository::list_directive_memories(&self.pool, directive.id).await { + Ok(m) => m, + Err(e) => { + tracing::warn!( + directive_id = %directive.id, + error = %e, + "Failed to load directive memories for planning — continuing without" + ); + vec![] + } + } + } else { + vec![] + }; + + let plan = build_planning_prompt(&directive, &[], 1, &memories); if let Err(e) = self .spawn_orchestrator_task( @@ -86,17 +103,40 @@ impl DirectiveOrchestrator { .as_deref() .unwrap_or("Execute the step described below."); + // Load memories if memory is enabled for this directive + let memory_context = if step.memory_enabled { + match repository::list_directive_memories(&self.pool, step.directive_id).await { + Ok(memories) if !memories.is_empty() => { + format!("\n\nMEMORY CONTEXT (from previous planning/execution cycles):\n{}\n", + format_memories_for_prompt(&memories)) + } + Ok(_) => String::new(), + Err(e) => { + tracing::warn!( + directive_id = %step.directive_id, + error = %e, + "Failed to load directive memories for execution — continuing without" + ); + String::new() + } + } + } else { + String::new() + }; + let plan = format!( "You are executing a step in directive \"{directive_title}\".\n\n\ STEP: {step_name}\n\ DESCRIPTION: {description}\n\n\ - INSTRUCTIONS:\n{task_plan}\n\n\ + INSTRUCTIONS:\n{task_plan}\n\ + {memory_context}\ When done, the system will automatically mark this step as completed.\n\ If you cannot complete the task, report the failure clearly.", directive_title = step.directive_title, step_name = step.step_name, description = step.step_description.as_deref().unwrap_or("(none)"), task_plan = task_plan, + memory_context = memory_context, ); match self @@ -239,7 +279,24 @@ impl DirectiveOrchestrator { let generation = repository::get_directive_max_generation(&self.pool, directive.id).await? + 1; - let plan = build_planning_prompt(&directive, &existing_steps, generation); + // Load memories if memory is enabled for this directive + let memories = if directive.memory_enabled { + match repository::list_directive_memories(&self.pool, directive.id).await { + Ok(m) => m, + Err(e) => { + tracing::warn!( + directive_id = %directive.id, + error = %e, + "Failed to load directive memories for re-planning — continuing without" + ); + vec![] + } + } + } else { + vec![] + }; + + let plan = build_planning_prompt(&directive, &existing_steps, generation, &memories); if let Err(e) = self .spawn_orchestrator_task( @@ -597,14 +654,34 @@ impl DirectiveOrchestrator { } } +/// Format memory entries into a readable prompt section. +fn format_memories_for_prompt(memories: &[DirectiveMemory]) -> String { + let mut out = String::new(); + for memory in memories { + out.push_str(&format!( + "- [{}] ({}): {}\n", + memory.category, memory.source, memory.content + )); + } + out +} + /// Build the planning prompt for a directive. fn build_planning_prompt( directive: &crate::db::models::Directive, existing_steps: &[crate::db::models::DirectiveStep], generation: i32, + memories: &[DirectiveMemory], ) -> String { let mut prompt = String::new(); + // Include memory context if available + if !memories.is_empty() { + prompt.push_str("MEMORY CONTEXT (insights and decisions from previous cycles):\n"); + prompt.push_str(&format_memories_for_prompt(memories)); + prompt.push_str("\nUse these memories to inform your planning. Avoid repeating past mistakes and build on prior insights.\n\n"); + } + if !existing_steps.is_empty() { prompt.push_str(&format!( "EXISTING STEPS (generation {}):\n", |
