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)]
49#[allow(clippy::struct_excessive_bools)] pub struct AgentSessionConfig {
51 pub max_tool_iterations: usize,
53 pub max_tool_retries: usize,
54 pub max_retry_duration_secs: u64,
55 pub retry_base_ms: u64,
56 pub retry_max_ms: u64,
57 pub parameter_reformat_provider: String,
58 pub tool_repeat_threshold: usize,
59 pub tool_summarization: bool,
60 pub tool_call_cutoff: usize,
61 pub max_tool_calls_per_session: Option<u32>,
62 pub overflow_config: zeph_tools::OverflowConfig,
63 pub permission_policy: zeph_tools::PermissionPolicy,
64
65 pub model_name: String,
67 pub embed_model: String,
68
69 pub semantic_cache_enabled: bool,
71 pub semantic_cache_threshold: f32,
72 pub semantic_cache_max_candidates: u32,
73
74 pub budget_tokens: usize,
76 pub soft_compaction_threshold: f32,
77 pub hard_compaction_threshold: f32,
78 pub compaction_preserve_tail: usize,
79 pub compaction_cooldown_turns: u8,
80 pub prune_protect_tokens: usize,
81 pub redact_credentials: bool,
82 pub consent_gate: zeph_config::ConsentGateConfig,
84
85 pub security: SecurityConfig,
87 pub timeouts: TimeoutConfig,
88
89 pub learning: LearningConfig,
91 pub document_config: DocumentConfig,
92 pub graph_config: GraphConfig,
93 pub persona_config: PersonaConfig,
94 pub trajectory_config: crate::config::TrajectoryConfig,
95 pub category_config: crate::config::CategoryConfig,
96 pub reasoning_config: zeph_config::ReasoningConfig,
97 pub memcot_config: zeph_config::MemCotConfig,
98 pub tree_config: crate::config::TreeConfig,
99 pub microcompact_config: crate::config::MicrocompactConfig,
100 pub autodream_config: crate::config::AutoDreamConfig,
101 pub magic_docs_config: crate::config::MagicDocsConfig,
102 pub acon_config: zeph_config::AconConfig,
104 pub arc_config: zeph_config::ArcCompactionConfig,
106 pub anomaly_config: zeph_tools::AnomalyConfig,
107 pub result_cache_config: zeph_tools::ResultCacheConfig,
108 pub utility_config: zeph_tools::UtilityScoringConfig,
109 pub orchestration_config: OrchestrationConfig,
110 pub store_config: zeph_config::CrossThreadStoreConfig,
115 pub debug_config: DebugConfig,
116 pub server_compaction: bool,
117
118 pub budget_hint_enabled: bool,
120
121 pub time_reminder_enabled: bool,
124 pub time_reminder_interval_requests: u32,
126
127 pub subagent_skill_token_budget: usize,
130
131 pub recap: zeph_config::RecapConfig,
133
134 pub resume: zeph_config::ResumeConfig,
136
137 pub loop_min_interval_secs: u64,
139
140 pub goal_config: zeph_config::GoalConfig,
142
143 pub secrets: Arc<[(String, Secret)]>,
149
150 pub fidelity_config: Option<zeph_config::FidelityConfig>,
152
153 pub mcp_media: zeph_config::McpMediaConfig,
156
157 pub media_passthrough_note_enabled: bool,
161
162 pub plugins_reputation: zeph_config::plugins::ReputationConfig,
166}
167
168impl AgentSessionConfig {
169 #[must_use]
174 pub fn from_config(config: &Config, budget_tokens: usize) -> Self {
175 Self {
176 max_tool_iterations: config.agent.max_tool_iterations,
177 max_tool_retries: config.tools.retry.max_attempts,
178 max_retry_duration_secs: config.tools.retry.budget_secs,
179 retry_base_ms: config.tools.retry.base_ms,
180 retry_max_ms: config.tools.retry.max_ms,
181 parameter_reformat_provider: config.tools.retry.parameter_reformat_provider.to_string(),
182 tool_repeat_threshold: config.agent.tool_repeat_threshold,
183 tool_summarization: config.tools.summarize_output,
184 tool_call_cutoff: config.memory.tool_call_cutoff,
185 max_tool_calls_per_session: config.tools.max_tool_calls_per_session,
186 overflow_config: config.tools.overflow.clone(),
187 permission_policy: zeph_tools::build_permission_policy(
188 &config.tools,
189 config.security.autonomy_level,
190 ),
191 model_name: config.llm.effective_model().to_owned(),
192 embed_model: config.llm.stable_skill_embedding_model(),
193 semantic_cache_enabled: config.llm.semantic_cache_enabled,
194 semantic_cache_threshold: config.llm.semantic_cache_threshold,
195 semantic_cache_max_candidates: config.llm.semantic_cache_max_candidates,
196 budget_tokens,
197 soft_compaction_threshold: config.memory.soft_compaction_threshold,
198 hard_compaction_threshold: config.memory.hard_compaction_threshold,
199 compaction_preserve_tail: config.memory.compaction_preserve_tail,
200 compaction_cooldown_turns: config.memory.compaction_cooldown_turns,
201 prune_protect_tokens: config.memory.prune_protect_tokens,
202 redact_credentials: config.memory.redact_credentials,
203 consent_gate: config.memory.consent_gate.clone(),
204 security: config.security.clone(),
205 timeouts: config.timeouts,
206 learning: config.skills.learning.clone(),
207 document_config: config.memory.documents.clone(),
208 graph_config: config.memory.graph.clone(),
209 persona_config: config.memory.persona.clone(),
210 trajectory_config: config.memory.trajectory.clone(),
211 category_config: config.memory.category.clone(),
212 reasoning_config: config.memory.reasoning.clone(),
213 memcot_config: config.memory.memcot.clone(),
214 tree_config: config.memory.tree.clone(),
215 microcompact_config: config.memory.microcompact.clone(),
216 autodream_config: config.memory.autodream.clone(),
217 magic_docs_config: config.magic_docs.clone(),
218 acon_config: config.memory.compression.acon.clone(),
219 arc_config: config.memory.compression.arc.clone(),
220 anomaly_config: config.tools.anomaly.clone(),
221 result_cache_config: config.tools.result_cache.clone(),
222 utility_config: config.tools.utility.clone(),
223 orchestration_config: config.orchestration.clone(),
224 store_config: config.memory.store.clone(),
225 debug_config: config.debug.clone(),
226 server_compaction: config.llm.providers.iter().any(|e| e.server_compaction),
227 budget_hint_enabled: config.agent.budget_hint_enabled,
228 time_reminder_enabled: config.agent.time_reminder_enabled,
229 time_reminder_interval_requests: config.agent.time_reminder_interval_requests,
230 subagent_skill_token_budget: config.skills.subagent_skill_token_budget.get(),
231 secrets: config
232 .secrets
233 .custom
234 .iter()
235 .map(|(k, v)| (k.clone(), Secret::new(v.expose().to_owned())))
236 .collect::<Vec<_>>()
237 .into(),
238 recap: config.session.recap.clone(),
239 resume: config.session.resume.clone(),
240 loop_min_interval_secs: config.cli.loop_.min_interval_secs,
241 goal_config: config.goals.clone(),
242 fidelity_config: {
243 let fc = config.memory.fidelity.clone();
244 if let Some(ref cfg) = fc
245 && let Err(e) = cfg.validate()
246 {
247 tracing::warn!("fidelity config invalid, scoring disabled: {e}");
248 }
249 fc
250 },
251 mcp_media: config.mcp.media.clone(),
252 media_passthrough_note_enabled: config.mcp.servers.iter().any(|s| s.media_passthrough),
253 plugins_reputation: config.plugins.reputation.clone(),
254 }
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
263 #[allow(clippy::too_many_lines)]
264 fn from_config_maps_all_fields() {
265 let config = Config::default();
266 let budget = 100_000;
267 let sc = AgentSessionConfig::from_config(&config, budget);
268
269 assert_eq!(sc.max_tool_iterations, config.agent.max_tool_iterations);
270 assert_eq!(sc.max_tool_retries, config.tools.retry.max_attempts);
271 assert_eq!(sc.max_retry_duration_secs, config.tools.retry.budget_secs);
272 assert_eq!(sc.retry_base_ms, config.tools.retry.base_ms);
273 assert_eq!(sc.retry_max_ms, config.tools.retry.max_ms);
274 assert_eq!(
275 sc.parameter_reformat_provider,
276 config.tools.retry.parameter_reformat_provider.as_str()
277 );
278 assert_eq!(sc.tool_repeat_threshold, config.agent.tool_repeat_threshold);
279 assert_eq!(sc.tool_summarization, config.tools.summarize_output);
280 assert_eq!(sc.tool_call_cutoff, config.memory.tool_call_cutoff);
281 assert_eq!(sc.model_name, config.llm.effective_model());
282 assert_eq!(sc.embed_model, config.llm.stable_skill_embedding_model());
283 assert_eq!(sc.semantic_cache_enabled, config.llm.semantic_cache_enabled);
284 assert!(
285 (sc.semantic_cache_threshold - config.llm.semantic_cache_threshold).abs()
286 < f32::EPSILON
287 );
288 assert_eq!(
289 sc.semantic_cache_max_candidates,
290 config.llm.semantic_cache_max_candidates
291 );
292 assert_eq!(sc.budget_tokens, budget);
293 assert!(
294 (sc.soft_compaction_threshold - config.memory.soft_compaction_threshold).abs()
295 < f32::EPSILON
296 );
297 assert!(
298 (sc.hard_compaction_threshold - config.memory.hard_compaction_threshold).abs()
299 < f32::EPSILON
300 );
301 assert_eq!(
302 sc.compaction_preserve_tail,
303 config.memory.compaction_preserve_tail
304 );
305 assert_eq!(
306 sc.compaction_cooldown_turns,
307 config.memory.compaction_cooldown_turns
308 );
309 assert_eq!(sc.prune_protect_tokens, config.memory.prune_protect_tokens);
310 assert_eq!(sc.redact_credentials, config.memory.redact_credentials);
311 assert_eq!(sc.graph_config.enabled, config.memory.graph.enabled);
312 assert_eq!(
313 sc.orchestration_config.enabled,
314 config.orchestration.enabled
315 );
316 assert_eq!(
317 sc.orchestration_config.max_tasks,
318 config.orchestration.max_tasks
319 );
320 assert_eq!(sc.store_config.enabled, config.memory.store.enabled);
321 assert_eq!(
322 sc.store_config.max_value_bytes,
323 config.memory.store.max_value_bytes
324 );
325 assert_eq!(sc.anomaly_config.enabled, config.tools.anomaly.enabled);
326 assert_eq!(
327 sc.result_cache_config.enabled,
328 config.tools.result_cache.enabled
329 );
330 assert_eq!(
331 sc.result_cache_config.ttl_secs,
332 config.tools.result_cache.ttl_secs
333 );
334 assert_eq!(sc.debug_config.enabled, config.debug.enabled);
335 assert_eq!(
336 sc.document_config.rag_enabled,
337 config.memory.documents.rag_enabled
338 );
339 assert_eq!(
340 sc.overflow_config.threshold,
341 config.tools.overflow.threshold
342 );
343 assert_eq!(
344 sc.permission_policy.autonomy_level(),
345 config.security.autonomy_level
346 );
347 assert_eq!(sc.security.autonomy_level, config.security.autonomy_level);
348 assert_eq!(sc.timeouts.llm_seconds, config.timeouts.llm_seconds);
349 assert_eq!(sc.learning.enabled, config.skills.learning.enabled);
350 assert_eq!(
351 sc.server_compaction,
352 config.llm.providers.iter().any(|e| e.server_compaction)
353 );
354 assert_eq!(sc.secrets.len(), config.secrets.custom.len());
355 assert_eq!(sc.recap.on_resume, config.session.recap.on_resume);
356 assert_eq!(sc.recap.max_tokens, config.session.recap.max_tokens);
357 assert_eq!(sc.goal_config.enabled, config.goals.enabled);
358 assert_eq!(sc.goal_config.max_text_chars, config.goals.max_text_chars);
359 assert_eq!(
360 sc.fidelity_config.is_some(),
361 config.memory.fidelity.is_some()
362 );
363 assert_eq!(
364 sc.subagent_skill_token_budget,
365 config.skills.subagent_skill_token_budget.get()
366 );
367 assert_eq!(
368 sc.plugins_reputation.enabled,
369 config.plugins.reputation.enabled
370 );
371 assert!(
372 (sc.plugins_reputation.similarity_threshold
373 - config.plugins.reputation.similarity_threshold)
374 .abs()
375 < f32::EPSILON
376 );
377 }
378}