use std::sync::Arc;
use crate::config::{
Config, DebugConfig, DocumentConfig, GraphConfig, LearningConfig, OrchestrationConfig,
SecurityConfig, TimeoutConfig,
};
use crate::vault::Secret;
pub const CONTEXT_BUDGET_RESERVE_RATIO: f32 = 0.20;
#[derive(Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct AgentSessionConfig {
pub max_tool_iterations: usize,
pub max_tool_retries: usize,
pub max_retry_duration_secs: u64,
pub tool_repeat_threshold: usize,
pub tool_summarization: bool,
pub tool_call_cutoff: usize,
pub overflow_config: zeph_tools::OverflowConfig,
pub permission_policy: zeph_tools::PermissionPolicy,
pub model_name: String,
pub embed_model: String,
pub semantic_cache_enabled: bool,
pub semantic_cache_threshold: f32,
pub semantic_cache_max_candidates: u32,
pub budget_tokens: usize,
pub soft_compaction_threshold: f32,
pub hard_compaction_threshold: f32,
pub compaction_preserve_tail: usize,
pub compaction_cooldown_turns: u8,
pub prune_protect_tokens: usize,
pub redact_credentials: bool,
pub security: SecurityConfig,
pub timeouts: TimeoutConfig,
pub learning: LearningConfig,
pub document_config: DocumentConfig,
pub graph_config: GraphConfig,
pub anomaly_config: zeph_tools::AnomalyConfig,
pub result_cache_config: zeph_tools::ResultCacheConfig,
pub orchestration_config: OrchestrationConfig,
pub debug_config: DebugConfig,
pub server_compaction: bool,
pub secrets: Arc<[(String, Secret)]>,
}
impl AgentSessionConfig {
#[must_use]
pub fn from_config(config: &Config, budget_tokens: usize) -> Self {
Self {
max_tool_iterations: config.agent.max_tool_iterations,
max_tool_retries: config.agent.max_tool_retries,
max_retry_duration_secs: config.agent.max_retry_duration_secs,
tool_repeat_threshold: config.agent.tool_repeat_threshold,
tool_summarization: config.tools.summarize_output,
tool_call_cutoff: config.memory.tool_call_cutoff,
overflow_config: config.tools.overflow.clone(),
permission_policy: config
.tools
.permission_policy(config.security.autonomy_level),
model_name: config.llm.effective_model().to_owned(),
embed_model: crate::bootstrap::effective_embedding_model(config),
semantic_cache_enabled: config.llm.semantic_cache_enabled,
semantic_cache_threshold: config.llm.semantic_cache_threshold,
semantic_cache_max_candidates: config.llm.semantic_cache_max_candidates,
budget_tokens,
soft_compaction_threshold: config.memory.soft_compaction_threshold,
hard_compaction_threshold: config.memory.hard_compaction_threshold,
compaction_preserve_tail: config.memory.compaction_preserve_tail,
compaction_cooldown_turns: config.memory.compaction_cooldown_turns,
prune_protect_tokens: config.memory.prune_protect_tokens,
redact_credentials: config.memory.redact_credentials,
security: config.security.clone(),
timeouts: config.timeouts,
learning: config.skills.learning.clone(),
document_config: config.memory.documents.clone(),
graph_config: config.memory.graph.clone(),
anomaly_config: config.tools.anomaly.clone(),
result_cache_config: config.tools.result_cache.clone(),
orchestration_config: config.orchestration.clone(),
debug_config: config.debug.clone(),
server_compaction: config.llm.providers.iter().any(|e| e.server_compaction),
secrets: config
.secrets
.custom
.iter()
.map(|(k, v)| (k.clone(), Secret::new(v.expose().to_owned())))
.collect::<Vec<_>>()
.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_config_maps_all_fields() {
let config = Config::default();
let budget = 100_000;
let sc = AgentSessionConfig::from_config(&config, budget);
assert_eq!(sc.max_tool_iterations, config.agent.max_tool_iterations);
assert_eq!(sc.max_tool_retries, config.agent.max_tool_retries);
assert_eq!(
sc.max_retry_duration_secs,
config.agent.max_retry_duration_secs
);
assert_eq!(sc.tool_repeat_threshold, config.agent.tool_repeat_threshold);
assert_eq!(sc.tool_summarization, config.tools.summarize_output);
assert_eq!(sc.tool_call_cutoff, config.memory.tool_call_cutoff);
assert_eq!(sc.model_name, config.llm.effective_model());
assert_eq!(
sc.embed_model,
crate::bootstrap::effective_embedding_model(&config)
);
assert_eq!(sc.semantic_cache_enabled, config.llm.semantic_cache_enabled);
assert_eq!(
sc.semantic_cache_threshold,
config.llm.semantic_cache_threshold
);
assert_eq!(
sc.semantic_cache_max_candidates,
config.llm.semantic_cache_max_candidates
);
assert_eq!(sc.budget_tokens, budget);
assert_eq!(
sc.soft_compaction_threshold,
config.memory.soft_compaction_threshold
);
assert_eq!(
sc.hard_compaction_threshold,
config.memory.hard_compaction_threshold
);
assert_eq!(
sc.compaction_preserve_tail,
config.memory.compaction_preserve_tail
);
assert_eq!(
sc.compaction_cooldown_turns,
config.memory.compaction_cooldown_turns
);
assert_eq!(sc.prune_protect_tokens, config.memory.prune_protect_tokens);
assert_eq!(sc.redact_credentials, config.memory.redact_credentials);
assert_eq!(sc.graph_config.enabled, config.memory.graph.enabled);
assert_eq!(
sc.orchestration_config.enabled,
config.orchestration.enabled
);
assert_eq!(
sc.orchestration_config.max_tasks,
config.orchestration.max_tasks
);
assert_eq!(sc.anomaly_config.enabled, config.tools.anomaly.enabled);
assert_eq!(
sc.result_cache_config.enabled,
config.tools.result_cache.enabled
);
assert_eq!(
sc.result_cache_config.ttl_secs,
config.tools.result_cache.ttl_secs
);
assert_eq!(sc.debug_config.enabled, config.debug.enabled);
assert_eq!(
sc.document_config.rag_enabled,
config.memory.documents.rag_enabled
);
assert_eq!(
sc.overflow_config.threshold,
config.tools.overflow.threshold
);
assert_eq!(
sc.permission_policy.autonomy_level(),
config.security.autonomy_level
);
assert_eq!(sc.security.autonomy_level, config.security.autonomy_level);
assert_eq!(sc.timeouts.llm_seconds, config.timeouts.llm_seconds);
assert_eq!(sc.learning.enabled, config.skills.learning.enabled);
assert_eq!(
sc.server_compaction,
config.llm.providers.iter().any(|e| e.server_compaction)
);
assert_eq!(sc.secrets.len(), config.secrets.custom.len());
}
}