bamboo_engine/session_app/child_session/
mod.rs1use async_trait::async_trait;
8use bamboo_domain::Session;
9
10mod actions;
11mod helpers;
12
13#[cfg(test)]
14mod tests;
15
16pub use actions::{
17 cancel_child_action, create_child_action, delete_child_action, get_child_action,
18 list_children_action, run_child_action, send_message_to_child_action, update_child_action,
19};
20pub use helpers::{
21 compute_status_guidance, format_child_assignment, map_child_entry, metadata_text,
22 normalize_non_empty_optional, normalize_required_text, replace_or_append_last_user_message,
23 resolve_system_prompt, truncate_after_index, truncate_after_last_user,
24};
25
26#[derive(Debug, thiserror::Error)]
31pub enum ChildSessionError {
32 #[error("session not found: {0}")]
33 NotFound(String),
34 #[error("session is not a root session: {0}")]
35 NotRootSession(String),
36 #[error("session is not a child session: {0}")]
37 NotChildSession(String),
38 #[error("child session {child_id} does not belong to parent {parent_id}")]
39 NotChildOfParent { child_id: String, parent_id: String },
40 #[error("{0}")]
41 InvalidArguments(String),
42 #[error("{0}")]
43 Execution(String),
44}
45
46#[derive(Debug, Clone)]
52pub struct ChildSessionEntry {
53 pub child_session_id: String,
54 pub title: String,
55 pub pinned: bool,
56 pub message_count: usize,
57 pub updated_at: String,
58 pub last_run_status: Option<String>,
59 pub last_run_error: Option<String>,
60}
61
62#[derive(Debug, Clone)]
64pub struct DeleteChildResult {
65 pub deleted: bool,
66 pub cancelled_running_child: bool,
67}
68
69#[derive(Debug, Clone)]
71pub struct ChildRunnerInfo {
72 pub started_at: Option<chrono::DateTime<chrono::Utc>>,
73 pub completed_at: Option<chrono::DateTime<chrono::Utc>>,
74 pub last_tool_name: Option<String>,
75 pub last_tool_phase: Option<String>,
76 pub last_event_at: Option<chrono::DateTime<chrono::Utc>>,
77 pub round_count: u32,
78}
79
80pub const CHILD_SYSTEM_PROMPT: &str = r#"You are a **Child Session**, delegated by a parent session.
82
83Requirements:
84- Focus only on the assigned task and avoid unrelated conversation.
85- You may use tools to complete the task.
86- Do not create or trigger any additional child sessions (no recursive spawn).
87- Keep output concise: provide the conclusion first, then only necessary evidence or steps.
88"#;
89
90pub const PLAN_AGENT_SYSTEM_PROMPT: &str = r#"You are a **Plan Agent**, a read-only exploration specialist delegated by a parent session.
92
93Your role is EXCLUSIVELY to explore the codebase and gather information to help design an implementation plan. You MUST NOT modify anything.
94
95=== CRITICAL: READ-ONLY MODE — NO FILE MODIFICATIONS ===
96
97You are FORBIDDEN from using these tools:
98- Write — do not create new files
99- Edit — do not modify existing files
100- NotebookEdit — do not edit notebooks
101- Bash — do not execute shell commands
102- BashOutput — do not execute shell commands
103- KillShell — do not manage processes
104- SubAgent — do not spawn further child sessions
105
106You MAY use these read-only tools:
107- Read — read file contents
108- Glob — list files matching patterns
109- Grep — search code for patterns
110- GetFileInfo — get file metadata
111- WebFetch — fetch web content
112- WebSearch — search the web
113- MemoryNote — write observations to session memory
114
115Requirements:
116- Focus only on the assigned exploration task.
117- Provide clear, structured findings: what you discovered, where the relevant code is, and what it does.
118- Keep output concise but thorough — the parent session needs enough detail to design a plan.
119- If you cannot find something after reasonable searching, say so clearly.
120"#;
121
122#[derive(Debug, Clone)]
124pub struct CreateChildInput {
125 pub parent_session: Session,
126 pub child_id: String,
127 pub title: String,
128 pub responsibility: String,
129 pub assignment_prompt: String,
130 pub subagent_type: String,
131 pub workspace: String,
133 pub model_override: Option<String>,
136 pub model_ref_override: Option<bamboo_domain::ProviderModelRef>,
139 pub runtime_metadata: std::collections::HashMap<String, String>,
141 pub system_prompt_override: Option<String>,
148 pub auto_run: bool,
151 pub reasoning_effort: Option<bamboo_domain::ReasoningEffort>,
158}
159
160#[derive(Debug, Clone)]
162pub struct CreateChildResult {
163 pub child_session_id: String,
164 pub model: String,
165}
166
167#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
169pub struct QueuedInjectedMessage {
170 pub content: String,
171 #[serde(default)]
172 pub created_at: Option<chrono::DateTime<chrono::Utc>>,
173}
174
175#[async_trait]
180pub trait ChildSessionPort: Send + Sync {
181 async fn load_root_session(&self, root_id: &str) -> Result<Session, ChildSessionError>;
182 async fn load_child_for_parent(
183 &self,
184 parent_id: &str,
185 child_id: &str,
186 ) -> Result<Session, ChildSessionError>;
187 async fn save_child_session(&self, child: &mut Session) -> Result<(), ChildSessionError>;
188 async fn is_child_running(&self, child_id: &str) -> bool;
189 async fn list_children(&self, parent_id: &str) -> Vec<ChildSessionEntry>;
190 async fn enqueue_child_run(
191 &self,
192 parent: &Session,
193 child: &Session,
194 ) -> Result<(), ChildSessionError>;
195 async fn cancel_child_run_and_wait(&self, child_id: &str) -> Result<(), ChildSessionError>;
196 async fn delete_child_session(
197 &self,
198 parent_id: &str,
199 child_id: &str,
200 ) -> Result<DeleteChildResult, ChildSessionError>;
201 async fn get_child_runner_info(&self, child_id: &str) -> Option<ChildRunnerInfo>;
203}