From d18a7c982e4abad5bf549cda6f4b61a18c10702e Mon Sep 17 00:00:00 2001 From: Dylan Hurd Date: Wed, 13 May 2026 12:33:36 -0700 Subject: [PATCH] chore(config) rm Feature::CodexGitCommit (#22412) ## Summary Removes the unused Feature::CodexGitCommit ## Testing - [x] tests pass --- codex-rs/Cargo.lock | 11 -- codex-rs/Cargo.toml | 2 - codex-rs/app-server/Cargo.toml | 1 - codex-rs/app-server/src/extensions.rs | 1 - codex-rs/config/src/config_toml.rs | 8 -- codex-rs/core/config.schema.json | 4 - codex-rs/core/src/config/config_tests.rs | 4 - codex-rs/core/src/config/mod.rs | 12 -- codex-rs/core/src/session/tests.rs | 32 ++--- codex-rs/ext/git-attribution/BUILD.bazel | 6 - codex-rs/ext/git-attribution/Cargo.toml | 21 ---- codex-rs/ext/git-attribution/src/lib.rs | 134 --------------------- codex-rs/features/src/lib.rs | 5 +- codex-rs/thread-manager-sample/src/main.rs | 1 - 14 files changed, 18 insertions(+), 224 deletions(-) delete mode 100644 codex-rs/ext/git-attribution/BUILD.bazel delete mode 100644 codex-rs/ext/git-attribution/Cargo.toml delete mode 100644 codex-rs/ext/git-attribution/src/lib.rs diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 25827331b2..a0a49e4399 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1902,7 +1902,6 @@ dependencies = [ "codex-feedback", "codex-file-search", "codex-file-watcher", - "codex-git-attribution", "codex-git-utils", "codex-guardian", "codex-hooks", @@ -2912,16 +2911,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "codex-git-attribution" -version = "0.0.0" -dependencies = [ - "codex-core", - "codex-extension-api", - "codex-features", - "pretty_assertions", -] - [[package]] name = "codex-git-utils" version = "0.0.0" diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index f5cfda7296..14b1264a81 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -46,7 +46,6 @@ members = [ "execpolicy-legacy", "ext/extension-api", "ext/guardian", - "ext/git-attribution", "ext/memories", "external-agent-migration", "external-agent-sessions", @@ -164,7 +163,6 @@ codex-exec-server = { path = "exec-server" } codex-execpolicy = { path = "execpolicy" } codex-extension-api = { path = "ext/extension-api" } codex-guardian = { path = "ext/guardian" } -codex-git-attribution = { path = "ext/git-attribution" } codex-external-agent-migration = { path = "external-agent-migration" } codex-external-agent-sessions = { path = "external-agent-sessions" } codex-experimental-api-macros = { path = "codex-experimental-api-macros" } diff --git a/codex-rs/app-server/Cargo.toml b/codex-rs/app-server/Cargo.toml index ecc8d1c25a..c75461ecf7 100644 --- a/codex-rs/app-server/Cargo.toml +++ b/codex-rs/app-server/Cargo.toml @@ -42,7 +42,6 @@ codex-external-agent-migration = { workspace = true } codex-external-agent-sessions = { workspace = true } codex-features = { workspace = true } codex-guardian = { workspace = true } -codex-git-attribution = { workspace = true } codex-git-utils = { workspace = true } codex-file-watcher = { workspace = true } codex-hooks = { workspace = true } diff --git a/codex-rs/app-server/src/extensions.rs b/codex-rs/app-server/src/extensions.rs index 411685e7d8..a293daf4f2 100644 --- a/codex-rs/app-server/src/extensions.rs +++ b/codex-rs/app-server/src/extensions.rs @@ -17,7 +17,6 @@ where S: AgentSpawner + 'static, { let mut builder = ExtensionRegistryBuilder::::new(); - codex_git_attribution::install(&mut builder); codex_guardian::install(&mut builder, guardian_agent_spawner); Arc::new(builder.build()) } diff --git a/codex-rs/config/src/config_toml.rs b/codex-rs/config/src/config_toml.rs index 06993e046a..fdca03de1a 100644 --- a/codex-rs/config/src/config_toml.rs +++ b/codex-rs/config/src/config_toml.rs @@ -177,14 +177,6 @@ pub struct ConfigToml { /// Compact prompt used for history compaction. pub compact_prompt: Option, - /// Optional commit attribution text for commit message co-author trailers. - /// This top-level setting only takes effect when `[features].codex_git_commit` - /// is enabled. - /// - /// When enabled and unset, Codex uses `Codex `. - /// Set to an empty string to disable automatic commit attribution. - pub commit_attribution: Option, - /// When set, restricts ChatGPT login to a specific workspace identifier. #[serde(default)] pub forced_chatgpt_workspace_id: Option, diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index faf7ec6817..847cd48399 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -4026,10 +4026,6 @@ "default": null, "description": "Preferred backend for storing CLI auth credentials. file (default): Use a file in the Codex home directory. keyring: Use an OS-specific keyring service. auto: Use the keyring if available, otherwise use a file." }, - "commit_attribution": { - "description": "Optional commit attribution text for commit message co-author trailers. This top-level setting only takes effect when `[features].codex_git_commit` is enabled.\n\nWhen enabled and unset, Codex uses `Codex `. Set to an empty string to disable automatic commit attribution.", - "type": "string" - }, "compact_prompt": { "description": "Compact prompt used for history compaction.", "type": "string" diff --git a/codex-rs/core/src/config/config_tests.rs b/codex-rs/core/src/config/config_tests.rs index 664730805a..d4db387631 100644 --- a/codex-rs/core/src/config/config_tests.rs +++ b/codex-rs/core/src/config/config_tests.rs @@ -7357,7 +7357,6 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> { include_skill_instructions: true, include_environment_context: true, compact_prompt: None, - commit_attribution: None, forced_chatgpt_workspace_id: None, forced_login_method: None, include_apply_patch_tool: true, @@ -7805,7 +7804,6 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> { include_skill_instructions: true, include_environment_context: true, compact_prompt: None, - commit_attribution: None, forced_chatgpt_workspace_id: None, forced_login_method: None, include_apply_patch_tool: true, @@ -7967,7 +7965,6 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> { include_skill_instructions: true, include_environment_context: true, compact_prompt: None, - commit_attribution: None, forced_chatgpt_workspace_id: None, forced_login_method: None, include_apply_patch_tool: true, @@ -8114,7 +8111,6 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> { include_skill_instructions: true, include_environment_context: true, compact_prompt: None, - commit_attribution: None, forced_chatgpt_workspace_id: None, forced_login_method: None, include_apply_patch_tool: true, diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 2071e1ed25..4aa3230332 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -478,15 +478,6 @@ pub struct Config { /// Compact prompt override. pub compact_prompt: Option, - /// Optional commit attribution text for commit message co-author trailers. - /// This top-level setting only takes effect when `[features].codex_git_commit` - /// is enabled. - /// - /// - `None`: use default attribution (`Codex `) - /// - `Some("")` or whitespace-only: disable commit attribution - /// - `Some("...")`: use the provided attribution text verbatim - pub commit_attribution: Option, - /// Optional external notifier command. When set, Codex will spawn this /// program after each completed *turn* (i.e. when the agent finishes /// processing a user submission). The value must be the full command @@ -2809,8 +2800,6 @@ impl Config { } }); - let commit_attribution = cfg.commit_attribution; - // Load base instructions override from a file if specified. If the // path is relative, resolve it against the effective cwd so the // behaviour matches other path-like config values. @@ -3052,7 +3041,6 @@ impl Config { personality, developer_instructions, compact_prompt, - commit_attribution, include_permissions_instructions, include_apps_instructions, include_collaboration_mode_instructions, diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 577b2fa5ec..36e4e866d9 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -6493,10 +6493,10 @@ async fn make_multi_agent_v2_usage_hint_test_session( (session, turn_context) } -struct GitAttributionTestContributor; -struct GitAttributionTestState; +struct PromptExtensionTestContributor; +struct PromptExtensionTestState; -impl codex_extension_api::ContextContributor for GitAttributionTestContributor { +impl codex_extension_api::ContextContributor for PromptExtensionTestContributor { fn contribute<'a>( &'a self, _session_store: &'a codex_extension_api::ExtensionData, @@ -6506,11 +6506,11 @@ impl codex_extension_api::ContextContributor for GitAttributionTestContributor { > { Box::pin(async move { thread_store - .get::() + .get::() .is_some() .then(|| { codex_extension_api::PromptFragment::developer_policy( - "git attribution extension enabled", + "prompt extension enabled", ) }) .into_iter() @@ -6519,21 +6519,21 @@ impl codex_extension_api::ContextContributor for GitAttributionTestContributor { } } -fn git_attribution_test_registry() +fn prompt_extension_test_registry() -> Arc> { let mut builder = codex_extension_api::ExtensionRegistryBuilder::new(); - builder.prompt_contributor(Arc::new(GitAttributionTestContributor)); + builder.prompt_contributor(Arc::new(PromptExtensionTestContributor)); Arc::new(builder.build()) } #[tokio::test] -async fn build_initial_context_includes_git_attribution_from_extensions() { +async fn build_initial_context_includes_prompt_fragments_from_extensions() { let (mut session, turn_context) = make_session_and_context().await; - session.services.extensions = git_attribution_test_registry(); + session.services.extensions = prompt_extension_test_registry(); session .services .thread_extension_data - .insert(GitAttributionTestState); + .insert(PromptExtensionTestState); let initial_context = session.build_initial_context(&turn_context).await; let developer_messages = developer_message_texts(&initial_context); @@ -6542,15 +6542,15 @@ async fn build_initial_context_includes_git_attribution_from_extensions() { developer_messages .iter() .flatten() - .any(|text| *text == "git attribution extension enabled"), - "expected git attribution developer text, got {developer_messages:?}" + .any(|text| *text == "prompt extension enabled"), + "expected prompt extension developer text, got {developer_messages:?}" ); } #[tokio::test] -async fn build_initial_context_omits_git_attribution_when_feature_is_disabled() { +async fn build_initial_context_omits_prompt_fragments_without_extension_state() { let (mut session, turn_context) = make_session_and_context().await; - session.services.extensions = git_attribution_test_registry(); + session.services.extensions = prompt_extension_test_registry(); let initial_context = session.build_initial_context(&turn_context).await; let developer_messages = developer_message_texts(&initial_context); @@ -6559,8 +6559,8 @@ async fn build_initial_context_omits_git_attribution_when_feature_is_disabled() !developer_messages .iter() .flatten() - .any(|text| *text == "git attribution extension enabled"), - "did not expect git attribution developer text, got {developer_messages:?}" + .any(|text| *text == "prompt extension enabled"), + "did not expect prompt extension developer text, got {developer_messages:?}" ); } diff --git a/codex-rs/ext/git-attribution/BUILD.bazel b/codex-rs/ext/git-attribution/BUILD.bazel deleted file mode 100644 index 0cb1ab5764..0000000000 --- a/codex-rs/ext/git-attribution/BUILD.bazel +++ /dev/null @@ -1,6 +0,0 @@ -load("//:defs.bzl", "codex_rust_crate") - -codex_rust_crate( - name = "git-attribution", - crate_name = "codex_git_attribution", -) diff --git a/codex-rs/ext/git-attribution/Cargo.toml b/codex-rs/ext/git-attribution/Cargo.toml deleted file mode 100644 index edf8c07196..0000000000 --- a/codex-rs/ext/git-attribution/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -edition.workspace = true -license.workspace = true -name = "codex-git-attribution" -version.workspace = true - -[lib] -name = "codex_git_attribution" -path = "src/lib.rs" -doctest = false - -[lints] -workspace = true - -[dependencies] -codex-core = { workspace = true } -codex-extension-api = { workspace = true } -codex-features = { workspace = true } - -[dev-dependencies] -pretty_assertions = { workspace = true } diff --git a/codex-rs/ext/git-attribution/src/lib.rs b/codex-rs/ext/git-attribution/src/lib.rs deleted file mode 100644 index 03655296da..0000000000 --- a/codex-rs/ext/git-attribution/src/lib.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::sync::Arc; - -use codex_core::config::Config; -use codex_extension_api::ContextContributor; -use codex_extension_api::ExtensionData; -use codex_extension_api::ExtensionRegistryBuilder; -use codex_extension_api::PromptFragment; -use codex_extension_api::ThreadLifecycleContributor; -use codex_extension_api::ThreadStartInput; -use codex_features::Feature; - -const DEFAULT_ATTRIBUTION_VALUE: &str = "Codex "; - -/// Contributes the configured git-attribution instruction. -#[derive(Clone, Copy, Debug, Default)] -pub struct GitAttributionExtension; - -impl ContextContributor for GitAttributionExtension { - fn contribute<'a>( - &'a self, - _session_store: &'a ExtensionData, - thread_store: &'a ExtensionData, - ) -> std::pin::Pin> + Send + 'a>> { - Box::pin(async move { - let Some(config_store) = thread_store.get::() else { - return Vec::new(); - }; - if !config_store.enabled { - return Vec::new(); - } - build_instruction(config_store.prompt.as_deref()) - .map(PromptFragment::developer_policy) - .into_iter() - .collect() - }) - } -} - -#[derive(Clone, Debug, Default)] -struct GitAttributionConfig { - enabled: bool, - prompt: Option, -} - -impl ThreadLifecycleContributor for GitAttributionExtension { - fn on_thread_start(&self, input: ThreadStartInput<'_, Config>) { - input.thread_store.insert(GitAttributionConfig { - enabled: input.config.features.enabled(Feature::CodexGitCommit), - prompt: input.config.commit_attribution.clone(), - }); - } -} - -/// Installs the git-attribution contributors into the extension registry. -pub fn install(registry: &mut ExtensionRegistryBuilder) { - let extension = Arc::new(GitAttributionExtension); - registry.thread_lifecycle_contributor(extension.clone()); - registry.prompt_contributor(extension); -} - -fn build_commit_message_trailer(config_attribution: Option<&str>) -> Option { - let value = resolve_attribution_value(config_attribution)?; - Some(format!("Co-authored-by: {value}")) -} - -fn build_instruction(config_attribution: Option<&str>) -> Option { - let trailer = build_commit_message_trailer(config_attribution)?; - Some(format!( - "When you write or edit a git commit message, ensure the message ends with this trailer exactly once:\n{trailer}\n\nRules:\n- Keep existing trailers and append this trailer at the end if missing.\n- Do not duplicate this trailer if it already exists.\n- Keep one blank line between the commit body and trailer block." - )) -} - -fn resolve_attribution_value(config_attribution: Option<&str>) -> Option { - match config_attribution { - Some(value) => { - let trimmed = value.trim(); - if trimmed.is_empty() { - None - } else { - Some(trimmed.to_string()) - } - } - None => Some(DEFAULT_ATTRIBUTION_VALUE.to_string()), - } -} - -#[cfg(test)] -mod tests { - use pretty_assertions::assert_eq; - - use super::build_commit_message_trailer; - use super::build_instruction; - use super::resolve_attribution_value; - - #[test] - fn blank_attribution_disables_trailer_prompt() { - assert_eq!(build_commit_message_trailer(Some("")), None); - assert_eq!(build_instruction(Some(" ")), None); - } - - #[test] - fn default_attribution_uses_codex_trailer() { - assert_eq!( - build_commit_message_trailer(/*config_attribution*/ None).as_deref(), - Some("Co-authored-by: Codex ") - ); - } - - #[test] - fn resolve_value_handles_default_custom_and_blank() { - assert_eq!( - resolve_attribution_value(/*config_attribution*/ None), - Some("Codex ".to_string()) - ); - assert_eq!( - resolve_attribution_value(Some("MyAgent ")), - Some("MyAgent ".to_string()) - ); - assert_eq!( - resolve_attribution_value(Some("MyAgent")), - Some("MyAgent".to_string()) - ); - assert_eq!(resolve_attribution_value(Some(" ")), None); - } - - #[test] - fn instruction_mentions_trailer_and_omits_generated_with() { - let instruction = - build_instruction(Some("AgentX ")).expect("instruction expected"); - assert!(instruction.contains("Co-authored-by: AgentX ")); - assert!(instruction.contains("exactly once")); - assert!(!instruction.contains("Generated-with")); - } -} diff --git a/codex-rs/features/src/lib.rs b/codex-rs/features/src/lib.rs index 75535cbaaa..c0a7a8a54d 100644 --- a/codex-rs/features/src/lib.rs +++ b/codex-rs/features/src/lib.rs @@ -130,7 +130,7 @@ pub enum Feature { RemoteModels, /// Experimental shell snapshotting. ShellSnapshot, - /// Enable git commit attribution guidance via model instructions. + /// Removed legacy git commit attribution guidance flag. CodexGitCommit, /// Enable runtime metrics snapshots via a manual reader. RuntimeMetrics, @@ -784,11 +784,10 @@ pub const FEATURES: &[FeatureSpec] = &[ stage: Stage::Removed, default_enabled: false, }, - // Experimental program. Rendered in the `/experimental` menu for users. FeatureSpec { id: Feature::CodexGitCommit, key: "codex_git_commit", - stage: Stage::UnderDevelopment, + stage: Stage::Removed, default_enabled: false, }, FeatureSpec { diff --git a/codex-rs/thread-manager-sample/src/main.rs b/codex-rs/thread-manager-sample/src/main.rs index 5f9fa813e0..fff914eff3 100644 --- a/codex-rs/thread-manager-sample/src/main.rs +++ b/codex-rs/thread-manager-sample/src/main.rs @@ -196,7 +196,6 @@ fn new_config(model: Option, arg0_paths: Arg0DispatchPaths) -> anyhow::R include_skill_instructions: false, include_environment_context: false, compact_prompt: None, - commit_attribution: None, notify: None, tui_notifications: TuiNotificationSettings::default(), animations: true,