Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
86 lines
2.7 KiB
Rust
86 lines
2.7 KiB
Rust
//! Router cost-based selection test.
|
|
//!
|
|
//! Given (in=10K, out=2K) the cheapest registered provider should be picked.
|
|
//! Costs (cents per MTok in/out):
|
|
//! anthropic = 100 / 500
|
|
//! openai = 15 / 60
|
|
//! kimi = 60 / 250
|
|
//! For (10_000 in, 2_000 out):
|
|
//! anthropic = ceil((100*10_000 + 500*2_000) / 1_000_000) = ceil(2_000_000/1M) = 2c
|
|
//! openai = ceil((15*10_000 + 60*2_000) / 1_000_000) = ceil(270_000/1M) = 1c
|
|
//! kimi = ceil((60*10_000 + 250*2_000) / 1_000_000) = ceil(1_100_000/1M) = 2c
|
|
//! → openai wins.
|
|
|
|
use kei_router::{
|
|
AnthropicProvider, KimiProvider, LlmRouter, OpenAiProvider, Provider,
|
|
};
|
|
|
|
#[test]
|
|
fn picks_openai_for_typical_chat_request() {
|
|
let mut router = LlmRouter::new();
|
|
router.register(Box::new(AnthropicProvider::with_endpoint(
|
|
"a".into(),
|
|
"claude-haiku-4-5".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
router.register(Box::new(OpenAiProvider::with_endpoint(
|
|
"o".into(),
|
|
"gpt-4o-mini".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
router.register(Box::new(KimiProvider::with_endpoint(
|
|
"k".into(),
|
|
"kimi-k2-thinking".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
|
|
let cheapest = router.cheapest_for_estimated_tokens(10_000, 2_000).unwrap();
|
|
assert_eq!(cheapest.name(), "openai");
|
|
}
|
|
|
|
#[test]
|
|
fn picks_anthropic_when_only_one_registered() {
|
|
let mut router = LlmRouter::new();
|
|
router.register(Box::new(AnthropicProvider::with_endpoint(
|
|
"a".into(),
|
|
"claude-haiku-4-5".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
let p = router.cheapest_for_estimated_tokens(1_000_000, 200_000).unwrap();
|
|
assert_eq!(p.name(), "anthropic");
|
|
}
|
|
|
|
#[test]
|
|
fn pick_by_name_returns_correct_provider() {
|
|
let mut router = LlmRouter::new();
|
|
router.register(Box::new(AnthropicProvider::with_endpoint(
|
|
"a".into(),
|
|
"claude-haiku-4-5".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
router.register(Box::new(KimiProvider::with_endpoint(
|
|
"k".into(),
|
|
"kimi-k2-thinking".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
|
|
assert_eq!(router.pick("anthropic").unwrap().name(), "anthropic");
|
|
assert_eq!(router.pick("kimi").unwrap().name(), "kimi");
|
|
assert!(router.pick("unknown").is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn names_returns_sorted_list() {
|
|
let mut router = LlmRouter::new();
|
|
router.register(Box::new(KimiProvider::with_endpoint(
|
|
"k".into(),
|
|
"kimi-k2-thinking".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
router.register(Box::new(AnthropicProvider::with_endpoint(
|
|
"a".into(),
|
|
"claude-haiku-4-5".into(),
|
|
"http://stub".into(),
|
|
)));
|
|
assert_eq!(router.names(), vec!["anthropic", "kimi"]);
|
|
}
|