summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-21 16:09:34 +0000
committersoryu <soryu@soryu.co>2026-01-21 16:09:34 +0000
commit3b3734e9c8cd889e6f7369d284ec530413821919 (patch)
tree14d04fb436737e9a5cf900b0f2540f4698302153
parent3bbb7ac92f0a480f9275c9b29b6a4e07e8e0ff45 (diff)
downloadsoryu-3b3734e9c8cd889e6f7369d284ec530413821919.tar.gz
soryu-3b3734e9c8cd889e6f7369d284ec530413821919.zip
Add task branching models and update CreateTaskRequest
- Add branched_from_task_id field to Task struct - Make contract_id optional in CreateTaskRequest for anonymous tasks - Add branched_from_task_id and conversation_history to CreateTaskRequest - Add BranchTaskRequest struct for branching API - Add BranchTaskResponse struct with task, message_count, daemon_id Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
-rw-r--r--makima/src/db/models.rs45
1 files changed, 43 insertions, 2 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 291fad7..bf95a3a 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -519,6 +519,12 @@ pub struct Task {
/// When the task was last interrupted due to daemon disconnect
#[serde(skip_serializing_if = "Option::is_none")]
pub interrupted_at: Option<DateTime<Utc>>,
+
+ // Task branching
+ /// Source task ID when this task was branched from another task's conversation.
+ /// Used to track the origin of "what if" explorations.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub branched_from_task_id: Option<Uuid>,
}
impl Task {
@@ -598,8 +604,8 @@ pub struct TaskListResponse {
#[derive(Debug, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct CreateTaskRequest {
- /// Contract this task belongs to (required)
- pub contract_id: Uuid,
+ /// Contract this task belongs to (optional for branched/anonymous tasks)
+ pub contract_id: Option<Uuid>,
/// Name of the task
pub name: String,
/// Optional description
@@ -633,6 +639,10 @@ pub struct CreateTaskRequest {
pub copy_files: Option<Vec<String>>,
/// Checkpoint SHA to branch from (optional)
pub checkpoint_sha: Option<String>,
+ /// Source task ID when branching from another task's conversation
+ 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>,
}
/// Request payload for updating a task
@@ -681,6 +691,37 @@ pub struct SendMessageRequest {
pub message: String,
}
+/// Default for include_conversation field in BranchTaskRequest
+fn default_include_conversation() -> bool {
+ true
+}
+
+/// Request to branch a task from an existing task's conversation.
+/// Creates a new anonymous task that continues from the source task's state.
+#[derive(Debug, Deserialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct BranchTaskRequest {
+ /// The initial message/instructions for the branched task
+ pub message: String,
+ /// Optional name for the branched task (auto-generated if not provided)
+ pub name: Option<String>,
+ /// Whether to include conversation history from the source task (default: true)
+ #[serde(default = "default_include_conversation")]
+ pub include_conversation: bool,
+}
+
+/// Response from branching a task.
+#[derive(Debug, Serialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
+pub struct BranchTaskResponse {
+ /// The newly created branched task
+ pub task: Task,
+ /// Number of conversation messages included from source task
+ pub message_count: usize,
+ /// Daemon ID if the task was started (None if no daemon available)
+ pub daemon_id: Option<Uuid>,
+}
+
// =============================================================================
// Daemon Types
// =============================================================================