mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
## Why Shell snapshots are currently session-scoped even though shell and cwd are properties of a selected turn environment. That makes snapshot refresh depend on separate session-cwd plumbing, prevents retained environments from retaining their snapshot work, and can make snapshot construction use a different shell than command execution. This follows #27955 by making the retained thread-environment service own environment snapshot lifecycles. Session configuration remains the requested selection state, while `ThreadEnvironments` remains the source of successfully resolved environments. ## What changed - Configure the shell-snapshot builder before initial environment resolution. - Start each local environment snapshot task when its `TurnEnvironment` is built and retain that shared task while environment ID and cwd still match. - Inherit retained environment snapshots into spawned child threads. - Carry the selected `TurnEnvironment` through shell runtimes so snapshot construction and command execution use the same environment-specific shell and cwd. - Load project instructions and warm plugins/skills after initial environment resolution. - Continue decoding invalid UTF-8 instruction files lossily without emitting a startup warning. - Keep requested selections in `SessionConfiguration`; failed or duplicate resolutions only affect the resolved environment snapshot. ## Validation - `cargo check -p codex-core --tests` - `just test -p codex-home instructions` (6 passed) - Focused environment, instruction, shell-snapshot, and user-shell tests (84 passed) - Focused shell-snapshot, user-shell, and unified-exec tests (126 passed; two event-timing tests passed on retry)
78 lines
2.7 KiB
Rust
78 lines
2.7 KiB
Rust
use std::io;
|
|
|
|
use codex_extension_api::LoadUserInstructionsFuture;
|
|
use codex_extension_api::LoadedUserInstructions;
|
|
use codex_extension_api::UserInstructions;
|
|
use codex_extension_api::UserInstructionsProvider;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
|
|
const DEFAULT_AGENTS_MD_FILENAME: &str = "AGENTS.md";
|
|
const LOCAL_AGENTS_MD_FILENAME: &str = "AGENTS.override.md";
|
|
|
|
/// Loads user instructions from a Codex home directory.
|
|
#[derive(Clone, Debug)]
|
|
pub struct CodexHomeUserInstructionsProvider {
|
|
codex_home: AbsolutePathBuf,
|
|
}
|
|
|
|
impl CodexHomeUserInstructionsProvider {
|
|
/// Creates a provider rooted at the supplied absolute Codex home directory.
|
|
pub fn new(codex_home: AbsolutePathBuf) -> Self {
|
|
Self { codex_home }
|
|
}
|
|
|
|
async fn load_from_codex_home(&self) -> LoadedUserInstructions {
|
|
let mut warnings = Vec::new();
|
|
for candidate in [LOCAL_AGENTS_MD_FILENAME, DEFAULT_AGENTS_MD_FILENAME] {
|
|
let path = self.codex_home.join(candidate);
|
|
match tokio::fs::metadata(path.as_path()).await {
|
|
Ok(metadata) if !metadata.is_file() => continue,
|
|
Ok(_) => {}
|
|
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
|
|
Err(err) => {
|
|
warnings.push(format!(
|
|
"Failed to read global AGENTS.md instructions from `{}`: {err}",
|
|
path.display()
|
|
));
|
|
continue;
|
|
}
|
|
}
|
|
let data = match tokio::fs::read(path.as_path()).await {
|
|
Ok(data) => data,
|
|
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
|
|
Err(err) => {
|
|
warnings.push(format!(
|
|
"Failed to read global AGENTS.md instructions from `{}`: {err}",
|
|
path.display()
|
|
));
|
|
continue;
|
|
}
|
|
};
|
|
let contents = String::from_utf8_lossy(&data);
|
|
let trimmed = contents.trim();
|
|
if !trimmed.is_empty() {
|
|
return LoadedUserInstructions {
|
|
instructions: Some(UserInstructions {
|
|
text: trimmed.to_string(),
|
|
source: path,
|
|
}),
|
|
warnings,
|
|
};
|
|
}
|
|
}
|
|
LoadedUserInstructions {
|
|
instructions: None,
|
|
warnings,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl UserInstructionsProvider for CodexHomeUserInstructionsProvider {
|
|
fn load_user_instructions(&self) -> LoadUserInstructionsFuture<'_> {
|
|
Box::pin(self.load_from_codex_home())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|