1use std::sync::Arc;
5
6use crate::config::{
7 Config, DebugConfig, DocumentConfig, GraphConfig, LearningConfig, OrchestrationConfig,
8 PersonaConfig, SecurityConfig, TimeoutConfig,
9};
10use crate::vault::Secret;
11
12pub const CONTEXT_BUDGET_RESERVE_RATIO: f32 = 0.20;
16
17#[derive(Clone)]
46#[allow(clippy::struct_excessive_bools)]
47pub struct AgentSessionConfig {
48 pub max_tool_iterations: usize,
50 pub max_tool_retries: usize,
51 pub max_retry_duration_secs: u64,
52 pub retry_base_ms: u64,
53 pub retry_max_ms: u64,
54 pub parameter_reformat_provider: String,
55 pub tool_repeat_threshold: usize,
56 pub tool_summarization: bool,
57 pub tool_call_cutoff: usize,
58 pub overflow_config: zeph_tools::OverflowConfig,
59 pub permission_policy: zeph_tools::PermissionPolicy,
60
61 pub model_name: String,
63 pub embed_model: String,
64
65 pub semantic_cache_enabled: bool,
67 pub semantic_cache_threshold: f32,
68 pub semantic_cache_max_candidates: u32,
69
70 pub budget_tokens: usize,
72 pub soft_compaction_threshold: f32,
73 pub hard_compaction_threshold: f32,
74 pub compaction_preserve_tail: usize,
75 pub compaction_cooldown_turns: u8,
76 pub prune_protect_tokens: usize,
77 pub redact_credentials: bool,
78
79 pub security: SecurityConfig,
81 pub timeouts: TimeoutConfig,
82
83 pub learning: LearningConfig,
85 pub document_config: DocumentConfig,
86 pub graph_config: GraphConfig,
87 pub persona_config: PersonaConfig,
88 pub anomaly_config: zeph_tools::AnomalyConfig,
89 pub result_cache_config: zeph_tools::ResultCacheConfig,
90 pub utility_config: zeph_tools::UtilityScoringConfig,
91 pub orchestration_config: OrchestrationConfig,
92 pub debug_config: DebugConfig,
93 pub server_compaction: bool,
94
95 pub budget_hint_enabled: bool,
97
98 pub secrets: Arc<[(String, Secret)]>,
104}
105
106impl AgentSessionConfig {
107 #[must_use]
112 pub fn from_config(config: &Config, budget_tokens: usize) -> Self {
113 Self {
114 max_tool_iterations: config.agent.max_tool_iterations,
115 max_tool_retries: config.tools.retry.max_attempts,
116 max_retry_duration_secs: config.tools.retry.budget_secs,
117 retry_base_ms: config.tools.retry.base_ms,
118 retry_max_ms: config.tools.retry.max_ms,
119 parameter_reformat_provider: config.tools.retry.parameter_reformat_provider.clone(),
120 tool_repeat_threshold: config.agent.tool_repeat_threshold,
121 tool_summarization: config.tools.summarize_output,
122 tool_call_cutoff: config.memory.tool_call_cutoff,
123 overflow_config: config.tools.overflow.clone(),
124 permission_policy: config
125 .tools
126 .permission_policy(config.security.autonomy_level),
127 model_name: config.llm.effective_model().to_owned(),
128 embed_model: crate::bootstrap::effective_embedding_model(config),
129 semantic_cache_enabled: config.llm.semantic_cache_enabled,
130 semantic_cache_threshold: config.llm.semantic_cache_threshold,
131 semantic_cache_max_candidates: config.llm.semantic_cache_max_candidates,
132 budget_tokens,
133 soft_compaction_threshold: config.memory.soft_compaction_threshold,
134 hard_compaction_threshold: config.memory.hard_compaction_threshold,
135 compaction_preserve_tail: config.memory.compaction_preserve_tail,
136 compaction_cooldown_turns: config.memory.compaction_cooldown_turns,
137 prune_protect_tokens: config.memory.prune_protect_tokens,
138 redact_credentials: config.memory.redact_credentials,
139 security: config.security.clone(),
140 timeouts: config.timeouts,
141 learning: config.skills.learning.clone(),
142 document_config: config.memory.documents.clone(),
143 graph_config: config.memory.graph.clone(),
144 persona_config: config.memory.persona.clone(),
145 anomaly_config: config.tools.anomaly.clone(),
146 result_cache_config: config.tools.result_cache.clone(),
147 utility_config: config.tools.utility.clone(),
148 orchestration_config: config.orchestration.clone(),
149 debug_config: config.debug.clone(),
150 server_compaction: config.llm.providers.iter().any(|e| e.server_compaction),
151 budget_hint_enabled: config.agent.budget_hint_enabled,
152 secrets: config
153 .secrets
154 .custom
155 .iter()
156 .map(|(k, v)| (k.clone(), Secret::new(v.expose().to_owned())))
157 .collect::<Vec<_>>()
158 .into(),
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn from_config_maps_all_fields() {
169 let config = Config::default();
170 let budget = 100_000;
171 let sc = AgentSessionConfig::from_config(&config, budget);
172
173 assert_eq!(sc.max_tool_iterations, config.agent.max_tool_iterations);
174 assert_eq!(sc.max_tool_retries, config.tools.retry.max_attempts);
175 assert_eq!(sc.max_retry_duration_secs, config.tools.retry.budget_secs);
176 assert_eq!(sc.retry_base_ms, config.tools.retry.base_ms);
177 assert_eq!(sc.retry_max_ms, config.tools.retry.max_ms);
178 assert_eq!(
179 sc.parameter_reformat_provider,
180 config.tools.retry.parameter_reformat_provider
181 );
182 assert_eq!(sc.tool_repeat_threshold, config.agent.tool_repeat_threshold);
183 assert_eq!(sc.tool_summarization, config.tools.summarize_output);
184 assert_eq!(sc.tool_call_cutoff, config.memory.tool_call_cutoff);
185 assert_eq!(sc.model_name, config.llm.effective_model());
186 assert_eq!(
187 sc.embed_model,
188 crate::bootstrap::effective_embedding_model(&config)
189 );
190 assert_eq!(sc.semantic_cache_enabled, config.llm.semantic_cache_enabled);
191 assert!(
192 (sc.semantic_cache_threshold - config.llm.semantic_cache_threshold).abs()
193 < f32::EPSILON
194 );
195 assert_eq!(
196 sc.semantic_cache_max_candidates,
197 config.llm.semantic_cache_max_candidates
198 );
199 assert_eq!(sc.budget_tokens, budget);
200 assert!(
201 (sc.soft_compaction_threshold - config.memory.soft_compaction_threshold).abs()
202 < f32::EPSILON
203 );
204 assert!(
205 (sc.hard_compaction_threshold - config.memory.hard_compaction_threshold).abs()
206 < f32::EPSILON
207 );
208 assert_eq!(
209 sc.compaction_preserve_tail,
210 config.memory.compaction_preserve_tail
211 );
212 assert_eq!(
213 sc.compaction_cooldown_turns,
214 config.memory.compaction_cooldown_turns
215 );
216 assert_eq!(sc.prune_protect_tokens, config.memory.prune_protect_tokens);
217 assert_eq!(sc.redact_credentials, config.memory.redact_credentials);
218 assert_eq!(sc.graph_config.enabled, config.memory.graph.enabled);
219 assert_eq!(
220 sc.orchestration_config.enabled,
221 config.orchestration.enabled
222 );
223 assert_eq!(
224 sc.orchestration_config.max_tasks,
225 config.orchestration.max_tasks
226 );
227 assert_eq!(sc.anomaly_config.enabled, config.tools.anomaly.enabled);
228 assert_eq!(
229 sc.result_cache_config.enabled,
230 config.tools.result_cache.enabled
231 );
232 assert_eq!(
233 sc.result_cache_config.ttl_secs,
234 config.tools.result_cache.ttl_secs
235 );
236 assert_eq!(sc.debug_config.enabled, config.debug.enabled);
237 assert_eq!(
238 sc.document_config.rag_enabled,
239 config.memory.documents.rag_enabled
240 );
241 assert_eq!(
242 sc.overflow_config.threshold,
243 config.tools.overflow.threshold
244 );
245 assert_eq!(
246 sc.permission_policy.autonomy_level(),
247 config.security.autonomy_level
248 );
249 assert_eq!(sc.security.autonomy_level, config.security.autonomy_level);
250 assert_eq!(sc.timeouts.llm_seconds, config.timeouts.llm_seconds);
251 assert_eq!(sc.learning.enabled, config.skills.learning.enabled);
252 assert_eq!(
253 sc.server_compaction,
254 config.llm.providers.iter().any(|e| e.server_compaction)
255 );
256 assert_eq!(sc.secrets.len(), config.secrets.custom.len());
257 }
258}