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(crate) fn task_item_snapshot(&self, item_id: &str) -> Option<TaskItem> {
46 self.items
47 .iter()
48 .find(|item| item.id == item_id)
49 .map(clone_loop_item_into_task_item)
50 }
51
52 pub fn from_session(session: &bamboo_agent_core::Session) -> Option<Self> {
54 session.task_list.as_ref().map(|task_list| {
55 let existing_version = session
58 .task_list_version_meta()
59 .or_else(|| session.todo_list_version_meta())
60 .and_then(|v| v.parse::<u64>().ok())
61 .unwrap_or(0);
62
63 let items: Vec<TaskLoopItem> = task_list
64 .items
65 .iter()
66 .map(|item| TaskLoopItem {
67 id: item.id.clone(),
68 description: item.description.clone(),
69 status: item.status.clone(),
70 depends_on: item.depends_on.clone(),
71 notes: item.notes.clone(),
72 active_form: item.active_form.clone(),
73 parent_id: item.parent_id.clone(),
74 phase: item.phase.clone(),
75 priority: item.priority.clone(),
76 completion_criteria: item.completion_criteria.clone(),
77 evidence: item.evidence.clone(),
78 blockers: item.blockers.clone(),
79 transitions: item.transitions.clone(),
80 tool_calls: Vec::new(),
81 started_at_round: item
82 .transitions
83 .iter()
84 .find(|transition| {
85 matches!(transition.to_status, TaskItemStatus::InProgress)
86 })
87 .and_then(|transition| transition.round),
88 completed_at_round: item
89 .transitions
90 .iter()
91 .rev()
92 .find(|transition| {
93 matches!(transition.to_status, TaskItemStatus::Completed)
94 })
95 .and_then(|transition| transition.round),
96 })
97 .collect();
98
99 Self {
100 session_id: task_list.session_id.clone(),
101 active_item_id: items
102 .iter()
103 .find(|item| matches!(item.status, TaskItemStatus::InProgress))
104 .map(|item| item.id.clone()),
105 items,
106 current_round: 0,
107 max_rounds: 200,
108 created_at: task_list.created_at,
109 updated_at: task_list.updated_at,
110 version: existing_version,
111 task_list_dirty: false,
112 }
113 })
114 }
115
116 pub fn to_task_list_with_title(&self, title: impl Into<String>) -> TaskList {
118 TaskList {
119 session_id: self.session_id.clone(),
120 title: title.into(),
121 items: self
122 .items
123 .iter()
124 .map(clone_loop_item_into_task_item)
125 .collect(),
126 created_at: self.created_at,
127 updated_at: self.updated_at,
128 }
129 }
130
131 pub fn into_task_list(self) -> TaskList {
133 self.into_task_list_with_title("Agent Tasks")
134 }
135
136 pub fn into_task_list_with_title(self, title: impl Into<String>) -> TaskList {
138 TaskList {
139 session_id: self.session_id,
140 title: title.into(),
141 items: self.items.into_iter().map(into_task_item).collect(),
142 created_at: self.created_at,
143 updated_at: self.updated_at,
144 }
145 }
146}