fix(aliases): delete API aliases without reasoning overrides

Determine deletability from the actual provider model mapping instead of requiring an effort payload rule. Keep source models and unrelated aliases intact.

Validation: cargo test --locked tests::alias_delete (3 passed), covering all four API provider sections, removing every option in the editor, and real-model name collisions.
This commit is contained in:
lzt404 committed 2026-09-11 16:25:14 +08:00
1 parent 69cc19679c
commit e84e576d1d
3 files changed
+71 -9

No files matched your search

+5 -9
View File
@@ -1906,10 +1906,10 @@ pub(crate) fn remove_thinking_alias_from_yaml_for_channel(
.ok_or_else(|| "内核配置顶层必须是 YAML 映射".to_string())?;
let mut removed = remove_oauth_model_alias(root, alias, oauth_channel)?;
if oauth_channel.is_none() {
removed |= remove_config_thinking_alias(root, "codex-api-key", "codex", alias)?;
removed |= remove_config_thinking_alias(root, "openai-compatibility", "openai", alias)?;
removed |= remove_config_thinking_alias(root, "claude-api-key", "claude", alias)?;
removed |= remove_config_thinking_alias(root, "gemini-api-key", "gemini", alias)?;
removed |= remove_config_model_alias(root, "codex-api-key", alias)?;
removed |= remove_config_model_alias(root, "openai-compatibility", alias)?;
removed |= remove_config_model_alias(root, "claude-api-key", alias)?;
removed |= remove_config_model_alias(root, "gemini-api-key", alias)?;
}
if !removed {
return Err(format!("别名模型 {alias} 不存在,请刷新后重试"));
@@ -2021,15 +2021,11 @@ pub(crate) fn configured_model_alias_exists(root: &serde_norway::Mapping, alias:
.any(|value| value.eq_ignore_ascii_case(alias))
}
pub(crate) fn remove_config_thinking_alias(
pub(crate) fn remove_config_model_alias(
root: &mut serde_norway::Mapping,
section: &str,
protocol: &str,
alias: &str,
) -> Result<bool, String> {
if find_thinking_alias_effort(root, alias, protocol).is_none() {
return Ok(false);
}
let Some(providers) = yaml_mapping_value_mut(root, section) else {
return Ok(false);
};
+1
View File
@@ -4,6 +4,7 @@ mod agent_configuration;
mod agent_paths;
mod agent_state;
mod agent_transactions;
mod alias_delete;
mod alias_edit;
mod alias_edit_regressions;
mod alias_save;
+65
View File
@@ -0,0 +1,65 @@
use super::support::*;
use super::*;
fn json(content: &str) -> serde_json::Value {
serde_json::to_value(serde_norway::from_str::<serde_norway::Value>(content).unwrap()).unwrap()
}
#[test]
fn plain_api_aliases_can_be_deleted_for_every_provider() {
for section in MODEL_ALIAS_CONFIG_SECTIONS {
let original = format!("{section}:\n - name: provider\n models: [{{name: model-a}}, {{name: model-b, alias: keep}}]\n");
let source =
resolved_alias_sources(&original, &[], &test_agent_models(&["model-a"]), false)
.unwrap()
.into_iter()
.find(|source| source.source.model == "model-a")
.unwrap();
let created = add_model_alias_to_yaml(&original, &source, "plain", "", false).unwrap();
assert!(thinking_aliases_from_yaml(&created)
.unwrap()
.iter()
.any(|entry| entry.alias == "plain" && entry.effort.is_none()));
let deleted = remove_thinking_alias_from_yaml(&created, "plain").unwrap();
assert_eq!(json(&deleted), json(&original), "{section}");
}
}
#[test]
fn api_alias_can_be_deleted_after_editing_away_all_options() {
for section in MODEL_ALIAS_CONFIG_SECTIONS {
let original = format!("{section}:\n - name: provider\n models: [{{name: model-a}}]\n");
let source =
resolved_alias_sources(&original, &[], &test_agent_models(&["model-a"]), false)
.unwrap()
.remove(0);
let created = add_model_alias_to_yaml(
&original,
&source,
"editable",
"high",
alias_source_supports_fast(&source),
)
.unwrap();
let edit_source = resolve_model_alias_edit_source(&created, "editable", &[]).unwrap();
let edited =
edit_model_alias_in_yaml(&created, "editable", &edit_source, "editable", "", false)
.unwrap();
let context = model_alias_edit_context(&edited, "editable", &[]).unwrap();
assert_eq!(context.effort, None);
assert!(!context.fast);
let deleted = remove_thinking_alias_from_yaml(&edited, "editable").unwrap();
assert_eq!(json(&deleted), json(&original), "{section}");
}
}
#[test]
fn plain_alias_deletion_preserves_real_models_with_the_same_name() {
let original = "openai-compatibility:\n - name: provider\n models: [plain, {name: plain}, {name: plain, alias: plain}, {name: model-a, alias: plain}]\n";
let deleted = remove_thinking_alias_from_yaml(original, "plain").unwrap();
assert_eq!(
json(&deleted)["openai-compatibility"][0]["models"],
serde_json::json!(["plain", {"name": "plain"}, {"name": "plain", "alias": "plain"}])
);
assert!(remove_thinking_alias_from_yaml(&deleted, "plain").is_err());
}