summaryrefslogtreecommitdiff
path: root/makima/src/db
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-24 00:52:28 +0000
committersoryu <soryu@soryu.co>2026-01-24 00:52:28 +0000
commitcb2aa9a73163ce392d7c3f1dd81888b039312a67 (patch)
tree4b124f0f8ab3762140fa8b7ed2e0370e479fedae /makima/src/db
parent579c983d3efb8f1414ffb45b9e031f741cce5f76 (diff)
downloadsoryu-cb2aa9a73163ce392d7c3f1dd81888b039312a67.tar.gz
soryu-cb2aa9a73163ce392d7c3f1dd81888b039312a67.zip
feat: Add maximum iterations limit for autonomous loop mode
Adds configurable iteration limits to prevent runaway autonomous loops and provide predictable behavior, inspired by Ralph's design patterns. Changes: - Add AutonomousLoopConfig to daemon config with: - default_max_iterations: 10 (default for new tasks) - hard_limit: 50 (absolute maximum that cannot be exceeded) - no_change_threshold: 3 (consecutive runs without progress) - same_error_threshold: 5 (consecutive runs with same error) - Add max_iterations and iteration_count fields to Task model - Add iteration_limit_reached status to TaskStatus enum - Pass max_iterations through DaemonCommand::SpawnTask - Apply limits in CircuitBreaker during autonomous loop execution When a task hits the iteration limit: - Task status is set to "iteration_limit_reached" (not "failed") - Clear message is logged about hitting the limit - Task can be resumed with a higher limit if needed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/db')
-rw-r--r--makima/src/db/models.rs19
1 files changed, 19 insertions, 0 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 58f4da1..c71dec5 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -351,6 +351,9 @@ pub enum TaskStatus {
Done,
Failed,
Merged,
+ /// Task stopped due to reaching maximum iteration limit in autonomous loop mode.
+ /// Task can be resumed with a higher limit if needed.
+ IterationLimitReached,
}
impl std::fmt::Display for TaskStatus {
@@ -363,6 +366,7 @@ impl std::fmt::Display for TaskStatus {
TaskStatus::Done => write!(f, "done"),
TaskStatus::Failed => write!(f, "failed"),
TaskStatus::Merged => write!(f, "merged"),
+ TaskStatus::IterationLimitReached => write!(f, "iteration_limit_reached"),
}
}
}
@@ -379,6 +383,7 @@ impl std::str::FromStr for TaskStatus {
"done" => Ok(TaskStatus::Done),
"failed" => Ok(TaskStatus::Failed),
"merged" => Ok(TaskStatus::Merged),
+ "iteration_limit_reached" => Ok(TaskStatus::IterationLimitReached),
_ => Err(format!("Unknown task status: {}", s)),
}
}
@@ -531,6 +536,15 @@ pub struct Task {
/// Standalone completed tasks can be dismissed by the user.
#[serde(default)]
pub hidden: bool,
+
+ // Autonomous loop iteration tracking
+ /// Maximum iterations for autonomous loop mode (None = use daemon default).
+ /// Task stops with "iteration_limit_reached" status when limit is hit.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub max_iterations: Option<i32>,
+ /// Current iteration count in autonomous loop mode.
+ #[serde(default)]
+ pub iteration_count: i32,
}
impl Task {
@@ -653,6 +667,9 @@ pub struct CreateTaskRequest {
pub branched_from_task_id: Option<Uuid>,
/// Conversation history to initialize the task with (JSON array of messages)
pub conversation_history: Option<serde_json::Value>,
+ /// Maximum iterations for autonomous loop mode (None = use daemon default).
+ /// Task stops with "iteration_limit_reached" status when limit is hit.
+ pub max_iterations: Option<i32>,
}
/// Request payload for updating a task
@@ -684,6 +701,8 @@ pub struct UpdateTaskRequest {
pub hidden: Option<bool>,
/// Version for optimistic locking
pub version: Option<i32>,
+ /// Update iteration count (for autonomous loop tracking)
+ pub iteration_count: Option<i32>,
}
/// Task with its subtasks for detail view