mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
## Why We want to remove implicit use of `$CODEX_HOME` from `codex-core` and make embedders responsible for supplying user-level instructions. This also ensures user instructions load when no primary environment is selected. ## What changed Stacked on #27415, which makes `codex exec` surface thread-scoped runtime warnings. - Added `UserInstructionsProvider` to `codex-extension-api`, with absolute source attribution and recoverable loading warnings. - Added `codex-home` with the filesystem-backed provider for `AGENTS.override.md` and `AGENTS.md`, preserving precedence, fallback, trimming, lossy UTF-8 handling, and the existing uncapped global instruction size. - Removed global instruction loading from `Config` and require `ThreadManager` callers to inject a provider. - Load provider instructions once for each fresh root runtime, including runtimes without a primary environment. Running sessions retain their snapshot, while child agents inherit the parent snapshot without invoking the provider. - Keep provider instructions separate while loading project `AGENTS.md`, then assemble the model-visible instructions with the existing ordering, source attribution, warning, and turn-context behavior. - Wired the Codex home provider through the CLI, app server, MCP server, core facade, and thread-manager sample. ## Validation - `just test -p codex-home -p codex-extension-api` - `just test -p codex-core agents_md` - `just test -p codex-core guardian` - `just test -p codex-app-server thread_start_without_selected_environment_includes_only_global_instruction_source` - `just test -p codex-exec warning` - `just bazel-lock-check`
84 lines
3.0 KiB
Rust
84 lines
3.0 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;
|
|
}
|
|
};
|
|
if let Err(err) = std::str::from_utf8(&data) {
|
|
warnings.push(format!(
|
|
"Global AGENTS.md instructions from `{}` contain invalid UTF-8: {err}. Invalid byte sequences were replaced.",
|
|
path.display()
|
|
));
|
|
}
|
|
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;
|