use super::{budget_model, model_for_task_budget, model_on_budget_preference, models_for_agent};
use crate::types::{AgentKind, TaskBudget};
#[test]
fn grok_budget_selection_is_a_monotonic_golden_table() {
let expected = [
(TaskBudget::Free, "grok-4.6"),
(TaskBudget::Cheap, "grok-4.6"),
(TaskBudget::Standard, "grok-4.6"),
(TaskBudget::Premium, "grok-4.6"),
];
for (budget, model) in expected {
assert_eq!(model_for_task_budget(AgentKind::Grok, budget), Some(model));
}
}
#[test]
fn budget_model_agrees_with_task_budget_cheap() {
assert_eq!(
budget_model(&AgentKind::Grok),
model_for_task_budget(AgentKind::Grok, TaskBudget::Cheap)
);
assert_eq!(
budget_model(&AgentKind::Codex),
model_for_task_budget(AgentKind::Codex, TaskBudget::Cheap)
);
assert_eq!(
budget_model(&AgentKind::Claude),
model_for_task_budget(AgentKind::Claude, TaskBudget::Cheap)
);
}
#[test]
fn models_for_agent_merges_cached_agy_model_as_unknown() {
let temp = tempfile::tempdir().expect("tempdir");
let _home = crate::paths::AidHomeGuard::set(temp.path());
crate::paths::ensure_dirs().expect("aid dirs");
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("current time")
.as_secs();
let cache = serde_json::json!({
"agy": {"models": ["gemini-3.7-flash-high"], "updated_at_secs": now}
});
std::fs::write(
crate::paths::aid_dir().join("served_models_cache.json"),
cache.to_string(),
)
.expect("served-model cache");
let models = models_for_agent(&AgentKind::Antigravity);
let discovered = models.iter()
.find(|model| model.model == "gemini-3.7-flash-high")
.expect("discovered model");
assert_eq!(discovered.input_per_m, None);
assert_eq!(discovered.output_per_m, None);
assert_eq!(discovered.capability, None);
}
#[test]
fn models_for_agent_merges_cached_opencode_model_as_unknown() {
let temp = tempfile::tempdir().expect("tempdir");
let _home = crate::paths::AidHomeGuard::set(temp.path());
crate::paths::ensure_dirs().expect("aid dirs");
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("current time")
.as_secs();
let cache = serde_json::json!({
"opencode": {"models": ["opencode-go/glm-5.2"], "updated_at_secs": now}
});
std::fs::write(
crate::paths::aid_dir().join("served_models_cache.json"),
cache.to_string(),
)
.expect("served-model cache");
let models = models_for_agent(&AgentKind::OpenCode);
let discovered = models
.iter()
.find(|model| model.model == "opencode-go/glm-5.2")
.expect("discovered model");
assert_eq!(discovered.input_per_m, None);
assert_eq!(discovered.output_per_m, None);
assert_eq!(discovered.capability, None);
}
#[test]
fn agent_list_json_marks_discovered_opencode_metadata_unknown() {
let temp = tempfile::tempdir().expect("tempdir");
let _home = crate::paths::AidHomeGuard::set(temp.path());
crate::paths::ensure_dirs().expect("aid dirs");
crate::agent::model_validation::clear_served_models_cache();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("current time")
.as_secs();
let cache = serde_json::json!({
"opencode": {"models": ["opencode-go/glm-5.2"], "updated_at_secs": now}
});
std::fs::write(
crate::paths::aid_dir().join("served_models_cache.json"),
cache.to_string(),
)
.expect("served-model cache");
let store = crate::store::Store::open_memory().expect("store");
let list = crate::cmd::agent_json::agents_list_value(&store).expect("agent list");
let agents = list["agents"].as_array().expect("agents");
let opencode = agents
.iter()
.find(|agent| agent["name"] == "opencode")
.expect("opencode");
let model = opencode["models"]["available"]
.as_array()
.expect("available")
.iter()
.find(|model| model["model"] == "opencode-go/glm-5.2")
.expect("discovered model");
assert!(model["input_per_m"].is_null());
assert!(model["output_per_m"].is_null());
assert!(model["capability"].is_null());
}
#[test]
fn budget_preferred_tiers_beat_unknown() {
let model = model_for_task_budget(AgentKind::Cursor, TaskBudget::Cheap)
.expect("cursor has a cheap model");
assert!(model_on_budget_preference(
AgentKind::Cursor,
TaskBudget::Cheap,
model
));
}
#[test]
fn unknown_model_is_not_on_budget_cheap_preference() {
assert!(!model_on_budget_preference(
AgentKind::Grok,
TaskBudget::Cheap,
"grok-4.5"
));
}
#[test]
fn budget_cheap_picks_lowest_price_within_tier() {
assert_eq!(
model_for_task_budget(AgentKind::Gemini, TaskBudget::Cheap),
Some("flash-lite")
);
assert_eq!(
budget_model(&AgentKind::Gemini),
Some("flash-lite")
);
}
#[test]
fn budget_cheap_picks_lowest_price_across_preferred_tiers() {
assert_eq!(
model_for_task_budget(AgentKind::OpenCode, TaskBudget::Cheap),
Some("opencode/deepseek-v4-flash-free")
);
assert_eq!(
budget_model(&AgentKind::OpenCode),
Some("opencode/deepseek-v4-flash-free")
);
}