ACP Wrap up

This commit is contained in:
2026-08-05 08:10:41 -05:00
parent 2015498831
commit 993abb96df
23 changed files with 1459 additions and 1194 deletions
+281
View File
@@ -155,6 +155,62 @@ fn openai_model(model_id: &str) -> OpenAIModelConfig {
}
}
fn acp_select_option(
id: &str,
category: &str,
current_value: &str,
values: &[(&str, &str)],
) -> AcpConfigOptionSettings {
AcpConfigOptionSettings {
id: id.to_owned(),
name: id.to_owned(),
description: None,
category: Some(category.to_owned()),
kind: "select".to_owned(),
current_value: serde_json::json!(current_value),
options: values
.iter()
.map(|(value, name)| AcpConfigValueSettings {
value: serde_json::json!(value),
name: (*name).to_owned(),
description: None,
})
.collect(),
}
}
fn acp_agent(
id: &str,
name: &str,
config_options: Vec<AcpConfigOptionSettings>,
) -> AcpAgentSettings {
AcpAgentSettings {
id: id.to_owned(),
name: name.to_owned(),
version: None,
description: None,
icon_url: None,
capabilities: Vec::new(),
config_options,
discovery_timestamp: None,
discovery_source: None,
discovery_error: None,
}
}
fn empty_preferences() -> LLMPreferences {
LLMPreferences {
models_by_feature: ModelsByFeature::default(),
last_update: None,
base_llm_for_terminal_view: HashMap::new(),
custom_llms: Vec::new(),
custom_model_routers: Vec::new(),
openai_provider_routing: HashMap::new(),
fetched_openai_models: Vec::new(),
acp_selections: HashMap::new(),
}
}
#[test]
fn provider_discovery_preserves_local_model_overrides() {
let mut existing = openai_model("codex-gpt-5.6-sol-xhigh");
@@ -275,6 +331,231 @@ fn acp_models_are_injected_only_while_acp_is_enabled() {
});
}
#[test]
fn acp_is_selectable_before_protocol_model_discovery_completes() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
AISettings::handle(&app).update(&mut app, |settings, ctx| {
settings
.acp_enabled
.set_value(true, ctx)
.expect("ACP setting should update");
settings
.acp_agent_id
.set_value("opencode".to_owned(), ctx)
.expect("ACP agent should update");
settings
.bedrock_enabled
.set_value(false, ctx)
.expect("Bedrock setting should update");
settings
.acp_agents
.set_value(Vec::new(), ctx)
.expect("ACP discovery cache should update");
});
let mut preferences = empty_preferences();
app.read(|ctx| {
preferences.inject_bedrock_models(ctx);
preferences.inject_acp_models(ctx);
});
let models = &preferences.models_by_feature.agent_mode.choices;
assert_eq!(models.len(), 1);
assert_eq!(models[0].display_name, "OpenCode");
assert_eq!(models[0].provider, LLMProvider::Acp);
assert_eq!(
preferences
.acp_selections
.get(&models[0].id)
.map(|selection| selection.agent_id.as_str()),
Some("opencode")
);
assert!(preferences.has_any_provider_models());
});
}
#[test]
fn acp_models_expand_reasoning_levels_for_only_the_configured_agent() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
AISettings::handle(&app).update(&mut app, |settings, ctx| {
settings
.acp_enabled
.set_value(true, ctx)
.expect("ACP setting should update");
settings
.acp_agent_id
.set_value("opencode".to_owned(), ctx)
.expect("ACP agent should update");
settings
.bedrock_enabled
.set_value(false, ctx)
.expect("Bedrock setting should update");
settings
.acp_agents
.set_value(
vec![
acp_agent(
"codex",
"Codex",
vec![acp_select_option(
"model",
"model",
"stale-model",
&[("stale-model", "Stale Model")],
)],
),
acp_agent(
"opencode",
"OpenCode",
vec![
acp_select_option(
"model",
"model",
"gpt-test",
&[("gpt-test", "GPT Test")],
),
acp_select_option(
"mode",
"mode",
"read-only",
&[("read-only", "Read-only")],
),
acp_select_option(
"thought_level",
"thought_level",
"xhigh",
&[("high", "High"), ("xhigh", "Xhigh")],
),
],
),
],
ctx,
)
.expect("ACP agents should update");
});
let mut preferences = empty_preferences();
app.read(|ctx| {
preferences.inject_bedrock_models(ctx);
preferences.inject_acp_models(ctx);
});
let models = &preferences.models_by_feature.agent_mode.choices;
assert_eq!(models.len(), 2);
assert_eq!(
models
.iter()
.map(|model| model.display_name.as_str())
.collect::<HashSet<_>>(),
HashSet::from(["GPT Test (High)", "GPT Test (Xhigh)"])
);
assert!(models.iter().all(|model| {
model.provider == LLMProvider::Acp && !model.display_name.contains("Read-only")
}));
assert!(preferences.acp_selections.values().all(|selection| {
selection.agent_id == "opencode"
&& selection.config_values.get("mode") == Some(&serde_json::json!("read-only"))
}));
});
}
#[test]
fn acp_bedrock_models_are_hidden_while_bedrock_is_disabled() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
AISettings::handle(&app).update(&mut app, |settings, ctx| {
settings
.acp_enabled
.set_value(true, ctx)
.expect("ACP setting should update");
settings
.acp_agent_id
.set_value("opencode".to_owned(), ctx)
.expect("ACP agent should update");
settings
.bedrock_enabled
.set_value(false, ctx)
.expect("Bedrock setting should update");
settings
.acp_agents
.set_value(
vec![acp_agent(
"opencode",
"OpenCode",
vec![acp_select_option(
"model",
"model",
"openai/gpt-test",
&[
("amazon-bedrock/claude-test", "Bedrock Claude"),
("openai/gpt-test", "GPT Test"),
],
)],
)],
ctx,
)
.expect("ACP agents should update");
});
let mut preferences = empty_preferences();
app.read(|ctx| {
preferences.inject_bedrock_models(ctx);
preferences.inject_acp_models(ctx);
});
assert_eq!(preferences.models_by_feature.agent_mode.choices.len(), 1);
assert_eq!(
preferences.models_by_feature.agent_mode.choices[0].display_name,
"GPT Test"
);
AISettings::handle(&app).update(&mut app, |settings, ctx| {
settings
.bedrock_enabled
.set_value(true, ctx)
.expect("Bedrock setting should update");
});
app.read(|ctx| preferences.inject_acp_models(ctx));
assert_eq!(preferences.models_by_feature.agent_mode.choices.len(), 2);
});
}
#[test]
fn disabled_providers_do_not_leave_models_in_the_runtime_inventory() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
AISettings::handle(&app).update(&mut app, |settings, ctx| {
settings
.bedrock_enabled
.set_value(false, ctx)
.expect("Bedrock setting should update");
settings
.openai_enabled
.set_value(false, ctx)
.expect("OpenAI setting should update");
settings
.acp_enabled
.set_value(false, ctx)
.expect("ACP setting should update");
});
let mut preferences = empty_preferences();
app.read(|ctx| {
preferences.inject_bedrock_models(ctx);
preferences.inject_openai_models(ctx);
});
assert!(preferences.models_by_feature.agent_mode.choices.is_empty());
assert!(preferences.models_by_feature.coding.choices.is_empty());
assert!(preferences
.models_by_feature
.cli_agent
.as_ref()
.is_none_or(|models| models.choices.is_empty()));
});
}
#[test]
fn provider_discovery_enables_rig_for_new_models_and_keeps_manual_models() {
let manual = openai_model("manual-model");