bamboo_engine/runtime/config.rs
1use std::collections::BTreeSet;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use crate::metrics::MetricsCollector;
6use crate::skills::SkillManager;
7use bamboo_agent_core::composition::CompositionExecutor;
8use bamboo_agent_core::storage::AttachmentReader;
9use bamboo_agent_core::storage::Storage;
10use bamboo_agent_core::tools::ToolSchema;
11use bamboo_compression::TokenBudget;
12use bamboo_domain::ReasoningEffort;
13use bamboo_domain::RuntimeSessionPersistence;
14use bamboo_infrastructure::config::PermissionMode;
15use bamboo_infrastructure::LLMProvider;
16use bamboo_infrastructure::MemoryConfig;
17use bamboo_tools::ToolRegistry;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ImageFallbackMode {
21 Placeholder,
22 Error,
23 Ocr,
24 /// Use a vision-capable LLM to describe the image, then replace the image
25 /// with the textual description so that text-only models can understand
26 /// the content.
27 Vision,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct ImageFallbackConfig {
32 pub mode: ImageFallbackMode,
33 /// Vision model name for `Vision` mode. Falls back to the session's main model
34 /// when `None`.
35 pub vision_model: Option<String>,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub struct PromptMemoryFlags {
40 pub project_prompt_injection: bool,
41 pub relevant_recall: bool,
42 pub relevant_recall_rerank: bool,
43 pub project_first_dream: bool,
44}
45
46impl Default for PromptMemoryFlags {
47 fn default() -> Self {
48 Self {
49 project_prompt_injection: true,
50 relevant_recall: true,
51 relevant_recall_rerank: false,
52 project_first_dream: true,
53 }
54 }
55}
56
57impl From<&MemoryConfig> for PromptMemoryFlags {
58 fn from(value: &MemoryConfig) -> Self {
59 Self {
60 project_prompt_injection: value.project_prompt_injection,
61 relevant_recall: value.relevant_recall,
62 relevant_recall_rerank: value.relevant_recall_rerank,
63 project_first_dream: value.project_first_dream,
64 }
65 }
66}
67
68/// Configuration for the agent loop.
69pub struct AgentLoopConfig {
70 pub max_rounds: usize,
71 pub system_prompt: Option<String>,
72 /// Skill IDs that are disabled globally for this execution.
73 pub disabled_skill_ids: BTreeSet<String>,
74 /// Optional explicit skill selection for this execution.
75 /// When set, only these skill IDs are considered for skill context and allowlists.
76 pub selected_skill_ids: Option<Vec<String>>,
77 /// Optional active skill mode for this execution.
78 ///
79 /// When set, skill discovery prefers `skills-<mode>` directories over generic
80 /// directories for the same skill id.
81 pub selected_skill_mode: Option<String>,
82 pub additional_tool_schemas: Vec<ToolSchema>,
83 pub tool_registry: Arc<ToolRegistry>,
84 pub composition_executor: Option<Arc<CompositionExecutor>>,
85 pub skill_manager: Option<Arc<SkillManager>>,
86 /// If true, skip appending the initial user message (already present in session).
87 pub skip_initial_user_message: bool,
88 /// Optional storage for persisting session changes
89 pub storage: Option<Arc<dyn Storage>>,
90 /// Optional runtime persistence for non-authoritative session saves.
91 /// When set, engine save sites use this instead of `storage` for writes.
92 pub persistence: Option<Arc<dyn RuntimeSessionPersistence>>,
93 /// Optional attachment reader for resolving `bamboo-attachment://...` references
94 /// into `data:` URLs for upstream providers. This must not mutate session storage.
95 pub attachment_reader: Option<Arc<dyn AttachmentReader>>,
96 /// Optional asynchronous metrics collector
97 pub metrics_collector: Option<MetricsCollector>,
98 /// Model name used for metrics attribution
99 pub model_name: Option<String>,
100 /// Fast/cheap model for lightweight tasks (task evaluation, search, etc.).
101 ///
102 /// Call sites may fall back to `model_name` when this is unset.
103 pub fast_model_name: Option<String>,
104 /// Optional provider override for lightweight fast-model LLM calls.
105 pub fast_model_provider: Option<Arc<dyn LLMProvider>>,
106 /// Fast/cheap model for memory/background tasks.
107 ///
108 /// This must not silently fall back to the main interaction model.
109 pub background_model_name: Option<String>,
110
111 /// Model for planning/coordination tasks (task decomposition, architecture).
112 /// Falls back to `model_name` when unset.
113 pub planning_model_name: Option<String>,
114 /// Model for search/navigation tasks (grep, file listing, symbol resolution).
115 /// Falls back to `fast_model_name` when unset.
116 pub search_model_name: Option<String>,
117 /// Custom instructions for conversation summarization, injected into the
118 /// LLM summary prompt. Lets users control what the summary focuses on.
119 ///
120 /// Resolution order: session-level > config-level > built-in defaults.
121 pub compression_instructions: Option<String>,
122 /// Dedicated model for summarization. Falls back to `background_model_name`.
123 pub summarization_model_name: Option<String>,
124 /// Optional provider override for memory/background model LLM calls.
125 ///
126 /// When set, memory recall rerank and other memory/background tasks use this
127 /// provider instead of the shared agent loop provider.
128 pub background_model_provider: Option<Arc<dyn LLMProvider>>,
129 /// Optional provider override for summarization / context compression calls.
130 ///
131 /// When set, conversation/task summarization uses this provider instead of
132 /// the shared agent loop provider.
133 pub summarization_model_provider: Option<Arc<dyn LLMProvider>>,
134 /// Provider routing key used for provider-specific request behavior.
135 ///
136 /// In multi-instance mode this may be the instance id.
137 pub provider_name: Option<String>,
138 /// Underlying provider type (for example `openai`, `anthropic`, `copilot`).
139 ///
140 /// This is distinct from `provider_name` so provider-specific behavior can
141 /// remain correct when routing keys are instance ids.
142 pub provider_type: Option<String>,
143 /// Optional request-time reasoning effort override.
144 pub reasoning_effort: Option<ReasoningEffort>,
145 /// Bamboo application data directory (typically `~/.bamboo`).
146 ///
147 /// Used by runtime features that persist auxiliary artifacts outside the
148 /// session store, such as durable plan mode files under `~/.bamboo/plan`.
149 pub app_data_dir: Option<PathBuf>,
150 /// Tool names that should be excluded from schemas sent to the LLM.
151 pub disabled_tools: BTreeSet<String>,
152 /// Token budget for context management (optional, defaults to model's limits)
153 pub token_budget: Option<TokenBudget>,
154 /// Optional image fallback behavior applied to *LLM requests only* (never persisted).
155 ///
156 /// This is intended for text-only provider paths where image parts must be degraded
157 /// (placeholder / OCR / error) without leaking into stored session history or UI.
158 pub image_fallback: Option<ImageFallbackConfig>,
159 /// Feature flags controlling prompt-time memory injection behavior.
160 pub prompt_memory_flags: PromptMemoryFlags,
161 /// Maximum tool calls allowed per round (default: 80).
162 pub max_tool_calls_per_round: usize,
163 /// Maximum consecutive failures per tool before circuit breaker (default: 3).
164 pub max_consecutive_failures_per_tool: usize,
165 /// Tool names that require strict argument validation.
166 pub strict_argument_tool_names: Vec<String>,
167 /// Per-tool execution timeout in seconds (default: 120).
168 pub per_tool_timeout_secs: u64,
169 /// Parallel batch execution timeout in seconds (default: 300).
170 pub parallel_batch_timeout_secs: u64,
171 /// Permission mode for this execution (default: None = use PermissionConfig's mode).
172 pub permission_mode: Option<PermissionMode>,
173 /// Enable dynamic per-round model routing based on task complexity.
174 /// When true, the pipeline classifies complexity at each round end and
175 /// stores the result in session metadata.
176 pub features_dynamic_model_routing: bool,
177}
178
179impl Default for AgentLoopConfig {
180 fn default() -> Self {
181 Self {
182 max_rounds: 200,
183 system_prompt: None,
184 disabled_skill_ids: BTreeSet::new(),
185 selected_skill_ids: None,
186 selected_skill_mode: None,
187 additional_tool_schemas: Vec::new(),
188 tool_registry: Arc::new(ToolRegistry::new()),
189 composition_executor: None,
190 skill_manager: None,
191 skip_initial_user_message: false,
192 storage: None,
193 persistence: None,
194 attachment_reader: None,
195 metrics_collector: None,
196 model_name: None,
197 fast_model_name: None,
198 fast_model_provider: None,
199 background_model_name: None,
200 planning_model_name: None,
201 search_model_name: None,
202 compression_instructions: None,
203 summarization_model_name: None,
204 background_model_provider: None,
205 summarization_model_provider: None,
206 provider_name: None,
207 provider_type: None,
208 reasoning_effort: None,
209 app_data_dir: None,
210 disabled_tools: BTreeSet::new(),
211 token_budget: None,
212 image_fallback: None,
213 prompt_memory_flags: PromptMemoryFlags::default(),
214 max_tool_calls_per_round: 80,
215 max_consecutive_failures_per_tool: 3,
216 strict_argument_tool_names: vec![
217 "Write".into(),
218 "Edit".into(),
219 "NotebookEdit".into(),
220 "apply_patch".into(),
221 "Bash".into(),
222 "Task".into(),
223 "SubAgent".into(),
224 "scheduler".into(),
225 "sub_session_manager".into(),
226 "session_note".into(),
227 "memory_note".into(),
228 ],
229 per_tool_timeout_secs: 120,
230 parallel_batch_timeout_secs: 300,
231 permission_mode: None,
232 features_dynamic_model_routing: false,
233 }
234 }
235}
236
237#[cfg(test)]
238mod tests;