fix(model): prefer MOONSHOT_API_KEY

Keep KIMI_API_KEY as a legacy fallback for env and vault credentials.
This commit is contained in:
Bryan Helmkamp 2026-07-31 09:14:58 -04:00
parent 24f9ac6bd1
commit fd55ff03ad
No known key found for this signature in database
10 changed files with 104 additions and 6 deletions

View file

@ -4,7 +4,7 @@ DAYTONA_API_KEY=
FIREWORKS_API_KEY=
GEMINI_API_KEY=
INCEPTION_API_KEY=
KIMI_API_KEY=
MOONSHOT_API_KEY=
MINIMAX_API_KEY=
MODAL_KIMI_K3_BASE_URL=
MODAL_TOKEN_ID=

View file

@ -383,7 +383,7 @@ fabro secret set GEMINI_API_KEY AI...
| `ANTHROPIC_API_KEY` | Anthropic (Claude) |
| `OPENAI_API_KEY` | OpenAI (GPT) |
| `GEMINI_API_KEY` | Google (Gemini) |
| `KIMI_API_KEY` | Moonshot AI |
| `MOONSHOT_API_KEY` or `KIMI_API_KEY` | Moonshot AI; `MOONSHOT_API_KEY` takes precedence |
| `ZAI_API_KEY` | Zai (GLM) |
| `MINIMAX_API_KEY` | Minimax |
| `INCEPTION_API_KEY` | Inception (Mercury) |

View file

@ -366,7 +366,7 @@ For env-backed usage, `EnvCredentialSource` checks for API key environment varia
| `ANTHROPIC_API_KEY` | Anthropic |
| `OPENAI_API_KEY` | OpenAI |
| `GEMINI_API_KEY` or `GOOGLE_API_KEY` | Gemini |
| `KIMI_API_KEY` | Moonshot AI |
| `MOONSHOT_API_KEY` or `KIMI_API_KEY` | Moonshot AI; `MOONSHOT_API_KEY` takes precedence |
| `ZAI_API_KEY` | ZAI |
| `MINIMAX_API_KEY` | Minimax |
| `INCEPTION_API_KEY` | Inception |

View file

