diff --git a/codex-rs/chatgpt/src/connectors.rs b/codex-rs/chatgpt/src/connectors.rs index 3430e1202..6dc2161f0 100644 --- a/codex-rs/chatgpt/src/connectors.rs +++ b/codex-rs/chatgpt/src/connectors.rs @@ -4,6 +4,8 @@ use std::sync::LazyLock; use std::sync::Mutex as StdMutex; use codex_core::config::Config; +use codex_core::default_client::is_first_party_chat_originator; +use codex_core::default_client::originator; use codex_core::features::Feature; use codex_core::token_data::TokenData; use serde::Deserialize; @@ -460,23 +462,34 @@ const DISALLOWED_CONNECTOR_IDS: &[&str] = &[ "connector_69272cb413a081919685ec3c88d1744e", "connector_0f9c9d4592e54d0a9a12b3f44a1e2010", ]; +const FIRST_PARTY_CHAT_DISALLOWED_CONNECTOR_IDS: &[&str] = + &["connector_0f9c9d4592e54d0a9a12b3f44a1e2010"]; const DISALLOWED_CONNECTOR_PREFIX: &str = "connector_openai_"; fn filter_disallowed_connectors(connectors: Vec) -> Vec { + filter_disallowed_connectors_for_originator(connectors, originator().value.as_str()) +} + +fn filter_disallowed_connectors_for_originator( + connectors: Vec, + originator_value: &str, +) -> Vec { + let disallowed_connector_ids = if is_first_party_chat_originator(originator_value) { + FIRST_PARTY_CHAT_DISALLOWED_CONNECTOR_IDS + } else { + DISALLOWED_CONNECTOR_IDS + }; + connectors .into_iter() - .filter(is_connector_allowed) + .filter(|connector| is_connector_allowed(connector, disallowed_connector_ids)) .collect() } -fn is_connector_allowed(connector: &AppInfo) -> bool { +fn is_connector_allowed(connector: &AppInfo, disallowed_connector_ids: &[&str]) -> bool { let connector_id = connector.id.as_str(); - if connector_id.starts_with(DISALLOWED_CONNECTOR_PREFIX) - || DISALLOWED_CONNECTOR_IDS.contains(&connector_id) - { - return false; - } - true + !connector_id.starts_with(DISALLOWED_CONNECTOR_PREFIX) + && !disallowed_connector_ids.contains(&connector_id) } #[cfg(test)] @@ -523,7 +536,7 @@ mod tests { } #[test] - fn filters_openai_connectors() { + fn filters_openai_prefixed_connectors() { let filtered = filter_disallowed_connectors(vec![ app("connector_openai_foo"), app("connector_openai_bar"), @@ -541,6 +554,22 @@ mod tests { assert_eq!(filtered, vec![app("delta")]); } + #[test] + fn first_party_chat_originator_filters_target_and_openai_prefixed_connectors() { + let filtered = filter_disallowed_connectors_for_originator( + vec![ + app("connector_openai_foo"), + app("asdk_app_6938a94a61d881918ef32cb999ff937c"), + app("connector_0f9c9d4592e54d0a9a12b3f44a1e2010"), + ], + "codex_atlas", + ); + assert_eq!( + filtered, + vec![app("asdk_app_6938a94a61d881918ef32cb999ff937c"),] + ); + } + fn merged_app(id: &str, is_accessible: bool) -> AppInfo { AppInfo { id: id.to_string(), diff --git a/codex-rs/core/src/default_client.rs b/codex-rs/core/src/default_client.rs index f4957883a..aa490e826 100644 --- a/codex-rs/core/src/default_client.rs +++ b/codex-rs/core/src/default_client.rs @@ -114,6 +114,10 @@ pub fn is_first_party_originator(originator_value: &str) -> bool { || originator_value.starts_with("Codex ") } +pub fn is_first_party_chat_originator(originator_value: &str) -> bool { + originator_value == "codex_atlas" || originator_value == "codex_chatgpt_desktop" +} + pub fn get_codex_user_agent() -> String { let build_version = env!("CARGO_PKG_VERSION"); let os_info = os_info::get(); @@ -234,6 +238,17 @@ mod tests { assert_eq!(is_first_party_originator("Other"), false); } + #[test] + fn is_first_party_chat_originator_matches_known_values() { + assert_eq!(is_first_party_chat_originator("codex_atlas"), true); + assert_eq!( + is_first_party_chat_originator("codex_chatgpt_desktop"), + true + ); + assert_eq!(is_first_party_chat_originator(DEFAULT_ORIGINATOR), false); + assert_eq!(is_first_party_chat_originator("codex_vscode"), false); + } + #[tokio::test] async fn test_create_client_sets_default_headers() { skip_if_no_network!();