mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Remove child AGENTS.md prompt experiment (#28993)
## Why `child_agents_md` is a disabled, under-development experiment that adds a second model-visible explanation of hierarchical `AGENTS.md` behavior. Keeping it leaves unused prompt, configuration, documentation, and test surface. ## What changed - remove the `ChildAgentsMd` feature and `child_agents_md` config schema entry - remove the hierarchical prompt asset, export, and instruction injection - remove feature-specific tests and documentation - keep the generic unstable-feature warning coverage using `apply_patch_streaming_events` Normal project `AGENTS.md` discovery and composition are unchanged. ## Testing - `just test -p codex-features` - `just test -p codex-prompts` - `just test -p codex-core agents_md` - `just test -p codex-core unstable_features_warning`
This commit is contained in:
committed by
GitHub
Unverified
parent
772c5c5195
commit
bb72e151e5
@@ -446,9 +446,6 @@
|
||||
"browser_use_external": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"child_agents_md": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"chronicle": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -4689,9 +4686,6 @@
|
||||
"browser_use_external": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"child_agents_md": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"chronicle": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -26,8 +26,6 @@ use codex_config::merge_toml_values;
|
||||
use codex_config::project_root_markers_from_config;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_extension_api::UserInstructions;
|
||||
use codex_features::Feature;
|
||||
use codex_prompts::HIERARCHICAL_AGENTS_MESSAGE;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use std::io;
|
||||
@@ -72,13 +70,6 @@ pub(crate) async fn load_project_instructions(
|
||||
}
|
||||
}
|
||||
|
||||
if config.features.enabled(Feature::ChildAgentsMd) {
|
||||
loaded.entries.push(InstructionEntry {
|
||||
contents: HIERARCHICAL_AGENTS_MESSAGE.to_string(),
|
||||
provenance: InstructionProvenance::Internal,
|
||||
});
|
||||
}
|
||||
|
||||
(!loaded.is_empty()).then_some(loaded)
|
||||
}
|
||||
|
||||
|
||||
@@ -909,32 +909,6 @@ async fn secondary_environment_invalid_utf8_does_not_suppress_other_docs() {
|
||||
assert!(loaded.text().contains("secondary\u{FFFD}doc"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn child_agents_guidance_is_appended_once_after_environment_groups() {
|
||||
let primary = tempfile::tempdir().expect("primary tempdir");
|
||||
let secondary = tempfile::tempdir().expect("secondary tempdir");
|
||||
fs::write(primary.path().join("AGENTS.md"), "primary doc").unwrap();
|
||||
fs::write(secondary.path().join("AGENTS.md"), "secondary doc").unwrap();
|
||||
let mut config = make_config(&primary, /*limit*/ 4096, /*instructions*/ None).await;
|
||||
config.features.enable(Feature::ChildAgentsMd).unwrap();
|
||||
let environments = resolved_local_environments([
|
||||
("primary", config.cwd.clone()),
|
||||
("secondary", secondary.abs()),
|
||||
]);
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
&config.config,
|
||||
/*user_instructions*/ None,
|
||||
&environments,
|
||||
)
|
||||
.await
|
||||
.expect("instructions expected");
|
||||
let text = loaded.text();
|
||||
|
||||
assert_eq!(text.matches(HIERARCHICAL_AGENTS_MESSAGE).count(), 1);
|
||||
assert!(text.ends_with(HIERARCHICAL_AGENTS_MESSAGE));
|
||||
}
|
||||
|
||||
/// If there are existing system instructions but AGENTS.md docs are
|
||||
/// missing we expect the original instructions to be returned unchanged.
|
||||
#[tokio::test]
|
||||
@@ -1098,32 +1072,6 @@ async fn agents_md_paths_preserve_symlinked_cwd() {
|
||||
assert_eq!(res, "project doc");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn child_agents_message_after_global_instructions_uses_plain_separator() {
|
||||
let tmp = tempfile::tempdir().expect("tempdir");
|
||||
let mut cfg = make_config(&tmp, /*limit*/ 4096, Some("global doc")).await;
|
||||
cfg.features.enable(Feature::ChildAgentsMd).unwrap();
|
||||
|
||||
let loaded = load_agents_md(&cfg).await.expect("instructions expected");
|
||||
let global_agents = cfg.codex_home.join(DEFAULT_AGENTS_MD_FILENAME);
|
||||
let expected = LoadedAgentsMd {
|
||||
user_instructions: Some(UserInstructions {
|
||||
text: "global doc".to_string(),
|
||||
source: global_agents,
|
||||
}),
|
||||
entries: vec![InstructionEntry {
|
||||
contents: HIERARCHICAL_AGENTS_MESSAGE.to_string(),
|
||||
provenance: InstructionProvenance::Internal,
|
||||
}],
|
||||
};
|
||||
|
||||
assert_eq!(loaded, expected);
|
||||
assert_eq!(
|
||||
loaded.text(),
|
||||
format!("global doc\n\n{HIERARCHICAL_AGENTS_MESSAGE}")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn instruction_sources_include_global_before_agents_md_docs() {
|
||||
let tmp = tempfile::tempdir().expect("tempdir");
|
||||
@@ -1162,50 +1110,6 @@ async fn instruction_sources_include_global_before_agents_md_docs() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn child_agents_message_after_project_docs_is_not_an_instruction_source() {
|
||||
let tmp = tempfile::tempdir().expect("tempdir");
|
||||
fs::write(tmp.path().join("AGENTS.md"), "project doc").unwrap();
|
||||
|
||||
let mut cfg = make_config(&tmp, /*limit*/ 4096, Some("global doc")).await;
|
||||
cfg.features.enable(Feature::ChildAgentsMd).unwrap();
|
||||
let global_agents = cfg.codex_home.join(DEFAULT_AGENTS_MD_FILENAME);
|
||||
fs::create_dir_all(&cfg.codex_home).unwrap();
|
||||
fs::write(&global_agents, "global doc").unwrap();
|
||||
|
||||
let loaded = load_agents_md(&cfg).await.expect("instructions expected");
|
||||
let project_agents = cfg.cwd.join("AGENTS.md");
|
||||
|
||||
let expected = LoadedAgentsMd {
|
||||
user_instructions: Some(UserInstructions {
|
||||
text: "global doc".to_string(),
|
||||
source: global_agents.clone(),
|
||||
}),
|
||||
entries: vec![
|
||||
InstructionEntry {
|
||||
contents: "project doc".to_string(),
|
||||
provenance: project_provenance(project_agents.clone(), cfg.cwd.clone()),
|
||||
},
|
||||
InstructionEntry {
|
||||
contents: HIERARCHICAL_AGENTS_MESSAGE.to_string(),
|
||||
provenance: InstructionProvenance::Internal,
|
||||
},
|
||||
],
|
||||
};
|
||||
assert_eq!(loaded, expected);
|
||||
assert_eq!(
|
||||
loaded.sources().collect::<Vec<_>>(),
|
||||
vec![
|
||||
PathUri::from_abs_path(&global_agents),
|
||||
PathUri::from_abs_path(&project_agents),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
loaded.text(),
|
||||
format!("global doc{AGENTS_MD_SEPARATOR}project doc\n\n{HIERARCHICAL_AGENTS_MESSAGE}")
|
||||
);
|
||||
}
|
||||
|
||||
/// AGENTS.override.md is preferred over AGENTS.md when both are present.
|
||||
#[tokio::test]
|
||||
async fn agents_local_md_preferred() {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
use codex_features::Feature;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
|
||||
const HIERARCHICAL_AGENTS_SNIPPET: &str =
|
||||
"Files called AGENTS.md commonly appear in many places inside a container";
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn hierarchical_agents_appends_to_project_doc_in_user_instructions() {
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp1"), ev_completed("resp1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ChildAgentsMd)
|
||||
.expect("test config should allow feature update");
|
||||
})
|
||||
.with_workspace_setup(|cwd, fs| async move {
|
||||
let agents_md = cwd.join("AGENTS.md");
|
||||
let agents_md_uri = PathUri::from_path(&agents_md)?;
|
||||
fs.write_file(&agents_md_uri, b"be nice".to_vec(), /*sandbox*/ None)
|
||||
.await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
let test = builder
|
||||
.build_with_remote_env(&server)
|
||||
.await
|
||||
.expect("build test codex");
|
||||
|
||||
test.submit_turn("hello").await.expect("submit turn");
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let user_messages = request.message_input_texts("user");
|
||||
let instructions = user_messages
|
||||
.iter()
|
||||
.find(|text| text.starts_with("# AGENTS.md instructions"))
|
||||
.expect("instructions message");
|
||||
assert!(
|
||||
instructions.contains("be nice"),
|
||||
"expected AGENTS.md text included: {instructions}"
|
||||
);
|
||||
let snippet_pos = instructions
|
||||
.find(HIERARCHICAL_AGENTS_SNIPPET)
|
||||
.expect("expected hierarchical agents snippet");
|
||||
let base_pos = instructions
|
||||
.find("be nice")
|
||||
.expect("expected AGENTS.md text");
|
||||
assert!(
|
||||
snippet_pos > base_pos,
|
||||
"expected hierarchical agents message appended after base instructions: {instructions}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn hierarchical_agents_emits_when_no_project_doc() {
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![ev_response_created("resp1"), ev_completed("resp1")]),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ChildAgentsMd)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder
|
||||
.build_with_remote_env(&server)
|
||||
.await
|
||||
.expect("build test codex");
|
||||
|
||||
test.submit_turn("hello").await.expect("submit turn");
|
||||
|
||||
let request = resp_mock.single_request();
|
||||
let user_messages = request.message_input_texts("user");
|
||||
let instructions = user_messages
|
||||
.iter()
|
||||
.find(|text| text.starts_with("# AGENTS.md instructions"))
|
||||
.expect("instructions message");
|
||||
assert!(
|
||||
instructions.contains(HIERARCHICAL_AGENTS_SNIPPET),
|
||||
"expected hierarchical agents message appended: {instructions}"
|
||||
);
|
||||
}
|
||||
@@ -57,7 +57,6 @@ mod extension_sandbox;
|
||||
mod fork_thread;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
mod guardian_review;
|
||||
mod hierarchical_agents;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
mod hooks;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
||||
@@ -21,14 +21,14 @@ async fn emits_warning_when_unstable_features_enabled_via_config() {
|
||||
let mut config = load_default_config_for_test(&home).await;
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ChildAgentsMd)
|
||||
.enable(Feature::ApplyPatchStreamingEvents)
|
||||
.expect("test config should allow feature update");
|
||||
let user_config_path =
|
||||
AbsolutePathBuf::from_absolute_path(config.codex_home.join(CONFIG_TOML_FILE))
|
||||
.expect("absolute user config path");
|
||||
config.config_layer_stack = config.config_layer_stack.with_user_config(
|
||||
&user_config_path,
|
||||
toml! { features = { child_agents_md = true } }.into(),
|
||||
toml! { features = { apply_patch_streaming_events = true } }.into(),
|
||||
);
|
||||
|
||||
let thread_manager = codex_core::test_support::thread_manager_with_models_provider(
|
||||
@@ -56,7 +56,7 @@ async fn emits_warning_when_unstable_features_enabled_via_config() {
|
||||
let EventMsg::Warning(WarningEvent { message }) = warning else {
|
||||
panic!("expected warning event");
|
||||
};
|
||||
assert!(message.contains("child_agents_md"));
|
||||
assert!(message.contains("apply_patch_streaming_events"));
|
||||
assert!(message.contains("Under-development features enabled"));
|
||||
assert!(message.contains("suppress_unstable_features_warning = true"));
|
||||
}
|
||||
@@ -67,7 +67,7 @@ async fn suppresses_warning_when_configured() {
|
||||
let mut config = load_default_config_for_test(&home).await;
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ChildAgentsMd)
|
||||
.enable(Feature::ApplyPatchStreamingEvents)
|
||||
.expect("test config should allow feature update");
|
||||
config.suppress_unstable_features_warning = true;
|
||||
let user_config_path =
|
||||
@@ -75,7 +75,7 @@ async fn suppresses_warning_when_configured() {
|
||||
.expect("absolute user config path");
|
||||
config.config_layer_stack = config.config_layer_stack.with_user_config(
|
||||
&user_config_path,
|
||||
toml! { features = { child_agents_md = true } }.into(),
|
||||
toml! { features = { apply_patch_streaming_events = true } }.into(),
|
||||
);
|
||||
|
||||
let thread_manager = codex_core::test_support::thread_manager_with_models_provider(
|
||||
|
||||
Reference in New Issue
Block a user