1use std::sync::Arc;
5
6use crate::config::{
7 Config, DebugConfig, DocumentConfig, GraphConfig, LearningConfig, OrchestrationConfig,
8 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 anomaly_config: zeph_tools::AnomalyConfig,
88 pub result_cache_config: zeph_tools::ResultCacheConfig,
89 pub orchestration_config: OrchestrationConfig,
90 pub debug_config: DebugConfig,
91 pub server_compaction: bool,
92
93 pub secrets: Arc<[(String, Secret)]>,
99}
100
101impl AgentSessionConfig {
102 #[must_use]
107 pub fn from_config(config: &Config, budget_tokens: usize) -> Self {
108 Self {
109 max_tool_iterations: config.agent.max_tool_iterations,
110 max_tool_retries: config.tools.retry.max_attempts,
111 max_retry_duration_secs: config.tools.retry.budget_secs,
112 retry_base_ms: config.tools.retry.base_ms,
113 retry_max_ms: config.tools.retry.max_ms,
114 parameter_reformat_provider: config.tools.retry.parameter_reformat_provider.clone(),
115 tool_repeat_threshold: config.agent.tool_repeat_threshold,
116 tool_summarization: config.tools.summarize_output,
117 tool_call_cutoff: config.memory.tool_call_cutoff,
118 overflow_config: config.tools.overflow.clone(),
119 permission_policy: config
120 .tools
121 .permission_policy(config.security.autonomy_level),
122 model_name: config.llm.effective_model().to_owned(),
123 embed_model: crate::bootstrap::effective_embedding_model(config),
124 semantic_cache_enabled: config.llm.semantic_cache_enabled,
125 semantic_cache_threshold: config.llm.semantic_cache_threshold,
126 semantic_cache_max_candidates: config.llm.semantic_cache_max_candidates,
127 budget_tokens,
128 soft_compaction_threshold: config.memory.soft_compaction_threshold,
129 hard_compaction_threshold: config.memory.hard_compaction_threshold,
130 compaction_preserve_tail: config.memory.compaction_preserve_tail,
131 compaction_cooldown_turns: config.memory.compaction_cooldown_turns,
132 prune_protect_tokens: config.memory.prune_protect_tokens,
133 redact_credentials: config.memory.redact_credentials,
134 security: config.security.clone(),
135 timeouts: config.timeouts,
136 learning: config.skills.learning.clone(),
137 document_config: config.memory.documents.clone(),
138 graph_config: config.memory.graph.clone(),
139 anomaly_config: config.tools.anomaly.clone(),
140 result_cache_config: config.tools.result_cache.clone(),
141 orchestration_config: config.orchestration.clone(),
142 debug_config: config.debug.clone(),
143 server_compaction: config.llm.providers.iter().any(|e| e.server_compaction),
144 secrets: config
145 .secrets
146 .custom
147 .iter()
148 .map(|(k, v)| (k.clone(), Secret::new(v.expose().to_owned())))
149 .collect::<Vec<_>>()
150 .into(),
151 }
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn from_config_maps_all_fields() {
161 let config = Config::default();
162 let budget = 100_000;
163 let sc = AgentSessionConfig::from_config(&config, budget);
164
165 assert_eq!(sc.max_tool_iterations, config.agent.max_tool_iterations);
166 assert_eq!(sc.max_tool_retries, config.tools.retry.max_attempts);
167 assert_eq!(sc.max_retry_duration_secs, config.tools.retry.budget_secs);
168 assert_eq!(sc.retry_base_ms, config.tools.retry.base_ms);
169 assert_eq!(sc.retry_max_ms, config.tools.retry.max_ms);
170 assert_eq!(
171 sc.parameter_reformat_provider,
172 config.tools.retry.parameter_reformat_provider
173 );
174 assert_eq!(sc.tool_repeat_threshold, config.agent.tool_repeat_threshold);
175 assert_eq!(sc.tool_summarization, config.tools.summarize_output);
176 assert_eq!(sc.tool_call_cutoff, config.memory.tool_call_cutoff);
177 assert_eq!(sc.model_name, config.llm.effective_model());
178 assert_eq!(
179 sc.embed_model,
180 crate::bootstrap::effective_embedding_model(&config)
181 );
182 assert_eq!(sc.semantic_cache_enabled, config.llm.semantic_cache_enabled);
183 assert_eq!(
184 sc.semantic_cache_threshold,
185 config.llm.semantic_cache_threshold
186 );
187 assert_eq!(
188 sc.semantic_cache_max_candidates,
189 config.llm.semantic_cache_max_candidates
190 );
191 assert_eq!(sc.budget_tokens, budget);
192 assert_eq!(
193 sc.soft_compaction_threshold,
194 config.memory.soft_compaction_threshold
195 );
196 assert_eq!(
197 sc.hard_compaction_threshold,
198 config.memory.hard_compaction_threshold
199 );
200 assert_eq!(
201 sc.compaction_preserve_tail,
202 config.memory.compaction_preserve_tail
203 );
204 assert_eq!(
205 sc.compaction_cooldown_turns,
206 config.memory.compaction_cooldown_turns
207 );
208 assert_eq!(sc.prune_protect_tokens, config.memory.prune_protect_tokens);
209 assert_eq!(sc.redact_credentials, config.memory.redact_credentials);
210 assert_eq!(sc.graph_config.enabled, config.memory.graph.enabled);
211 assert_eq!(
212 sc.orchestration_config.enabled,
213 config.orchestration.enabled
214 );
215 assert_eq!(
216 sc.orchestration_config.max_tasks,
217 config.orchestration.max_tasks
218 );
219 assert_eq!(sc.anomaly_config.enabled, config.tools.anomaly.enabled);
220 assert_eq!(
221 sc.result_cache_config.enabled,
222 config.tools.result_cache.enabled
223 );
224 assert_eq!(
225 sc.result_cache_config.ttl_secs,
226 config.tools.result_cache.ttl_secs
227 );
228 assert_eq!(sc.debug_config.enabled, config.debug.enabled);
229 assert_eq!(
230 sc.document_config.rag_enabled,
231 config.memory.documents.rag_enabled
232 );
233 assert_eq!(
234 sc.overflow_config.threshold,
235 config.tools.overflow.threshold
236 );
237 assert_eq!(
238 sc.permission_policy.autonomy_level(),
239 config.security.autonomy_level
240 );
241 assert_eq!(sc.security.autonomy_level, config.security.autonomy_level);
242 assert_eq!(sc.timeouts.llm_seconds, config.timeouts.llm_seconds);
243 assert_eq!(sc.learning.enabled, config.skills.learning.enabled);
244 assert_eq!(
245 sc.server_compaction,
246 config.llm.providers.iter().any(|e| e.server_compaction)
247 );
248 assert_eq!(sc.secrets.len(), config.secrets.custom.len());
249 }
250}