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 /// and background work (context compression, summarization).
102 ///
103 /// This is the same concept as `background_model_name` — both refer to the
104 /// same cheap model. The separate field exists only because different call
105 /// sites have different fallback requirements (foreground tasks may fall back
106 /// to `model_name`, while background tasks must not).
107 ///
108 /// Call sites may fall back to `model_name` when this is unset.
109 pub fast_model_name: Option<String>,
110 /// Fast/cheap model for background summarization and context compression.
111 ///
112 /// This is the same model as `fast_model_name` (both are resolved from the
113 /// same `resolve_background_model` source). The separate field exists because
114 /// background tasks must not silently fall back to the main interaction model.
115 pub background_model_name: Option<String>,
116 /// Model for planning/coordination tasks (task decomposition, architecture).
117 /// Falls back to `model_name` when unset.
118 pub planning_model_name: Option<String>,
119 /// Model for search/navigation tasks (grep, file listing, symbol resolution).
120 /// Falls back to `fast_model_name` when unset.
121 pub search_model_name: Option<String>,
122 /// Custom instructions for conversation summarization, injected into the
123 /// LLM summary prompt. Lets users control what the summary focuses on.
124 ///
125 /// Resolution order: session-level > config-level > built-in defaults.
126 pub compression_instructions: Option<String>,
127 /// Dedicated model for summarization. Falls back to `background_model_name`.
128 pub summarization_model_name: Option<String>,
129 /// Optional provider override for background/fast model LLM calls.
130 ///
131 /// When set, context compression, summarization, and other background
132 /// model calls use this provider instead of the shared agent loop provider.
133 pub background_model_provider: Option<Arc<dyn LLMProvider>>,
134 /// Provider name used for provider-specific request behavior.
135 pub provider_name: Option<String>,
136 /// Optional request-time reasoning effort override.
137 pub reasoning_effort: Option<ReasoningEffort>,
138 /// Bamboo application data directory (typically `~/.bamboo`).
139 ///
140 /// Used by runtime features that persist auxiliary artifacts outside the
141 /// session store, such as durable plan mode files under `~/.bamboo/plan`.
142 pub app_data_dir: Option<PathBuf>,
143 /// Tool names that should be excluded from schemas sent to the LLM.
144 pub disabled_tools: BTreeSet<String>,
145 /// Token budget for context management (optional, defaults to model's limits)
146 pub token_budget: Option<TokenBudget>,
147 /// Optional image fallback behavior applied to *LLM requests only* (never persisted).
148 ///
149 /// This is intended for text-only provider paths where image parts must be degraded
150 /// (placeholder / OCR / error) without leaking into stored session history or UI.
151 pub image_fallback: Option<ImageFallbackConfig>,
152 /// Feature flags controlling prompt-time memory injection behavior.
153 pub prompt_memory_flags: PromptMemoryFlags,
154 /// Maximum tool calls allowed per round (default: 80).
155 pub max_tool_calls_per_round: usize,
156 /// Maximum consecutive failures per tool before circuit breaker (default: 3).
157 pub max_consecutive_failures_per_tool: usize,
158 /// Tool names that require strict argument validation.
159 pub strict_argument_tool_names: Vec<String>,
160 /// Per-tool execution timeout in seconds (default: 120).
161 pub per_tool_timeout_secs: u64,
162 /// Parallel batch execution timeout in seconds (default: 300).
163 pub parallel_batch_timeout_secs: u64,
164 /// Permission mode for this execution (default: None = use PermissionConfig's mode).
165 pub permission_mode: Option<PermissionMode>,
166 /// Enable dynamic per-round model routing based on task complexity.
167 /// When true, the pipeline classifies complexity at each round end and
168 /// stores the result in session metadata.
169 pub features_dynamic_model_routing: bool,
170}
171
172impl Default for AgentLoopConfig {
173 fn default() -> Self {
174 Self {
175 max_rounds: 200,
176 system_prompt: None,
177 disabled_skill_ids: BTreeSet::new(),
178 selected_skill_ids: None,
179 selected_skill_mode: None,
180 additional_tool_schemas: Vec::new(),
181 tool_registry: Arc::new(ToolRegistry::new()),
182 composition_executor: None,
183 skill_manager: None,
184 skip_initial_user_message: false,
185 storage: None,
186 persistence: None,
187 attachment_reader: None,
188 metrics_collector: None,
189 model_name: None,
190 fast_model_name: None,
191 background_model_name: None,
192 planning_model_name: None,
193 search_model_name: None,
194 compression_instructions: None,
195 summarization_model_name: None,
196 background_model_provider: None,
197 provider_name: None,
198 reasoning_effort: None,
199 app_data_dir: None,
200 disabled_tools: BTreeSet::new(),
201 token_budget: None,
202 image_fallback: None,
203 prompt_memory_flags: PromptMemoryFlags::default(),
204 max_tool_calls_per_round: 80,
205 max_consecutive_failures_per_tool: 3,
206 strict_argument_tool_names: vec![
207 "Write".into(),
208 "Edit".into(),
209 "NotebookEdit".into(),
210 "apply_patch".into(),
211 "Bash".into(),
212 "Task".into(),
213 "SubAgent".into(),
214 "scheduler".into(),
215 "sub_session_manager".into(),
216 "session_note".into(),
217 "memory_note".into(),
218 ],
219 per_tool_timeout_secs: 120,
220 parallel_batch_timeout_secs: 300,
221 permission_mode: None,
222 features_dynamic_model_routing: false,
223 }
224 }
225}
226
227#[cfg(test)]
228mod tests;