vtcode_core/core/agent/
session_config.rs1use std::path::Path;
2
3use anyhow::Result;
4use hashbrown::HashMap;
5
6use crate::config::VTCodeConfig;
7use crate::config::loader::ConfigManager;
8use crate::config::loader::layers::ConfigLayerMetadata;
9use crate::core::agent::features::FeatureSet;
10
11#[derive(Debug, Clone)]
17pub struct ResolvedSessionConfig {
18 effective: VTCodeConfig,
19 features: FeatureSet,
20 origins: HashMap<String, ConfigLayerMetadata>,
21}
22
23impl ResolvedSessionConfig {
24 pub fn from_manager(manager: &ConfigManager) -> Self {
26 let (_, origins) = manager.layer_stack().effective_config_with_origins();
27 let effective = manager.config().clone();
28 Self {
29 features: FeatureSet::from_config(Some(&effective)),
30 effective,
31 origins,
32 }
33 }
34
35 pub fn from_config(config: VTCodeConfig) -> Self {
37 let features = FeatureSet::from_config(Some(&config));
38 Self {
39 effective: config,
40 features,
41 origins: HashMap::new(),
42 }
43 }
44
45 pub fn load_from_workspace(workspace: impl AsRef<Path>) -> Result<Self> {
47 let manager = ConfigManager::load_from_workspace(workspace)?;
48 Ok(Self::from_manager(&manager))
49 }
50
51 pub fn effective(&self) -> &VTCodeConfig {
53 &self.effective
54 }
55
56 pub fn origins(&self) -> &HashMap<String, ConfigLayerMetadata> {
58 &self.origins
59 }
60
61 pub fn features(&self) -> &FeatureSet {
63 &self.features
64 }
65
66 pub fn origin_for(&self, path: &str) -> Option<&ConfigLayerMetadata> {
68 self.origins.get(path)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::ResolvedSessionConfig;
75 use anyhow::Result;
76 use std::fs;
77 use tempfile::TempDir;
78
79 #[test]
80 fn captures_origin_metadata_from_workspace_config() -> Result<()> {
81 let temp = TempDir::new()?;
82 fs::write(
83 temp.path().join("vtcode.toml"),
84 "[agent]\nprovider = \"openai\"\n",
85 )?;
86
87 let snapshot = ResolvedSessionConfig::load_from_workspace(temp.path())?;
88
89 assert_eq!(snapshot.effective().agent.provider, "openai");
90 assert!(
91 snapshot.origin_for("agent.provider").is_some(),
92 "expected origin metadata for agent.provider"
93 );
94
95 Ok(())
96 }
97
98 #[test]
99 fn snapshot_is_immutable_after_disk_changes() -> Result<()> {
100 let temp = TempDir::new()?;
101 let config_path = temp.path().join("vtcode.toml");
102 fs::write(&config_path, "[agent]\nprovider = \"openai\"\n")?;
103
104 let snapshot = ResolvedSessionConfig::load_from_workspace(temp.path())?;
105 fs::write(&config_path, "[agent]\nprovider = \"anthropic\"\n")?;
106
107 assert_eq!(snapshot.effective().agent.provider, "openai");
108
109 let refreshed = ResolvedSessionConfig::load_from_workspace(temp.path())?;
110 assert_eq!(refreshed.effective().agent.provider, "anthropic");
111
112 Ok(())
113 }
114}