fix(codex): load context defaults from CPA model definitions

- Resolve context limits from core model definitions, aliases, and configuration
- Preserve user overrides and display context sources and fallback hints
- Refresh defaults from CPA when restoring all model settings
- Keep restore-all available without customizations and remove its icon
- Allow saving restored defaults even when values remain unchanged
- Add regression coverage for context resolution and default restoration
This commit is contained in:
lzt404 committed 2026-09-07 19:28:21 +08:00
1 parent ce9944c316
commit 40ba85d6f0
10 files changed
+452 -66

No files matched your search

+51 -7
View File
@@ -414,8 +414,7 @@ pub(crate) async fn get_codex_model_catalog_editor(
) -> Result<codex_catalog::CatalogEditorSnapshot, String> {
let _sync_guard = CODEX_CATALOG_SYNC_LOCK.lock().await;
let config = gui_config_state.snapshot()?;
let runtime_models =
fetch_codex_runtime_models(config.port, effective_agent_api_key(&config)).await?;
let runtime_models = fetch_codex_catalog_runtime_models(&config).await?;
codex_catalog::editor_snapshot(&runtime_models)
}
@@ -434,8 +433,7 @@ pub(crate) async fn save_codex_model_catalog_editor(
) -> Result<CodexCatalogEditorSaveResult, String> {
let _sync_guard = CODEX_CATALOG_SYNC_LOCK.lock().await;
let config = gui_config_state.snapshot()?;
let runtime_models =
fetch_codex_runtime_models(config.port, effective_agent_api_key(&config)).await?;
let runtime_models = fetch_codex_catalog_runtime_models(&config).await?;
let snapshot = codex_catalog::save_customizations(
&codex_model_customizations_path(&app)?,
&runtime_models,
@@ -796,13 +794,60 @@ pub(crate) async fn fetch_codex_runtime_models(
Err("本地内核不支持 Codex 模型列表接口".to_string())
}
// The client_version response contains synthesized Codex templates; its context
// fields are not the raw core model definitions. Resolve defaults through the
// management APIs before generating or editing the Codex catalog.
pub(crate) async fn fetch_codex_catalog_runtime_models(
config: &GuiConfigFile,
) -> Result<Vec<codex_catalog::CodexRuntimeModel>, String> {
let (runtime, definitions, content) = tokio::join!(
fetch_codex_runtime_models(config.port, effective_agent_api_key(config)),
fetch_codex_context_definitions(config),
fetch_management_config_yaml(config),
);
let mut runtime = runtime?;
let definitions = definitions?;
let content = content?;
let mut aliases = runtime.iter().map(|model| AgentModelOption {
name: model.slug.clone(), alias: None, is_alias: false, context_window: None,
}).collect::<Vec<_>>();
mark_configured_agent_model_aliases(&mut aliases, &content)?;
codex_catalog::merge_context_definitions(&mut runtime, &definitions, &aliases);
codex_catalog::apply_configured_context_limits(&mut runtime, &content)?;
Ok(runtime)
}
async fn fetch_codex_context_definitions(
config: &GuiConfigFile,
) -> Result<Vec<CodexModelDefinition>, String> {
// API-key sources may expose models from other channels, so do not filter by
// active OAuth credentials. Model IDs still come only from the available list.
let channels = ["gemini", "vertex", "aistudio", "antigravity", "claude", "codex", "kimi", "xai"];
let results = futures_util::future::join_all(channels.iter().map(|channel|
fetch_oauth_channel_model_definitions(config, channel)
)).await;
let mut definitions = Vec::new();
let mut successes = 0;
let mut first_error = None;
for result in results {
match result {
Ok(models) => { successes += 1; definitions.extend(models); }
Err(error) => { first_error.get_or_insert(error); }
}
}
if successes == 0 {
return Err(format!("读取 CPA 模型上下文定义失败: {}", first_error.unwrap_or_default()));
}
Ok(definitions)
}
pub(crate) async fn fetch_prepared_agent_models(
client: AgentClient,
config: &GuiConfigFile,
) -> Result<PreparedAgentModels, String> {
let api_key = effective_agent_api_key(config);
if client == AgentClient::Codex {
let runtime_models = fetch_codex_runtime_models(config.port, api_key).await?;
let runtime_models = fetch_codex_catalog_runtime_models(config).await?;
prepare_codex_agent_models(&runtime_models)
} else {
let mut models = fetch_agent_models(config.port, api_key).await?;
@@ -872,8 +917,7 @@ pub(crate) async fn refresh_applied_codex_model_catalog(
config: &GuiConfigFile,
) -> Result<bool, String> {
let _sync_guard = CODEX_CATALOG_SYNC_LOCK.lock().await;
let runtime_models =
fetch_codex_runtime_models(config.port, effective_agent_api_key(config)).await?;
let runtime_models = fetch_codex_catalog_runtime_models(config).await?;
let prepared = prepare_codex_agent_models(&runtime_models)?;
sync_prepared_codex_model_catalog(app, config, &prepared)
}