@ -18,6 +18,7 @@ fn remove_provider_env(cmd: &mut Command) -> &mut Command {
.env_remove("OPENAI_API_KEY")
.env_remove("GEMINI_API_KEY")
.env_remove("GOOGLE_API_KEY")
.env_remove("MOONSHOT_API_KEY")
.env_remove("KIMI_API_KEY")
.env_remove("ZAI_API_KEY")
.env_remove("MINIMAX_API_KEY")

View file

@ -630,6 +630,60 @@ base_url = "https://example--kimi-k3.modal.run/v1"
);
}
#[tokio::test]
async fn resolve_moonshot_api_request_prefers_moonshot_env_key() {
let dir = tempfile::tempdir().unwrap();
let vault = Vault::load(dir.path().join("secrets.json")).unwrap();
let resolver = test_resolver(
vault,
Arc::new(|name| match name {
EnvVars::MOONSHOT_API_KEY => Some("moonshot-key".to_string()),
EnvVars::KIMI_API_KEY => Some("kimi-key".to_string()),
_ => None,
}),
);
let resolved = resolver
.resolve(
ProviderId::new("moonshot"),
CredentialUsage::ApiRequest,
&default_catalog(),
)
.await
.unwrap();
let ResolvedCredential::Api(api) = resolved;
assert_eq!(
api.auth_header,
Some(ApiKeyHeader::Bearer("moonshot-key".to_string()))
);
}
#[tokio::test]
async fn resolve_moonshot_api_request_falls_back_to_kimi_env_key() {
let dir = tempfile::tempdir().unwrap();
let vault = Vault::load(dir.path().join("secrets.json")).unwrap();
let resolver = test_resolver(
vault,
Arc::new(|name| (name == EnvVars::KIMI_API_KEY).then(|| "kimi-key".to_string())),
);
let resolved = resolver
.resolve(
ProviderId::new("moonshot"),
CredentialUsage::ApiRequest,
&default_catalog(),
)
.await
.unwrap();
let ResolvedCredential::Api(api) = resolved;
assert_eq!(
api.auth_header,
Some(ApiKeyHeader::Bearer("kimi-key".to_string()))
);
}
#[tokio::test]
async fn resolve_openai_api_request_falls_back_to_codex_oauth_credential() {
let dir = tempfile::tempdir().unwrap();

View file

@ -7,11 +7,18 @@
//! display_name = "Moonshot AI"
//! adapter = "openai_compatible"
//! base_url = "https://api.moonshot.ai/v1"
//! auth = { credentials = ["env:KIMI_API_KEY", "vault:KIMI_API_KEY"] }
//! priority = 60
//! enabled = true
//! aliases = ["moonshot-ai"]
//!
//! [llm.providers.moonshot.auth]
//! credentials = [
//! "env:MOONSHOT_API_KEY",
//! "env:KIMI_API_KEY",
//! "vault:MOONSHOT_API_KEY",
//! "vault:KIMI_API_KEY",
//! ]
//!
//! [llm.providers.moonshot.models."kimi-k2.5"]
//! ...
//! ```
@ -499,7 +506,12 @@ enabled = true
aliases = ["moonshot-ai"]
[providers.moonshot.auth]
credentials = ["env:KIMI_API_KEY", "vault:KIMI_API_KEY"]
credentials = [
"env:MOONSHOT_API_KEY",
"env:KIMI_API_KEY",
"vault:MOONSHOT_API_KEY",
"vault:KIMI_API_KEY",
]
"#;
let layer: LlmLayer = toml::from_str(toml).unwrap();
let moonshot = layer.providers.get("moonshot").unwrap();
@ -509,7 +521,9 @@ credentials = ["env:KIMI_API_KEY", "vault:KIMI_API_KEY"]
let auth = moonshot.auth.as_ref().expect("expected api_key auth");
assert_eq!(auth.header, ApiKeyHeaderPolicy::Bearer);
assert_eq!(auth.credentials, vec![
CredentialRef::Env("MOONSHOT_API_KEY".to_string()),
CredentialRef::Env("KIMI_API_KEY".to_string()),
CredentialRef::Vault("MOONSHOT_API_KEY".to_string()),
CredentialRef::Vault("KIMI_API_KEY".to_string()),
]);
assert_eq!(

View file

@ -3694,6 +3694,26 @@ enabled = true
]);
}
#[test]
fn builtin_moonshot_provider_prefers_moonshot_api_key() {
let moonshot = ProviderId::new("moonshot");
let catalog = Catalog::builtin();
let provider = catalog
.provider(&moonshot)
.expect("Moonshot provider should be present");
assert_eq!(provider.auth.as_ref().unwrap().credentials, vec![
CredentialRef::Env("MOONSHOT_API_KEY".to_string()),
CredentialRef::Env("KIMI_API_KEY".to_string()),
CredentialRef::Vault("MOONSHOT_API_KEY".to_string()),
CredentialRef::Vault("KIMI_API_KEY".to_string()),
]);
assert_eq!(
catalog.provider_vault_secret_name(&moonshot),
Some("MOONSHOT_API_KEY")
);
}
#[test]
fn builtin_kimi_k3_selection_prefers_modal_then_moonshot_over_openrouter() {
let moonshot = ProviderId::new("moonshot");

View file

@ -7,7 +7,12 @@ base_url = "https://api.moonshot.ai/v1"
priority = 70
[providers.moonshot.auth]
credentials = ["env:KIMI_API_KEY", "vault:KIMI_API_KEY"]
credentials = [
"env:MOONSHOT_API_KEY",
"env:KIMI_API_KEY",
"vault:MOONSHOT_API_KEY",
"vault:KIMI_API_KEY",
]
[providers.moonshot.models."kimi-k2.5"]
display_name = "Kimi K2.5"

View file

@ -56,6 +56,7 @@ impl EnvVars {
pub const INCEPTION_API_KEY: &'static str = "INCEPTION_API_KEY";
pub const KIMI_API_KEY: &'static str = "KIMI_API_KEY";
pub const MINIMAX_API_KEY: &'static str = "MINIMAX_API_KEY";
pub const MOONSHOT_API_KEY: &'static str = "MOONSHOT_API_KEY";
pub const MODAL_TOKEN_ID: &'static str = "MODAL_TOKEN_ID";
pub const MODAL_TOKEN_SECRET: &'static str = "MODAL_TOKEN_SECRET";
pub const OPENAI_API_KEY: &'static str = "OPENAI_API_KEY";
@ -206,6 +207,7 @@ mod tests {
EnvVars::INCEPTION_API_KEY,
EnvVars::KIMI_API_KEY,
EnvVars::MINIMAX_API_KEY,
EnvVars::MOONSHOT_API_KEY,
EnvVars::OPENAI_API_KEY,
EnvVars::OPENAI_BASE_URL,
EnvVars::OPENAI_ORGANIZATION,

View file

@ -30,6 +30,7 @@ const OPTIONAL_VAULT_SECRETS: &[&str] = &[
EnvVars::INCEPTION_API_KEY,
EnvVars::KIMI_API_KEY,
EnvVars::MINIMAX_API_KEY,
EnvVars::MOONSHOT_API_KEY,
EnvVars::OPENAI_API_KEY,
EnvVars::OPENROUTER_API_KEY,
EnvVars::POOLSIDE_API_KEY,
@ -97,6 +98,7 @@ mod tests {
EnvVars::INCEPTION_API_KEY,
EnvVars::KIMI_API_KEY,
EnvVars::MINIMAX_API_KEY,
EnvVars::MOONSHOT_API_KEY,
EnvVars::OPENAI_API_KEY,
EnvVars::OPENROUTER_API_KEY,
EnvVars::POOLSIDE_API_KEY,