summaryrefslogtreecommitdiff
path: root/makima/src/llm/phase_guidance.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-29 02:56:44 +0000
committersoryu <soryu@soryu.co>2026-01-29 02:56:44 +0000
commitf19acd400cc5bbe1fe51c004c50ee90d704240d8 (patch)
treeb7dcfd6926efcafd6eac33e713ebd321ec4284d0 /makima/src/llm/phase_guidance.rs
parent7af8561677cfdcfd23d099a25783c7fef51d1ba6 (diff)
downloadsoryu-f19acd400cc5bbe1fe51c004c50ee90d704240d8.tar.gz
soryu-f19acd400cc5bbe1fe51c004c50ee90d704240d8.zip
Fix contract type selection
Diffstat (limited to 'makima/src/llm/phase_guidance.rs')
-rw-r--r--makima/src/llm/phase_guidance.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/makima/src/llm/phase_guidance.rs b/makima/src/llm/phase_guidance.rs
index 379bdca..712e8bb 100644
--- a/makima/src/llm/phase_guidance.rs
+++ b/makima/src/llm/phase_guidance.rs
@@ -112,6 +112,8 @@ pub struct TaskInfo {
pub status: String,
}
+use crate::db::models::PhaseConfig;
+
/// Get phase deliverables configuration (legacy, defaults to "simple" contract type)
pub fn get_phase_deliverables(phase: &str) -> PhaseDeliverables {
get_phase_deliverables_for_type(phase, "simple")
@@ -126,6 +128,90 @@ pub fn get_phase_deliverables_for_type(phase: &str, contract_type: &str) -> Phas
}
}
+/// Get phase deliverables from a custom PhaseConfig
+/// This is used for contracts with custom templates
+pub fn get_phase_deliverables_from_config(phase: &str, config: &PhaseConfig) -> PhaseDeliverables {
+ // Check if this phase exists in the config
+ let phase_exists = config.phases.iter().any(|p| p.id == phase);
+ if !phase_exists {
+ return PhaseDeliverables {
+ phase: phase.to_string(),
+ deliverables: vec![],
+ requires_repository: false,
+ requires_tasks: false,
+ guidance: format!("Phase '{}' is not defined in this contract template", phase),
+ };
+ }
+
+ // Get deliverables for this phase from the config
+ let deliverables: Vec<Deliverable> = config
+ .deliverables
+ .get(phase)
+ .map(|defs| {
+ defs.iter()
+ .map(|d| Deliverable {
+ id: d.id.clone(),
+ name: d.name.clone(),
+ priority: match d.priority.as_str() {
+ "recommended" => DeliverablePriority::Recommended,
+ "optional" => DeliverablePriority::Optional,
+ _ => DeliverablePriority::Required,
+ },
+ description: format!("{} deliverable", d.name),
+ })
+ .collect()
+ })
+ .unwrap_or_default();
+
+ // Determine if repository is required (typically for execute-like phases)
+ let requires_repository = phase == "execute" || phase == "plan";
+
+ // Determine if tasks are required (typically for execute phase)
+ let requires_tasks = phase == "execute";
+
+ // Find the phase name for better guidance
+ let phase_name = config
+ .phases
+ .iter()
+ .find(|p| p.id == phase)
+ .map(|p| p.name.clone())
+ .unwrap_or_else(|| phase.to_string());
+
+ let guidance = if deliverables.is_empty() {
+ format!("Complete the {} phase. No specific deliverables are required.", phase_name)
+ } else {
+ let deliverable_names: Vec<_> = deliverables.iter().map(|d| d.name.clone()).collect();
+ format!(
+ "Complete the {} phase by producing the following deliverables: {}",
+ phase_name,
+ deliverable_names.join(", ")
+ )
+ };
+
+ PhaseDeliverables {
+ phase: phase.to_string(),
+ deliverables,
+ requires_repository,
+ requires_tasks,
+ guidance,
+ }
+}
+
+/// Get phase deliverables, checking custom config first, then falling back to built-in types
+pub fn get_phase_deliverables_with_config(
+ phase: &str,
+ contract_type: &str,
+ phase_config: Option<&PhaseConfig>,
+) -> PhaseDeliverables {
+ // If we have a custom phase config, use it
+ if let Some(config) = phase_config {
+ return get_phase_deliverables_from_config(phase, config);
+ }
+
+ // Otherwise, fall back to built-in contract types
+ get_phase_deliverables_for_type(phase, contract_type)
+}
+
/// Get deliverables for 'simple' contract type
fn get_simple_type_deliverables(phase: &str) -> PhaseDeliverables {
match phase {