mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
Add Kimi K3 via OpenRouter
This commit is contained in:
parent
03b1b790d1
commit
129c893c86
3 changed files with 132 additions and 1 deletions
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use fabro_auth::ApiCredential;
|
||||
use fabro_llm::client::Client;
|
||||
use fabro_llm::error::ProviderErrorKind;
|
||||
use fabro_llm::model_test::{ModelTestStatus, run_model_test};
|
||||
use fabro_llm::provider::ProviderAdapter;
|
||||
use fabro_llm::providers::{
|
||||
AnthropicAdapter, BedrockAdapter, GeminiAdapter, OpenAiAdapter, OpenAiCompatibleAdapter,
|
||||
|
|
@ -13,7 +16,8 @@ use fabro_llm::providers::{
|
|||
use fabro_llm::types::{
|
||||
CostSource, FinishReason, Message, ReasoningEffort, Request, ToolChoice, ToolDefinition,
|
||||
};
|
||||
use fabro_model::Catalog;
|
||||
use fabro_model::catalog::{LlmCatalogSettings, ProviderCatalogSettings};
|
||||
use fabro_model::{Catalog, ModelTestMode, ProviderId};
|
||||
use fabro_static::EnvVars;
|
||||
|
||||
fn make_request(model: &str) -> Request {
|
||||
|
|
@ -332,6 +336,42 @@ async fn openrouter_complete() {
|
|||
assert_eq!(response.cost_source, Some(CostSource::Authoritative));
|
||||
}
|
||||
|
||||
#[fabro_macros::e2e_test(live("OPENROUTER_API_KEY"))]
|
||||
async fn openrouter_kimi_k3_deep_tool_round_trip() {
|
||||
let api_key =
|
||||
std::env::var(EnvVars::OPENROUTER_API_KEY).expect("OPENROUTER_API_KEY must be set");
|
||||
let provider = ProviderId::new("openrouter");
|
||||
let mut settings = LlmCatalogSettings::default();
|
||||
settings
|
||||
.providers
|
||||
.insert(provider.to_string(), ProviderCatalogSettings {
|
||||
enabled: Some(true),
|
||||
..ProviderCatalogSettings::default()
|
||||
});
|
||||
let catalog = Arc::new(
|
||||
Catalog::from_builtin_with_overrides(&settings)
|
||||
.expect("enabled OpenRouter catalog should build"),
|
||||
);
|
||||
let credential = ApiCredential::from_api_key(provider, api_key, &catalog)
|
||||
.expect("OpenRouter credential should resolve from the catalog");
|
||||
let client = Arc::new(
|
||||
Client::from_credentials(vec![credential], Arc::clone(&catalog))
|
||||
.await
|
||||
.expect("OpenRouter client should build from the catalog"),
|
||||
);
|
||||
let model = catalog
|
||||
.get("moonshotai/kimi-k3")
|
||||
.expect("OpenRouter Kimi K3 should be present");
|
||||
|
||||
let outcome = run_model_test(model, ModelTestMode::Deep, client).await;
|
||||
assert_eq!(
|
||||
outcome.status,
|
||||
ModelTestStatus::Ok,
|
||||
"OpenRouter Kimi K3 deep test failed: {:?}",
|
||||
outcome.error_message
|
||||
);
|
||||
}
|
||||
|
||||
async fn run_multi_turn_cache_test(
|
||||
adapter: &dyn ProviderAdapter,
|
||||
model: &str,
|
||||
|
|
|
|||
|
|
@ -2056,6 +2056,71 @@ enabled = true
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_openrouter_includes_kimi_k3_when_enabled() {
|
||||
let catalog = Catalog::from_builtin_with_overrides(&minimal_settings(
|
||||
r"
|
||||
[providers.openrouter]
|
||||
enabled = true
|
||||
",
|
||||
))
|
||||
.expect("enabled OpenRouter override should build from the built-in provider settings");
|
||||
|
||||
let model = catalog
|
||||
.get("moonshotai/kimi-k3")
|
||||
.expect("OpenRouter Kimi K3 should be present");
|
||||
insta::assert_debug_snapshot!(model, @r#"
|
||||
Model {
|
||||
id: "moonshotai/kimi-k3",
|
||||
provider: openrouter,
|
||||
family: "kimi-k3",
|
||||
display_name: "Kimi K3 (via OpenRouter)",
|
||||
limits: ModelLimits {
|
||||
context_window: 1048576,
|
||||
max_output: Some(
|
||||
131072,
|
||||
),
|
||||
},
|
||||
training: None,
|
||||
knowledge_cutoff: None,
|
||||
features: ModelFeatures {
|
||||
tools: true,
|
||||
vision: true,
|
||||
reasoning: true,
|
||||
reasoning_effort: AlwaysAdaptive,
|
||||
prompt_cache: true,
|
||||
sampling_params: false,
|
||||
},
|
||||
costs: ModelCosts {
|
||||
input_cost_per_mtok: Some(
|
||||
3.0,
|
||||
),
|
||||
output_cost_per_mtok: Some(
|
||||
15.0,
|
||||
),
|
||||
cache_input_cost_per_mtok: Some(
|
||||
0.3,
|
||||
),
|
||||
},
|
||||
estimated_output_tps: None,
|
||||
aliases: [],
|
||||
default: false,
|
||||
small_default: false,
|
||||
configured: false,
|
||||
}
|
||||
"#);
|
||||
|
||||
let settings = catalog
|
||||
.model_settings("moonshotai/kimi-k3")
|
||||
.expect("OpenRouter Kimi K3 settings should be present");
|
||||
assert_eq!(settings.api_id, "moonshotai/kimi-k3");
|
||||
assert_eq!(settings.controls.reasoning_effort, vec![
|
||||
ReasoningEffort::Low,
|
||||
ReasoningEffort::High,
|
||||
ReasoningEffort::Max,
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_ollama_provider_is_opt_in() {
|
||||
let ollama = ProviderId::new("ollama");
|
||||
|
|
|
|||
|
|
@ -278,6 +278,32 @@ reasoning = false
|
|||
input_cost_per_mtok = 0.73
|
||||
output_cost_per_mtok = 3.49
|
||||
|
||||
[models."moonshotai/kimi-k3"]
|
||||
provider = "openrouter"
|
||||
api_id = "moonshotai/kimi-k3"
|
||||
display_name = "Kimi K3 (via OpenRouter)"
|
||||
family = "kimi-k3"
|
||||
|
||||
[models."moonshotai/kimi-k3".limits]
|
||||
context_window = 1048576
|
||||
max_output = 131072
|
||||
|
||||
[models."moonshotai/kimi-k3".features]
|
||||
tools = true
|
||||
vision = true
|
||||
reasoning = true
|
||||
reasoning_effort = "always_adaptive"
|
||||
prompt_cache = true
|
||||
sampling_params = false
|
||||
|
||||
[models."moonshotai/kimi-k3".controls]
|
||||
reasoning_effort = ["low", "high", "max"]
|
||||
|
||||
[models."moonshotai/kimi-k3".costs]
|
||||
input_cost_per_mtok = 3.0
|
||||
output_cost_per_mtok = 15.0
|
||||
cache_input_cost_per_mtok = 0.3
|
||||
|
||||
[models."qwen/qwen3-coder"]
|
||||
provider = "openrouter"
|
||||
api_id = "qwen/qwen3-coder"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue