bamboo_engine/runtime/task_context/
conversion.rs1use bamboo_domain::{TaskItem, TaskItemStatus, TaskList};
2
3use super::{TaskLoopContext, TaskLoopItem};
4
5fn clone_loop_item_into_task_item(loop_item: &TaskLoopItem) -> TaskItem {
6 TaskItem {
7 id: loop_item.id.clone(),
8 description: loop_item.description.clone(),
9 status: loop_item.status.clone(),
10 depends_on: loop_item.depends_on.clone(),
11 notes: loop_item.notes.clone(),
12 active_form: loop_item.active_form.clone(),
13 parent_id: loop_item.parent_id.clone(),
14 phase: loop_item.phase.clone(),
15 priority: loop_item.priority.clone(),
16 completion_criteria: loop_item.completion_criteria.clone(),
17 evidence: loop_item.evidence.clone(),
18 blockers: loop_item.blockers.clone(),
19 transitions: loop_item.transitions.clone(),
20 }
21}
22
23fn into_task_item(loop_item: TaskLoopItem) -> TaskItem {
24 TaskItem {
25 id: loop_item.id,
26 description: loop_item.description,
27 status: loop_item.status,
28 depends_on: loop_item.depends_on,
29 notes: loop_item.notes,
30 active_form: loop_item.active_form,
31 parent_id: loop_item.parent_id,
32 phase: loop_item.phase,
33 priority: loop_item.priority,
34 completion_criteria: loop_item.completion_criteria,
35 evidence: loop_item.evidence,
36 blockers: loop_item.blockers,
37 transitions: loop_item.transitions,
38 }
39}
40
41impl TaskLoopContext {
42 pub fn from_session(session: &bamboo_agent_core::Session) -> Option<Self> {
44 session.task_list.as_ref().map(|task_list| {
45 let existing_version = session
48 .metadata
49 .get("task_list_version")
50 .or_else(|| session.metadata.get("todo_list_version"))
51 .and_then(|v| v.parse::<u64>().ok())
52 .unwrap_or(0);
53
54 let items: Vec<TaskLoopItem> = task_list
55 .items
56 .iter()
57 .map(|item| TaskLoopItem {
58 id: item.id.clone(),
59 description: item.description.clone(),
60 status: item.status.clone(),
61 depends_on: item.depends_on.clone(),
62 notes: item.notes.clone(),
63 active_form: item.active_form.clone(),
64 parent_id: item.parent_id.clone(),
65 phase: item.phase.clone(),
66 priority: item.priority.clone(),
67 completion_criteria: item.completion_criteria.clone(),
68 evidence: item.evidence.clone(),
69 blockers: item.blockers.clone(),
70 transitions: item.transitions.clone(),
71 tool_calls: Vec::new(),
72 started_at_round: item
73 .transitions
74 .iter()
75 .find(|transition| {
76 matches!(transition.to_status, TaskItemStatus::InProgress)
77 })
78 .and_then(|transition| transition.round),
79 completed_at_round: item
80 .transitions
81 .iter()
82 .rev()
83 .find(|transition| {
84 matches!(transition.to_status, TaskItemStatus::Completed)
85 })
86 .and_then(|transition| transition.round),
87 })
88 .collect();
89
90 Self {
91 session_id: task_list.session_id.clone(),
92 active_item_id: items
93 .iter()
94 .find(|item| matches!(item.status, TaskItemStatus::InProgress))
95 .map(|item| item.id.clone()),
96 items,
97 current_round: 0,
98 max_rounds: 200,
99 created_at: task_list.created_at,
100 updated_at: task_list.updated_at,
101 version: existing_version,
102 }
103 })
104 }
105
106 pub fn to_task_list_with_title(&self, title: impl Into<String>) -> TaskList {
108 TaskList {
109 session_id: self.session_id.clone(),
110 title: title.into(),
111 items: self
112 .items
113 .iter()
114 .map(clone_loop_item_into_task_item)
115 .collect(),
116 created_at: self.created_at,
117 updated_at: self.updated_at,
118 }
119 }
120
121 pub fn into_task_list(self) -> TaskList {
123 self.into_task_list_with_title("Agent Tasks")
124 }
125
126 pub fn into_task_list_with_title(self, title: impl Into<String>) -> TaskList {
128 TaskList {
129 session_id: self.session_id,
130 title: title.into(),
131 items: self.items.into_iter().map(into_task_item).collect(),
132 created_at: self.created_at,
133 updated_at: self.updated_at,
134 }
135 }
136}