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)] pub 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 max_tool_calls_per_session: Option<u32>,
59 pub overflow_config: zeph_tools::OverflowConfig,
60 pub permission_policy: zeph_tools::PermissionPolicy,
61
62 pub model_name: String,
64 pub embed_model: String,
65
66 pub semantic_cache_enabled: bool,
68 pub semantic_cache_threshold: f32,
69 pub semantic_cache_max_candidates: u32,
70
71 pub budget_tokens: usize,
73 pub soft_compaction_threshold: f32,
74 pub hard_compaction_threshold: f32,
75 pub compaction_preserve_tail: usize,
76 pub compaction_cooldown_turns: u8,
77 pub prune_protect_tokens: usize,
78 pub redact_credentials: bool,
79
80 pub security: SecurityConfig,
82 pub timeouts: TimeoutConfig,
83
84 pub learning: LearningConfig,
86 pub document_config: DocumentConfig,
87 pub graph_config: GraphConfig,
88 pub persona_config: PersonaConfig,
89 pub trajectory_config: crate::config::TrajectoryConfig,
90 pub category_config: crate::config::CategoryConfig,
91 pub reasoning_config: zeph_config::ReasoningConfig,
92 pub tree_config: crate::config::TreeConfig,
93 pub microcompact_config: crate::config::MicrocompactConfig,
94 pub autodream_config: crate::config::AutoDreamConfig,
95 pub magic_docs_config: crate::config::MagicDocsConfig,
96 pub anomaly_config: zeph_tools::AnomalyConfig,
97 pub result_cache_config: zeph_tools::ResultCacheConfig,
98 pub utility_config: zeph_tools::UtilityScoringConfig,
99 pub orchestration_config: OrchestrationConfig,
100 pub debug_config: DebugConfig,
101 pub server_compaction: bool,
102
103 pub budget_hint_enabled: bool,
105
106 pub recap: zeph_config::RecapConfig,
108
109 pub loop_min_interval_secs: u64,
111
112 pub secrets: Arc<[(String, Secret)]>,
118}
119
120impl AgentSessionConfig {
121 #[must_use]
126 pub fn from_config(config: &Config, budget_tokens: usize) -> Self {
127 Self {
128 max_tool_iterations: config.agent.max_tool_iterations,
129 max_tool_retries: config.tools.retry.max_attempts,
130 max_retry_duration_secs: config.tools.retry.budget_secs,
131 retry_base_ms: config.tools.retry.base_ms,
132 retry_max_ms: config.tools.retry.max_ms,
133 parameter_reformat_provider: config.tools.retry.parameter_reformat_provider.clone(),
134 tool_repeat_threshold: config.agent.tool_repeat_threshold,
135 tool_summarization: config.tools.summarize_output,
136 tool_call_cutoff: config.memory.tool_call_cutoff,
137 max_tool_calls_per_session: config.tools.max_tool_calls_per_session,
138 overflow_config: config.tools.overflow.clone(),
139 permission_policy: zeph_tools::build_permission_policy(
140 &config.tools,
141 config.security.autonomy_level,
142 ),
143 model_name: config.llm.effective_model().to_owned(),
144 embed_model: crate::provider_factory::stable_skill_embedding_model(config),
145 semantic_cache_enabled: config.llm.semantic_cache_enabled,
146 semantic_cache_threshold: config.llm.semantic_cache_threshold,
147 semantic_cache_max_candidates: config.llm.semantic_cache_max_candidates,
148 budget_tokens,
149 soft_compaction_threshold: config.memory.soft_compaction_threshold,
150 hard_compaction_threshold: config.memory.hard_compaction_threshold,
151 compaction_preserve_tail: config.memory.compaction_preserve_tail,
152 compaction_cooldown_turns: config.memory.compaction_cooldown_turns,
153 prune_protect_tokens: config.memory.prune_protect_tokens,
154 redact_credentials: config.memory.redact_credentials,
155 security: config.security.clone(),
156 timeouts: config.timeouts,
157 learning: config.skills.learning.clone(),
158 document_config: config.memory.documents.clone(),
159 graph_config: config.memory.graph.clone(),
160 persona_config: config.memory.persona.clone(),
161 trajectory_config: config.memory.trajectory.clone(),
162 category_config: config.memory.category.clone(),
163 reasoning_config: config.memory.reasoning.clone(),
164 tree_config: config.memory.tree.clone(),
165 microcompact_config: config.memory.microcompact.clone(),
166 autodream_config: config.memory.autodream.clone(),
167 magic_docs_config: config.magic_docs.clone(),
168 anomaly_config: config.tools.anomaly.clone(),
169 result_cache_config: config.tools.result_cache.clone(),
170 utility_config: config.tools.utility.clone(),
171 orchestration_config: config.orchestration.clone(),
172 debug_config: config.debug.clone(),
173 server_compaction: config.llm.providers.iter().any(|e| e.server_compaction),
174 budget_hint_enabled: config.agent.budget_hint_enabled,
175 secrets: config
176 .secrets
177 .custom
178 .iter()
179 .map(|(k, v)| (k.clone(), Secret::new(v.expose().to_owned())))
180 .collect::<Vec<_>>()
181 .into(),
182 recap: config.session.recap.clone(),
183 loop_min_interval_secs: config.cli.loop_.min_interval_secs,
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn from_config_maps_all_fields() {
194 let config = Config::default();
195 let budget = 100_000;
196 let sc = AgentSessionConfig::from_config(&config, budget);
197
198 assert_eq!(sc.max_tool_iterations, config.agent.max_tool_iterations);
199 assert_eq!(sc.max_tool_retries, config.tools.retry.max_attempts);
200 assert_eq!(sc.max_retry_duration_secs, config.tools.retry.budget_secs);
201 assert_eq!(sc.retry_base_ms, config.tools.retry.base_ms);
202 assert_eq!(sc.retry_max_ms, config.tools.retry.max_ms);
203 assert_eq!(
204 sc.parameter_reformat_provider,
205 config.tools.retry.parameter_reformat_provider
206 );
207 assert_eq!(sc.tool_repeat_threshold, config.agent.tool_repeat_threshold);
208 assert_eq!(sc.tool_summarization, config.tools.summarize_output);
209 assert_eq!(sc.tool_call_cutoff, config.memory.tool_call_cutoff);
210 assert_eq!(sc.model_name, config.llm.effective_model());
211 assert_eq!(
212 sc.embed_model,
213 crate::provider_factory::stable_skill_embedding_model(&config)
214 );
215 assert_eq!(sc.semantic_cache_enabled, config.llm.semantic_cache_enabled);
216 assert!(
217 (sc.semantic_cache_threshold - config.llm.semantic_cache_threshold).abs()
218 < f32::EPSILON
219 );
220 assert_eq!(
221 sc.semantic_cache_max_candidates,
222 config.llm.semantic_cache_max_candidates
223 );
224 assert_eq!(sc.budget_tokens, budget);
225 assert!(
226 (sc.soft_compaction_threshold - config.memory.soft_compaction_threshold).abs()
227 < f32::EPSILON
228 );
229 assert!(
230 (sc.hard_compaction_threshold - config.memory.hard_compaction_threshold).abs()
231 < f32::EPSILON
232 );
233 assert_eq!(
234 sc.compaction_preserve_tail,
235 config.memory.compaction_preserve_tail
236 );
237 assert_eq!(
238 sc.compaction_cooldown_turns,
239 config.memory.compaction_cooldown_turns
240 );
241 assert_eq!(sc.prune_protect_tokens, config.memory.prune_protect_tokens);
242 assert_eq!(sc.redact_credentials, config.memory.redact_credentials);
243 assert_eq!(sc.graph_config.enabled, config.memory.graph.enabled);
244 assert_eq!(
245 sc.orchestration_config.enabled,
246 config.orchestration.enabled
247 );
248 assert_eq!(
249 sc.orchestration_config.max_tasks,
250 config.orchestration.max_tasks
251 );
252 assert_eq!(sc.anomaly_config.enabled, config.tools.anomaly.enabled);
253 assert_eq!(
254 sc.result_cache_config.enabled,
255 config.tools.result_cache.enabled
256 );
257 assert_eq!(
258 sc.result_cache_config.ttl_secs,
259 config.tools.result_cache.ttl_secs
260 );
261 assert_eq!(sc.debug_config.enabled, config.debug.enabled);
262 assert_eq!(
263 sc.document_config.rag_enabled,
264 config.memory.documents.rag_enabled
265 );
266 assert_eq!(
267 sc.overflow_config.threshold,
268 config.tools.overflow.threshold
269 );
270 assert_eq!(
271 sc.permission_policy.autonomy_level(),
272 config.security.autonomy_level
273 );
274 assert_eq!(sc.security.autonomy_level, config.security.autonomy_level);
275 assert_eq!(sc.timeouts.llm_seconds, config.timeouts.llm_seconds);
276 assert_eq!(sc.learning.enabled, config.skills.learning.enabled);
277 assert_eq!(
278 sc.server_compaction,
279 config.llm.providers.iter().any(|e| e.server_compaction)
280 );
281 assert_eq!(sc.secrets.len(), config.secrets.custom.len());
282 assert_eq!(sc.recap.on_resume, config.session.recap.on_resume);
283 assert_eq!(sc.recap.max_tokens, config.session.recap.max_tokens);
284 }
285}