Skip to content

Commit 63f03c2

Browse files
tusharmathforge-code-agent
authored andcommitted
refactor(forge_config): simplify config docs and reader comments
1 parent ebc632c commit 63f03c2

2 files changed

Lines changed: 23 additions & 107 deletions

File tree

crates/forge_config/src/config.rs

Lines changed: 11 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,7 @@ use crate::{
1111
TopP, Update,
1212
};
1313

14-
/// Forge configuration containing all the fields from the Environment struct.
15-
///
16-
/// # Field Naming Convention
17-
///
18-
/// Fields follow these rules to make units and semantics unambiguous at the
19-
/// call-site:
20-
///
21-
/// - **Unit suffixes are mandatory** for any numeric field that carries a
22-
/// physical unit:
23-
/// - `_ms` — duration in milliseconds
24-
/// - `_secs` — duration in seconds
25-
/// - `_bytes` — size in bytes
26-
/// - `_lines` — count of text lines
27-
/// - `_chars` — count of characters
28-
/// - Pure counts / dimensionless values (e.g. `max_redirects`) carry no
29-
/// suffix.
30-
///
31-
/// - **`max_` is always a prefix**, never embedded mid-name:
32-
/// - Correct: `max_stdout_prefix_lines`
33-
/// - Incorrect: `stdout_max_prefix_length`
34-
///
35-
/// - **No redundant struct-name prefixes inside a sub-struct**: fields inside
36-
/// `RetryConfig` must not repeat `retry_` (e.g. use `status_codes`, not
37-
/// `retry_status_codes`).
38-
///
39-
/// - **`_limit` is avoided**; prefer the explicit `max_` prefix + unit suffix
40-
/// instead.
14+
/// Top-level Forge configuration merged from all sources (defaults, file, environment).
4115
#[derive(Default, Debug, Setters, Clone, PartialEq, Serialize, Deserialize)]
4216
#[serde(rename_all = "snake_case")]
4317
#[setters(strip_option)]
@@ -92,8 +66,7 @@ pub struct ForgeConfig {
9266
pub max_parallel_file_reads: usize,
9367
/// TTL in seconds for the model API list cache
9468
pub model_cache_ttl_secs: u64,
95-
/// Default model and provider configuration to use for all operations if
96-
/// not specified
69+
/// Default model and provider configuration used when not overridden by individual agents.
9770
#[serde(default)]
9871
pub session: Option<ModelConfig>,
9972
/// Provider and model to use for commit message generation
@@ -126,77 +99,41 @@ pub struct ForgeConfig {
12699
#[serde(skip_serializing_if = "Option::is_none")]
127100
pub updates: Option<Update>,
128101

129-
/// Temperature used for all agents.
130-
///
131-
/// Temperature controls the randomness in the model's output.
132-
/// - Lower values (e.g., 0.1) make responses more focused, deterministic,
133-
/// and coherent
134-
/// - Higher values (e.g., 0.8) make responses more creative, diverse, and
135-
/// exploratory
136-
/// - Valid range is 0.0 to 2.0
137-
/// - If not specified, each agent's individual setting or the model
138-
/// provider's default will be used
102+
/// Output randomness for all agents; lower values are deterministic, higher values are creative (0.0–2.0).
139103
#[serde(default, skip_serializing_if = "Option::is_none")]
140104
pub temperature: Option<Temperature>,
141105

142-
/// Top-p (nucleus sampling) used for all agents.
143-
///
144-
/// Controls the diversity of the model's output by considering only the
145-
/// most probable tokens up to a cumulative probability threshold.
146-
/// - Lower values (e.g., 0.1) make responses more focused
147-
/// - Higher values (e.g., 0.9) make responses more diverse
148-
/// - Valid range is 0.0 to 1.0
149-
/// - If not specified, each agent's individual setting or the model
150-
/// provider's default will be used
106+
/// Nucleus sampling threshold for all agents; limits token selection to the top cumulative probability mass (0.0–1.0).
151107
#[serde(default, skip_serializing_if = "Option::is_none")]
152108
pub top_p: Option<TopP>,
153109

154-
/// Top-k used for all agents.
155-
///
156-
/// Controls the number of highest probability vocabulary tokens to keep.
157-
/// - Lower values (e.g., 10) make responses more focused
158-
/// - Higher values (e.g., 100) make responses more diverse
159-
/// - Valid range is 1 to 1000
160-
/// - If not specified, each agent's individual setting or the model
161-
/// provider's default will be used
110+
/// Top-k vocabulary cutoff for all agents; restricts sampling to the k highest-probability tokens (1–1000).
162111
#[serde(default, skip_serializing_if = "Option::is_none")]
163112
pub top_k: Option<TopK>,
164113

165-
/// Maximum number of tokens the model can generate for all agents.
166-
///
167-
/// Controls the maximum length of the model's response.
168-
/// - Lower values (e.g., 100) limit response length for concise outputs
169-
/// - Higher values (e.g., 4000) allow for longer, more detailed responses
170-
/// - Valid range is 1 to 100,000
171-
/// - If not specified, each agent's individual setting or the model
172-
/// provider's default will be used
114+
/// Maximum tokens the model may generate per response for all agents (1–100,000).
173115
#[serde(default, skip_serializing_if = "Option::is_none")]
174116
pub max_tokens: Option<MaxTokens>,
175117

176-
/// Maximum number of times a tool can fail before the orchestrator
177-
/// forces the completion.
118+
/// Maximum tool failures per turn before the orchestrator forces completion.
178119
#[serde(default, skip_serializing_if = "Option::is_none")]
179120
pub max_tool_failure_per_turn: Option<usize>,
180121

181122
/// Maximum number of requests that can be made in a single turn.
182123
#[serde(default, skip_serializing_if = "Option::is_none")]
183124
pub max_requests_per_turn: Option<usize>,
184125

185-
/// Configuration for automatic context compaction for all agents.
186-
/// If specified, this will be applied to all agents in the workflow.
187-
/// If not specified, each agent's individual setting will be used.
126+
/// Context compaction settings applied to all agents; falls back to each agent's individual setting when absent.
188127
#[serde(default, skip_serializing_if = "Option::is_none")]
189128
pub compact: Option<Compact>,
190129
}
191130

192131
impl ForgeConfig {
193-
/// Reads and merges configuration from all sources, returning the resolved
194-
/// [`ForgeConfig`].
132+
/// Reads and merges configuration from all sources, returning the resolved [`ForgeConfig`].
195133
///
196134
/// # Errors
197135
///
198-
/// Returns an error if the config path cannot be resolved, the file cannot
199-
/// be read, or the configuration cannot be deserialized.
136+
/// Returns an error if the config path cannot be resolved, the file cannot be read, or deserialization fails.
200137
pub fn read() -> crate::Result<ForgeConfig> {
201138
Ok(ConfigReader::default()
202139
.read_defaults()
@@ -210,8 +147,7 @@ impl ForgeConfig {
210147
///
211148
/// # Errors
212149
///
213-
/// Returns an error if the configuration cannot be serialized or written to
214-
/// disk.
150+
/// Returns an error if the configuration cannot be serialized or written to disk.
215151
pub async fn write(&self) -> crate::Result<()> {
216152
let path = ConfigReader::config_path();
217153
ConfigWriter::new(self.clone()).write(&path).await

crates/forge_config/src/reader.rs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,29 @@ use config::ConfigBuilder;
44
use config::builder::DefaultState;
55
use std::path::PathBuf;
66

7-
/// Reads and merges [`ForgeConfig`] from multiple sources: embedded defaults,
8-
/// home directory file, current working directory file, and environment
9-
/// variables.
7+
/// Merges [`ForgeConfig`] from layered sources using a builder pattern.
108
#[derive(Default)]
119
pub struct ConfigReader {
1210
builder: ConfigBuilder<DefaultState>,
1311
}
1412

1513
impl ConfigReader {
14+
/// Returns the path to the legacy JSON config file (`~/.forge/.config.json`).
1615
pub fn config_legacy_path() -> PathBuf {
1716
Self::base_path().join(".config.json")
1817
}
1918

19+
/// Returns the path to the primary TOML config file (`~/.forge/.forge.toml`).
2020
pub fn config_path() -> PathBuf {
2121
Self::base_path().join(".forge.toml")
2222
}
2323

24+
/// Returns the base directory for all Forge config files (`~/forge`).
2425
pub fn base_path() -> PathBuf {
2526
dirs::home_dir().unwrap_or(PathBuf::from(".")).join("forge")
2627
}
2728

28-
/// Reads and merges configuration from the embedded defaults and the given
29-
/// TOML string, returning the resolved [`ForgeConfig`].
30-
///
31-
/// Unlike [`read`], this method accepts already-loaded TOML content and
32-
/// does not touch the filesystem or environment variables. This is
33-
/// appropriate when the caller has already read the raw file content via
34-
/// its own I/O abstraction.
29+
/// Adds the provided TOML string as a config source without touching the filesystem.
3530
pub fn read_toml(mut self, contents: &str) -> Self {
3631
self.builder = self
3732
.builder
@@ -40,15 +35,14 @@ impl ConfigReader {
4035
self
4136
}
4237

43-
/// Returns the [`ForgeConfig`] built from the embedded defaults only,
44-
/// without reading any file or environment variables.
38+
/// Adds the embedded default config (`../.forge.toml`) as a source.
4539
pub fn read_defaults(self) -> Self {
4640
let defaults = include_str!("../.forge.toml");
4741

4842
self.read_toml(defaults)
4943
}
5044

51-
/// Adds environment variables prefixed with `FORGE_` as a source.
45+
/// Adds `FORGE_`-prefixed environment variables as a config source.
5246
pub fn read_env(mut self) -> Self {
5347
self.builder = self.builder.add_source(
5448
config::Environment::with_prefix("FORGE")
@@ -63,7 +57,7 @@ impl ConfigReader {
6357
self
6458
}
6559

66-
/// Builds and returns the merged [`ForgeConfig`] from all accumulated sources.
60+
/// Builds and deserializes all accumulated sources into a [`ForgeConfig`].
6761
///
6862
/// # Errors
6963
///
@@ -73,25 +67,14 @@ impl ConfigReader {
7367
Ok(config.try_deserialize::<ForgeConfig>()?)
7468
}
7569

76-
/// Reads `~/.forge/.forge.toml` and adds it as a config source.
77-
///
78-
/// If the file does not exist it is silently skipped. If the file cannot
79-
/// be read or parsed the error is propagated.
80-
///
81-
/// # Errors
82-
///
83-
/// Returns an error if the file exists but cannot be read or deserialized.
84-
70+
/// Adds `~/.forge/.forge.toml` as a config source, silently skipping if absent.
8571
pub fn read_global(mut self) -> Self {
8672
let path = Self::config_path();
8773
self.builder = self.builder.add_source(config::File::from(path));
8874
self
8975
}
9076

91-
/// Reads `~/.forge/.config.json` (the legacy JSON format), converts it to
92-
/// a [`ForgeConfig`], and adds it as a config source.
93-
///
94-
/// If the file does not exist or cannot be parsed it is silently skipped.
77+
/// Reads `~/.forge/.config.json` (legacy format) and adds it as a source, silently skipping errors.
9578
pub fn read_legacy(self) -> Self {
9679
let content = LegacyConfig::read(&Self::config_legacy_path());
9780
if let Ok(content) = content {
@@ -114,17 +97,14 @@ mod tests {
11497
/// Serializes tests that mutate environment variables to prevent races.
11598
static ENV_MUTEX: Mutex<()> = Mutex::new(());
11699

117-
/// Guard that holds a set of environment variables for the duration of a
118-
/// test, removing them all on drop. Also holds the [`ENV_MUTEX`] lock to
119-
/// prevent concurrent env mutations across tests.
100+
/// Holds env vars set for a test's duration and removes them on drop, while holding [`ENV_MUTEX`].
120101
struct EnvGuard {
121102
keys: Vec<&'static str>,
122103
_lock: MutexGuard<'static, ()>,
123104
}
124105

125106
impl EnvGuard {
126-
/// Sets each `(key, value)` pair in the process environment and returns
127-
/// a guard that removes all those keys when dropped.
107+
/// Sets each `(key, value)` pair in the environment, returning a guard that cleans them up on drop.
128108
#[must_use]
129109
fn set(pairs: &[(&'static str, &str)]) -> Self {
130110
let lock = ENV_MUTEX.lock().unwrap_or_else(|e| e.into_inner());

0 commit comments

Comments
 (0)