diff --git a/codex-rs/core/src/credentialed_routes.rs b/codex-rs/core/src/credentialed_routes.rs index c6e8c484b25..5642658e245 100644 --- a/codex-rs/core/src/credentialed_routes.rs +++ b/codex-rs/core/src/credentialed_routes.rs @@ -7,6 +7,7 @@ use codex_network_proxy::MitmHookActionsConfig; use codex_network_proxy::MitmHookConfig; use codex_network_proxy::MitmHookMatchConfig; use http::HeaderMap; +use std::collections::BTreeSet; use tracing::debug; use tracing::warn; use url::Url; @@ -80,6 +81,26 @@ impl CredentialedRoutesSessionConfig { ) .collect() } + + pub(crate) fn developer_instructions(&self) -> Option { + let route_prefixes = self + .routes + .iter() + .map(|route| route.base_url.clone()) + .collect::>(); + if route_prefixes.is_empty() { + return None; + } + + let route_prefixes = route_prefixes + .into_iter() + .map(|route_prefix| format!("- {route_prefix}")) + .collect::>() + .join("\n"); + Some(format!( + "The managed network proxy automatically attaches stored credentials when you call these HTTPS URL prefixes directly:\n{route_prefixes}" + )) + } } fn route_mitm_hook( @@ -187,4 +208,41 @@ mod tests { }) ); } + + #[test] + fn credentialed_routes_render_model_visible_prefixes() { + let config = CredentialedRoutesSessionConfig { + routes: vec![ + ResolvedCredentialRoute { + connector_id: "connector_b".to_string(), + link_id: "link_b".to_string(), + auth_type: CredentialRouteAuthType::OAuth, + base_url: "https://b.example.com/v1".to_string(), + }, + ResolvedCredentialRoute { + connector_id: "connector_a".to_string(), + link_id: "link_a".to_string(), + auth_type: CredentialRouteAuthType::OAuth, + base_url: "https://a.example.com/v1".to_string(), + }, + ResolvedCredentialRoute { + connector_id: "connector_a".to_string(), + link_id: "link_a".to_string(), + auth_type: CredentialRouteAuthType::OAuth, + base_url: "https://a.example.com/v1".to_string(), + }, + ], + proxy_headers: Vec::new(), + proxy_url: Some( + "https://chatgpt.com/backend-api/wham/credential_routes/proxy".to_string(), + ), + }; + + assert_eq!( + config.developer_instructions(), + Some( + "The managed network proxy automatically attaches stored credentials when you call these HTTPS URL prefixes directly:\n- https://a.example.com/v1\n- https://b.example.com/v1".to_string() + ) + ); + } } diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index e6c1d0cc87a..ac4bdb5eef4 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -2715,6 +2715,11 @@ impl Session { .render(), ); } + if let Some(credentialed_routes_instructions) = + self.services.credentialed_routes.developer_instructions() + { + developer_sections.push(credentialed_routes_instructions); + } let separate_guardian_developer_message = crate::guardian::is_guardian_reviewer_source(&session_source); // Keep the guardian policy prompt out of the aggregated developer bundle so it