diff --git a/crates/codex-plus-core/src/ccs_import.rs b/crates/codex-plus-core/src/ccs_import.rs index 4f275e960..8e58e1bd5 100644 --- a/crates/codex-plus-core/src/ccs_import.rs +++ b/crates/codex-plus-core/src/ccs_import.rs @@ -322,10 +322,10 @@ fn extract_toml_string_value(text: &str, key: &str) -> Option { } fn build_config_toml(base_url: &str, api_key: &str, protocol: RelayProtocol) -> String { - let wire_api = match protocol { - RelayProtocol::Responses => "responses", - RelayProtocol::ChatCompletions => "chat", - }; + // Codex 26.901+ 不再支持 wire_api = "chat"(openai/codex discussion #7782), + // Chat Completions 上游由本地协议代理转换,对 Codex 始终暴露 "responses"。 + let _ = protocol; + let wire_api = "responses"; [ "model_provider = \"CodexPlusPlus\"".to_string(), String::new(), diff --git a/crates/codex-plus-core/src/provider_import.rs b/crates/codex-plus-core/src/provider_import.rs index e0775e114..d1c465b52 100644 --- a/crates/codex-plus-core/src/provider_import.rs +++ b/crates/codex-plus-core/src/provider_import.rs @@ -255,10 +255,11 @@ fn relay_mode(value: &str) -> RelayMode { } fn build_config_toml(base_url: &str, api_key: &str, protocol: RelayProtocol) -> String { - let wire_api = match protocol { - RelayProtocol::Responses => "responses", - RelayProtocol::ChatCompletions => "chat", - }; + // Codex 26.901+ 不再支持 wire_api = "chat"(openai/codex discussion #7782), + // 写出 "chat" 会导致整份 config.toml 无效并回退默认。Chat Completions 上游 + // 一律经由本地协议代理转换,对 Codex 始终暴露 "responses"。 + let _ = protocol; + let wire_api = "responses"; [ "model_provider = \"CodexPlusPlus\"".to_string(), String::new(), diff --git a/crates/codex-plus-core/src/relay_config.rs b/crates/codex-plus-core/src/relay_config.rs index d2be4bf32..85e5dc85d 100644 --- a/crates/codex-plus-core/src/relay_config.rs +++ b/crates/codex-plus-core/src/relay_config.rs @@ -1896,7 +1896,12 @@ fn apply_model_catalog_to_config( || entries .iter() .any(|entry| entry.suffix_window.is_some() || entry.auto_compact_percent.is_some()); - let custom_responses = custom_responses_provider(&config_text); + // custom_responses_provider(&config_text) 读取的是生成后 config 里的 wire_api; + // 自对 Codex 恒写 "responses" 起,该信号已失真(chat 上游也会读到 responses)。 + // catalog 是否按 Responses 语义生成取决于真实上游协议,只能由 profile.protocol 判定。 + let custom_responses = profile.protocol == RelayProtocol::Responses + && active_provider_id(&parse_toml_document(&config_text)?) + .is_some_and(|provider_id| is_custom_provider_id(&provider_id)); // Catalog capabilities must follow the effective config, not stale profile URLs. let official_deepseek_responses = uses_official_deepseek_responses_for_config(profile, &config_text); @@ -2193,25 +2198,6 @@ fn uses_official_deepseek_responses_for_config(profile: &RelayProfile, config_te uses_official_deepseek_responses(profile) } -fn custom_responses_provider(config_text: &str) -> bool { - let Ok(doc) = parse_toml_document(config_text) else { - return false; - }; - let Some(provider_id) = active_provider_id(&doc) else { - return false; - }; - if !is_custom_provider_id(&provider_id) { - return false; - } - doc.get("model_providers") - .and_then(Item::as_table) - .and_then(|providers| providers.get(&provider_id)) - .and_then(Item::as_table_like) - .and_then(|provider| provider.get("wire_api")) - .and_then(Item::as_str) - .is_some_and(|wire_api| wire_api.trim().eq_ignore_ascii_case("responses")) -} - fn copy_standard_responses_catalog( home: &Path, source: &str, @@ -2911,14 +2897,11 @@ fn complete_relay_profile_config(profile: &RelayProfile) -> anyhow::Result