mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-13 07:38:28 +08:00
fix(pricing): seed Claude Fable 5.1 / Mythos 5.1 and restore Sonnet 5 to the $2/$10 standard price (#7051)
- Add claude-fable-5-1 / claude-mythos-5-1 pricing rows ($10/$50, cache read $0.25 = 0.025x, cache write $12.50). Without a row these requests were stored at $0: the prefix rule only looks for longer dated ids and cannot fall back to claude-fable-5. - Sonnet 5: Anthropic's pricing page now states the $2/$10 introductory price is the standard price and the September 1 increase to $3/$15 will not occur. Update the seed and add a repair_current_model_pricing guard so installs seeded at 3/15/0.30/3.75 are corrected; user-customized rows are left alone. - Tests: seed values for the three rows; the repair guard fixes the old list price and keeps a custom price. Fixes #7050
This commit is contained in:
@@ -1604,6 +1604,24 @@ impl Database {
|
||||
/// 注意: model_id 使用短横线格式(如 claude-haiku-4-5),与 API 返回的模型名称标准化后一致
|
||||
fn seed_model_pricing(conn: &Connection) -> Result<(), AppError> {
|
||||
let pricing_data = [
|
||||
// Claude Fable 5.1 / Mythos 5.1(2026-09-01 发布;同 Fable 5 价,
|
||||
// 但缓存读为 0.025x = $0.25,非 Fable 5 的 $1)
|
||||
(
|
||||
"claude-fable-5-1",
|
||||
"Claude Fable 5.1",
|
||||
"10",
|
||||
"50",
|
||||
"0.25",
|
||||
"12.50",
|
||||
),
|
||||
(
|
||||
"claude-mythos-5-1",
|
||||
"Claude Mythos 5.1",
|
||||
"10",
|
||||
"50",
|
||||
"0.25",
|
||||
"12.50",
|
||||
),
|
||||
// Claude Fable 5(Opus 之上的新档)
|
||||
(
|
||||
"claude-fable-5",
|
||||
@@ -1632,14 +1650,15 @@ impl Database {
|
||||
"0.50",
|
||||
"6.25",
|
||||
),
|
||||
// Claude Sonnet 5(list 价,与 Sonnet 4.6 一致;促销 $2/$10 至 2026-08-31 不入表)
|
||||
// Claude Sonnet 5(官方定价页 2026-09 确认:$2/$10 介绍价转为正式价,
|
||||
// 原定 09-01 涨至 $3/$15 取消)
|
||||
(
|
||||
"claude-sonnet-5",
|
||||
"Claude Sonnet 5",
|
||||
"3",
|
||||
"15",
|
||||
"0.30",
|
||||
"3.75",
|
||||
"2",
|
||||
"10",
|
||||
"0.20",
|
||||
"2.50",
|
||||
),
|
||||
// Claude 4.7 系列
|
||||
(
|
||||
@@ -2597,6 +2616,20 @@ impl Database {
|
||||
|
||||
fn repair_current_model_pricing(conn: &Connection) -> Result<(), AppError> {
|
||||
let pricing_fixes = [
|
||||
// 2026-09-02 官方定价页确认 Sonnet 5 $2/$10 介绍价转为正式价、原定 09-01 涨至
|
||||
// $3/$15 取消:早先按 list 价 seed 的行改回正式价(用户手改过的行不匹配旧值,不动)
|
||||
(
|
||||
"claude-sonnet-5",
|
||||
"Claude Sonnet 5",
|
||||
"2",
|
||||
"10",
|
||||
"0.20",
|
||||
"2.50",
|
||||
"3",
|
||||
"15",
|
||||
"0.30",
|
||||
"3.75",
|
||||
),
|
||||
// 2026-08-13 models.dev 审计核价:grok-4.5 的 cached input 官方挂牌为 0.30
|
||||
// (docs.x.ai 现行价表),与 grok-4.5-build 的实测计费一致;早先按 0.50
|
||||
// 录入的行在此校正。注意 0.50 是 grok-4.6 的 cached 价,勿两者互串
|
||||
|
||||
@@ -892,6 +892,135 @@ fn model_pricing_seed_repairs_known_outdated_builtin_prices() {
|
||||
assert_eq!(glm, ("9".to_string(), "9".to_string(), "9".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_pricing_seed_includes_claude_5_1_and_standard_sonnet_5_prices() {
|
||||
let db = Database::memory().expect("create memory db");
|
||||
let conn = db.conn.lock().expect("lock conn");
|
||||
|
||||
for model_id in ["claude-fable-5-1", "claude-mythos-5-1"] {
|
||||
let price: (String, String, String, String) = conn
|
||||
.query_row(
|
||||
"SELECT input_cost_per_million, output_cost_per_million,
|
||||
cache_read_cost_per_million, cache_creation_cost_per_million
|
||||
FROM model_pricing WHERE model_id = ?1",
|
||||
[model_id],
|
||||
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
|
||||
)
|
||||
.expect("query Fable 5.1 family price");
|
||||
// 缓存读 0.025x = $0.25,不是 Fable 5 的 $1
|
||||
assert_eq!(
|
||||
price,
|
||||
(
|
||||
"10".to_string(),
|
||||
"50".to_string(),
|
||||
"0.25".to_string(),
|
||||
"12.50".to_string(),
|
||||
),
|
||||
"{model_id}"
|
||||
);
|
||||
}
|
||||
|
||||
let sonnet: (String, String, String, String) = conn
|
||||
.query_row(
|
||||
"SELECT input_cost_per_million, output_cost_per_million,
|
||||
cache_read_cost_per_million, cache_creation_cost_per_million
|
||||
FROM model_pricing WHERE model_id = 'claude-sonnet-5'",
|
||||
[],
|
||||
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
|
||||
)
|
||||
.expect("query Sonnet 5 price");
|
||||
// $2/$10 介绍价已转为正式价(原定 2026-09-01 涨至 $3/$15 取消)
|
||||
assert_eq!(
|
||||
sonnet,
|
||||
(
|
||||
"2".to_string(),
|
||||
"10".to_string(),
|
||||
"0.20".to_string(),
|
||||
"2.50".to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_pricing_seed_repairs_sonnet_5_list_price_but_keeps_custom_price() {
|
||||
let db = Database::memory().expect("create memory db");
|
||||
|
||||
{
|
||||
let conn = db.conn.lock().expect("lock conn");
|
||||
// 旧 seed 按 list 价录入的行 → 应被修正
|
||||
conn.execute(
|
||||
"UPDATE model_pricing
|
||||
SET input_cost_per_million = '3',
|
||||
output_cost_per_million = '15',
|
||||
cache_read_cost_per_million = '0.30',
|
||||
cache_creation_cost_per_million = '3.75'
|
||||
WHERE model_id = 'claude-sonnet-5'",
|
||||
[],
|
||||
)
|
||||
.expect("restore old Sonnet 5 list price");
|
||||
}
|
||||
|
||||
db.ensure_model_pricing_seeded()
|
||||
.expect("ensure pricing seeded");
|
||||
|
||||
{
|
||||
let conn = db.conn.lock().expect("lock conn");
|
||||
let sonnet: (String, String, String, String) = conn
|
||||
.query_row(
|
||||
"SELECT input_cost_per_million, output_cost_per_million,
|
||||
cache_read_cost_per_million, cache_creation_cost_per_million
|
||||
FROM model_pricing WHERE model_id = 'claude-sonnet-5'",
|
||||
[],
|
||||
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
|
||||
)
|
||||
.expect("query repaired Sonnet 5 price");
|
||||
assert_eq!(
|
||||
sonnet,
|
||||
(
|
||||
"2".to_string(),
|
||||
"10".to_string(),
|
||||
"0.20".to_string(),
|
||||
"2.50".to_string(),
|
||||
)
|
||||
);
|
||||
|
||||
// 用户手改过的价(不匹配旧 seed 值)不动
|
||||
conn.execute(
|
||||
"UPDATE model_pricing
|
||||
SET input_cost_per_million = '9',
|
||||
output_cost_per_million = '9',
|
||||
cache_read_cost_per_million = '9',
|
||||
cache_creation_cost_per_million = '9'
|
||||
WHERE model_id = 'claude-sonnet-5'",
|
||||
[],
|
||||
)
|
||||
.expect("set custom Sonnet 5 price");
|
||||
}
|
||||
|
||||
db.ensure_model_pricing_seeded()
|
||||
.expect("ensure pricing seeded again");
|
||||
|
||||
let conn = db.conn.lock().expect("lock conn");
|
||||
let custom: (String, String, String, String) = conn
|
||||
.query_row(
|
||||
"SELECT input_cost_per_million, output_cost_per_million,
|
||||
cache_read_cost_per_million, cache_creation_cost_per_million
|
||||
FROM model_pricing WHERE model_id = 'claude-sonnet-5'",
|
||||
[],
|
||||
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
|
||||
)
|
||||
.expect("query custom Sonnet 5 price");
|
||||
assert_eq!(
|
||||
custom,
|
||||
(
|
||||
"9".to_string(),
|
||||
"9".to_string(),
|
||||
"9".to_string(),
|
||||
"9".to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ensure_incremental_auto_vacuum_rebuilds_existing_file_db() {
|
||||
let temp = NamedTempFile::new().expect("create temp db file");
|
||||
|
||||
Reference in New Issue
Block a user