mirror of
https://github.com/openai/codex.git
synced 2026-04-24 06:35:50 +00:00
agents doc path passed as sessionconfigured instead
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
use codex_core::WireApi;
|
||||
use codex_core::agents_doc_path_string;
|
||||
use codex_core::config::Config;
|
||||
|
||||
use crate::sandbox_summary::summarize_sandbox_policy;
|
||||
|
||||
/// Build a list of key/value pairs summarizing the effective configuration.
|
||||
pub fn create_config_summary_entries(config: &Config) -> Vec<(&'static str, String)> {
|
||||
let mut entries = vec![
|
||||
("workdir", config.cwd.display().to_string()),
|
||||
let mut entries = vec![("workdir", config.cwd.display().to_string())];
|
||||
|
||||
entries.extend([
|
||||
(
|
||||
"agents.md",
|
||||
agents_doc_path_string(config).unwrap_or_else(|| "none".to_string()),
|
||||
),
|
||||
("model", config.model.clone()),
|
||||
("provider", config.model_provider_id.clone()),
|
||||
("approval", config.approval_policy.to_string()),
|
||||
("sandbox", summarize_sandbox_policy(&config.sandbox_policy)),
|
||||
];
|
||||
]);
|
||||
if config.model_provider.wire_api == WireApi::Responses
|
||||
&& config.model_family.supports_reasoning_summaries
|
||||
{
|
||||
|
||||
@@ -857,6 +857,7 @@ async fn submission_loop(
|
||||
msg: EventMsg::SessionConfigured(SessionConfiguredEvent {
|
||||
session_id,
|
||||
model,
|
||||
agents_doc_path: crate::project_doc::agents_doc_path_string(&config),
|
||||
history_log_id,
|
||||
history_entry_count,
|
||||
}),
|
||||
|
||||
@@ -39,6 +39,7 @@ mod openai_model_info;
|
||||
mod openai_tools;
|
||||
pub mod plan_tool;
|
||||
mod project_doc;
|
||||
pub use project_doc::agents_doc_path_string;
|
||||
pub use project_doc::discover_project_doc_path;
|
||||
pub mod protocol;
|
||||
mod rollout;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
use crate::config::Config;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tracing::error;
|
||||
|
||||
@@ -128,6 +129,113 @@ pub(crate) async fn get_user_instructions(config: &Config) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a human‑readable description of the AGENTS.md path(s) that will be
|
||||
/// loaded for this session, or `None` if neither global nor project docs are
|
||||
/// present.
|
||||
///
|
||||
/// This mirrors the discovery logic used by `get_user_instructions()`:
|
||||
/// - If `~/.codex/AGENTS.md` (global) is non‑empty, it is included.
|
||||
/// - If a project AGENTS.md is found (respecting the byte limit and git root
|
||||
/// stop), it is included.
|
||||
/// - When the project_doc_max_bytes is set to 0, project docs are disabled.
|
||||
pub fn agents_doc_path_string(config: &Config) -> Option<String> {
|
||||
let mut parts: Vec<String> = Vec::new();
|
||||
|
||||
// Global AGENTS.md in CODEX_HOME.
|
||||
if config.user_instructions.is_some() {
|
||||
let global = config.codex_home.join("AGENTS.md");
|
||||
parts.push(global.display().to_string());
|
||||
}
|
||||
|
||||
// Project AGENTS.md, unless disabled via byte‑limit == 0.
|
||||
if config.project_doc_max_bytes > 0 {
|
||||
if let Some(p) = find_project_doc_path_sync(config) {
|
||||
parts.push(p.display().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if parts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(parts.join(" + "))
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous counterpart to `find_project_doc()` that returns the discovered
|
||||
/// path rather than the contents. Skips empty files (after trimming) to stay
|
||||
/// consistent with `load_first_candidate()`.
|
||||
fn find_project_doc_path_sync(config: &Config) -> Option<PathBuf> {
|
||||
// Attempt to locate in cwd first.
|
||||
if let Some(p) = first_nonempty_candidate_in_dir(&config.cwd, CANDIDATE_FILENAMES) {
|
||||
return Some(p);
|
||||
}
|
||||
|
||||
// Walk up to git root.
|
||||
let mut dir = config.cwd.clone();
|
||||
if let Ok(canon) = dir.canonicalize() {
|
||||
dir = canon;
|
||||
}
|
||||
|
||||
while let Some(parent) = dir.parent() {
|
||||
let git_marker = dir.join(".git");
|
||||
let git_exists = std::fs::metadata(&git_marker).is_ok();
|
||||
if git_exists {
|
||||
if let Some(p) = first_nonempty_candidate_in_dir(&dir, CANDIDATE_FILENAMES) {
|
||||
return Some(p);
|
||||
}
|
||||
break; // do not walk past git root
|
||||
}
|
||||
dir = parent.to_path_buf();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Return the first path in `dir` that matches any of `names` and is non‑empty
|
||||
/// (after trimming). Returns `None` if no such file exists.
|
||||
fn first_nonempty_candidate_in_dir(dir: &Path, names: &[&str]) -> Option<PathBuf> {
|
||||
for name in names {
|
||||
let candidate = dir.join(name);
|
||||
// Fast path: must exist and be a file.
|
||||
let md = match std::fs::metadata(&candidate) {
|
||||
Ok(m) if m.is_file() => m,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// If the file is zero bytes, skip without reading.
|
||||
if md.len() == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read up to a modest limit to determine if the contents are
|
||||
// effectively empty after trimming. Use the same limit as
|
||||
// `project_doc_max_bytes` would permit by default: however, the goal is
|
||||
// to avoid reading arbitrarily large files here just for display. Read
|
||||
// up to 8 KiB which should be sufficient to determine non‑emptiness
|
||||
// after trimming whitespace.
|
||||
const MAX_PEEK_BYTES: usize = 8 * 1024;
|
||||
let mut file = match std::fs::File::open(&candidate) {
|
||||
Ok(f) => f,
|
||||
Err(_) => continue,
|
||||
};
|
||||
use std::io::Read as _;
|
||||
let mut buf = Vec::with_capacity(std::cmp::min(md.len() as usize, MAX_PEEK_BYTES));
|
||||
if std::io::Read::by_ref(&mut file)
|
||||
.take(MAX_PEEK_BYTES as u64)
|
||||
.read_to_end(&mut buf)
|
||||
.is_err()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let s = String::from_utf8_lossy(&buf);
|
||||
if s.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
return Some(candidate);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Attempt to locate and load the project documentation. Currently, the search
|
||||
/// starts from `Config::cwd`, but if we may want to consider other directories
|
||||
/// in the future, e.g., additional writable directories in the `SandboxPolicy`.
|
||||
|
||||
@@ -642,6 +642,10 @@ pub struct SessionConfiguredEvent {
|
||||
/// Tell the client what model is being queried.
|
||||
pub model: String,
|
||||
|
||||
/// The path(s) to AGENTS.md that were loaded for this session, if any.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub agents_doc_path: Option<String>,
|
||||
|
||||
/// Identifier of the history log file (inode on Unix, 0 otherwise).
|
||||
pub history_log_id: u64,
|
||||
|
||||
@@ -707,6 +711,7 @@ mod tests {
|
||||
msg: EventMsg::SessionConfigured(SessionConfiguredEvent {
|
||||
session_id,
|
||||
model: "codex-mini-latest".to_string(),
|
||||
agents_doc_path: None,
|
||||
history_log_id: 0,
|
||||
history_entry_count: 0,
|
||||
}),
|
||||
|
||||
@@ -494,6 +494,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
|
||||
model,
|
||||
history_log_id: _,
|
||||
history_entry_count: _,
|
||||
..
|
||||
} = session_configured_event;
|
||||
|
||||
ts_println!(
|
||||
|
||||
@@ -906,6 +906,7 @@ mod tests {
|
||||
msg: EventMsg::SessionConfigured(codex_core::protocol::SessionConfiguredEvent {
|
||||
session_id: uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"),
|
||||
model: "codex-mini-latest".into(),
|
||||
agents_doc_path: None,
|
||||
history_log_id: 42,
|
||||
history_entry_count: 3,
|
||||
}),
|
||||
|
||||
@@ -242,6 +242,7 @@ mod tests {
|
||||
msg: EventMsg::SessionConfigured(SessionConfiguredEvent {
|
||||
session_id: Uuid::new_v4(),
|
||||
model: "gpt-4o".to_string(),
|
||||
agents_doc_path: None,
|
||||
history_log_id: 1,
|
||||
history_entry_count: 1000,
|
||||
}),
|
||||
@@ -282,6 +283,7 @@ mod tests {
|
||||
let session_configured_event = SessionConfiguredEvent {
|
||||
session_id: Uuid::new_v4(),
|
||||
model: "gpt-4o".to_string(),
|
||||
agents_doc_path: None,
|
||||
history_log_id: 1,
|
||||
history_entry_count: 1000,
|
||||
};
|
||||
|
||||
@@ -169,6 +169,7 @@ impl HistoryCell {
|
||||
session_id,
|
||||
history_log_id: _,
|
||||
history_entry_count: _,
|
||||
..
|
||||
} = event;
|
||||
if is_first_event {
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
Reference in New Issue
Block a user