fix(acp): allow custom model as default for non-local providers (#10438)

This commit is contained in:
Zane Wang
2026-07-17 21:40:38 -07:00
committed by GitHub
parent f43870951f
commit 445da5dcdf
2 changed files with 57 additions and 8 deletions
+16 -8
View File
@@ -214,14 +214,22 @@ impl GooseAcpAgent {
.data(format!("Provider is not configured: {provider_id}")));
}
if let Some(model_id) = model_id.as_deref() {
let model_exists = entry.default_model == model_id
|| entry.models.iter().any(|model| model.id == model_id)
|| (provider_id == "local" && local_inference_model_exists(model_id)?);
if !model_exists {
return Err(agent_client_protocol::Error::invalid_params().data(format!(
"Model '{model_id}' is not available for provider '{provider_id}'"
)));
// Custom/unlisted model entry is always allowed (#7255), matching the CLI
// and in-session model-selection paths, so a model that is simply absent
// from the provider's (often non-exhaustive) inventory must still be
// accepted as the default here. Local inference is the exception: its
// models cannot be fetched on demand, so they are validated against the
// inventory or the on-disk registry.
if provider_id == "local" {
if let Some(model_id) = model_id.as_deref() {
let model_exists = entry.default_model == model_id
|| entry.models.iter().any(|model| model.id == model_id)
|| local_inference_model_exists(model_id)?;
if !model_exists {
return Err(agent_client_protocol::Error::invalid_params().data(format!(
"Model '{model_id}' is not available for provider '{provider_id}'"
)));
}
}
}
@@ -901,6 +901,47 @@ fn test_custom_defaults_read() {
});
}
// Regression test for #10401: a custom model that is not present in a provider's
// (non-exhaustive) inventory must still be accepted when saved as the default from
// a brand-new chat, matching the CLI and in-session model-selection paths where
// custom/unlisted model entry is always allowed (#7255).
#[test]
#[serial]
fn test_custom_defaults_save_allows_unlisted_model() {
let _env = env_lock::lock_env([("ANTHROPIC_API_KEY", Some("test-key"))]);
let config_dir = write_acp_global_config(
"GOOSE_MODEL: claude-3-5-haiku-latest\nGOOSE_PROVIDER: anthropic\n",
);
run_test(async move {
let openai = OpenAiFixture::new(vec![], Arc::new(EnforceSessionId::default())).await;
let config = TestConnectionConfig {
data_root: config_dir,
..Default::default()
};
let conn = AcpServerConnection::new(config, openai).await;
let response = send_custom(
conn.cx(),
"_goose/unstable/defaults/save",
serde_json::json!({
"providerId": "anthropic",
"modelId": "custom-unlisted-model",
}),
)
.await
.expect("saving an unlisted custom model as the default should succeed");
assert_eq!(
response,
serde_json::json!({
"providerId": "anthropic",
"modelId": "custom-unlisted-model",
})
);
});
}
#[test]
#[serial]
fn test_custom_dictation_secret_save_delete() {