mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Allow catalog URL overrides for the built-in OpenAI provider (#57567)
## What changed Allow `model_catalog_url` under `[model_providers.openai]` while preserving the built-in provider's identity, authentication, and inference routing through `openai_base_url`. Reject other non-default overrides and require an HTTPS catalog URL on an allowed ChatGPT host, without embedded credentials. Apply the same catalog override merging when checking managed provider requirements for existing threads, preserving each thread's inference endpoint even if user defaults change. Document the required Codex catalog format, credential forwarding, and existing discovery and access restrictions. ## Testing Add coverage for allowed and rejected catalog destinations, preservation of built-in provider settings, and managed requirement changes. Add integration coverage for API key and ChatGPT authentication that verifies separate catalog and inference routing. GitOrigin-RevId: 4d91ada518ebd2a09cbf6ded0ddf4b11c92b77dd
This commit is contained in:
@@ -17,6 +17,7 @@ use codex_login::default_client::set_default_client_residency_requirement;
|
||||
use codex_model_provider_info::AMAZON_BEDROCK_PROVIDER_ID;
|
||||
use codex_model_provider_info::AMAZON_BEDROCK_RUNTIME_PROVIDER_ID;
|
||||
use codex_model_provider_info::GCP_PROVIDER_ID;
|
||||
use codex_model_provider_info::OPENAI_PROVIDER_ID;
|
||||
use codex_model_provider_info::built_in_model_providers;
|
||||
use codex_model_provider_info::merge_configured_model_providers;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -380,11 +381,13 @@ impl ConfigManager {
|
||||
AMAZON_BEDROCK_PROVIDER_ID
|
||||
| AMAZON_BEDROCK_RUNTIME_PROVIDER_ID
|
||||
| GCP_PROVIDER_ID
|
||||
| OPENAI_PROVIDER_ID
|
||||
) =>
|
||||
{
|
||||
// Managed overrides must receive the same built-in defaults as startup config.
|
||||
// OpenAI's inference URL belongs to the retained session, not the catalog override.
|
||||
let mut provider = merge_configured_model_providers(
|
||||
built_in_model_providers(/*openai_base_url*/ None),
|
||||
built_in_model_providers(current.model_provider.base_url.clone()),
|
||||
HashMap::from([(current.model_provider_id.clone(), provider)]),
|
||||
)
|
||||
.map_err(|message| std::io::Error::new(std::io::ErrorKind::InvalidData, message))?
|
||||
|
||||
@@ -14,20 +14,29 @@ use pretty_assertions::assert_eq;
|
||||
use tempfile::tempdir;
|
||||
use test_case::test_case;
|
||||
|
||||
#[test_case(AMAZON_BEDROCK_PROVIDER_ID, "aws.region = 'us-west-2'", "us-west-2", "us-east-1"; "bedrock")]
|
||||
#[test_case(AMAZON_BEDROCK_RUNTIME_PROVIDER_ID, "aws.region = 'us-west-2'", "us-west-2", "us-east-1"; "bedrock_runtime")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nlocation = 'us-central1'", "example-project", "other-project"; "gcp_project")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nlocation = 'us-central1'", "us-central1", "us-east4"; "gcp_location")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nauth.command = 'print-token'", "print-token", "other-token"; "gcp_auth")]
|
||||
#[test_case(AMAZON_BEDROCK_PROVIDER_ID, "aws.region = 'us-west-2'", "us-west-2", "us-east-1", None; "bedrock")]
|
||||
#[test_case(AMAZON_BEDROCK_RUNTIME_PROVIDER_ID, "aws.region = 'us-west-2'", "us-west-2", "us-east-1", None; "bedrock_runtime")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nlocation = 'us-central1'", "example-project", "other-project", None; "gcp_project")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nlocation = 'us-central1'", "us-central1", "us-east4", None; "gcp_location")]
|
||||
#[test_case(GCP_PROVIDER_ID, "project_id = 'example-project'\nauth.command = 'print-token'", "print-token", "other-token", None; "gcp_auth")]
|
||||
#[test_case("openai", "model_catalog_url = 'https://chatgpt.com/backend-api/codex/models'", "https://chatgpt.com/backend-api/codex/models", "https://chatgpt.com/backend-api/codex/other-models", None; "openai_catalog")]
|
||||
#[test_case("openai", "model_catalog_url = 'https://chatgpt.com/backend-api/codex/models'", "https://chatgpt.com/backend-api/codex/models", "https://chatgpt.com/backend-api/codex/other-models", Some("https://us.api.openai.com/v1"); "openai_regional_catalog")]
|
||||
#[tokio::test]
|
||||
async fn provider_requirements_resolve_builtin_overrides(
|
||||
provider_id: &str,
|
||||
provider_config: &str,
|
||||
original: &str,
|
||||
replacement: &str,
|
||||
openai_base_url: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let home = tempdir()?;
|
||||
let workspace = tempdir()?;
|
||||
if let Some(base_url) = openai_base_url {
|
||||
std::fs::write(
|
||||
home.path().join("config.toml"),
|
||||
format!("openai_base_url = '{base_url}'"),
|
||||
)?;
|
||||
}
|
||||
let requirements = format!(
|
||||
"model_provider = '{provider_id}'\n[model_providers.{provider_id}]\n{provider_config}"
|
||||
);
|
||||
@@ -40,6 +49,14 @@ async fn provider_requirements_resolve_builtin_overrides(
|
||||
let current = manager
|
||||
.load_latest_config(Some(workspace.path().to_path_buf()))
|
||||
.await?;
|
||||
if provider_id == "openai" {
|
||||
assert_eq!(current.model_provider.base_url.as_deref(), openai_base_url);
|
||||
// Retained threads keep their inference route even if user defaults later change.
|
||||
std::fs::write(
|
||||
home.path().join("config.toml"),
|
||||
"openai_base_url = 'https://eu.api.openai.com/v1'",
|
||||
)?;
|
||||
}
|
||||
manager.check_thread_model_provider(¤t).await?;
|
||||
|
||||
let changed = ConfigManager::new_for_tests(
|
||||
|
||||
Reference in New Issue
Block a user