Update default models and pricing across presets

Bump default model names project-wide: gpt-5.4 -> gpt-5.5,
gemini-3.x -> gemini-3.5-flash, glm-5 -> glm-5.1, and
grok-code-fast-1 -> grok-build-0.1 across all provider presets
(claude, codex, gemini, hermes, openclaw, opencode, universal),
Gemini config, and stream check defaults.

Pricing:
- Seed gemini-3.5-flash, gemini-3.1-flash-lite, step-3.5-flash-2603,
  doubao-seed-2.0-code, mimo-v2.5(/pro), qwen3-coder-480b, grok-build-0.1.
- Correct deepseek-v4-flash/pro, glm-5/5.1, grok pricing.
- Add repair_current_model_pricing: idempotent pass that fixes only
  rows still equal to the outdated built-in values, preserving any
  user-customized prices (seed uses INSERT OR IGNORE and cannot update
  existing rows).

Fixes from review:
- opencode: drop duplicate gemini-3.5-flash variant (unreachable via
  .find), keep the entry with the full minimal/low/medium/high set.
- Align stale display names/costs to gemini-3.5-flash (hermes, openclaw,
  opencode); openclaw cost -> {1.5, 9, 0.15} to match seed.
- i18n (zh/en/ja/zh-TW): refresh OMO category tooltips for new model
  names; fix writing tooltip to Kimi K2.5 to match its recommended.

Update tests accordingly and add a regression test asserting unique
model ids in the Google opencode preset variants.
This commit is contained in:
Jason
2026-05-29 15:54:03 +08:00
parent 2b6ede1431
commit 3a15420770
27 changed files with 477 additions and 256 deletions
+154 -11
View File
@@ -1485,6 +1485,15 @@ impl Database {
("gpt-4.1", "GPT-4.1", "2", "8", "0.50", "0"),
("gpt-4.1-mini", "GPT-4.1 Mini", "0.40", "1.60", "0.10", "0"),
("gpt-4.1-nano", "GPT-4.1 Nano", "0.10", "0.40", "0.025", "0"),
// Gemini 3.5 系列
(
"gemini-3.5-flash",
"Gemini 3.5 Flash",
"1.50",
"9.00",
"0.15",
"0",
),
// Gemini 3.1 系列
(
"gemini-3.1-pro-preview",
@@ -1494,6 +1503,14 @@ impl Database {
"0.20",
"0",
),
(
"gemini-3.1-flash-lite",
"Gemini 3.1 Flash Lite",
"0.25",
"1.50",
"0.025",
"0",
),
(
"gemini-3.1-flash-lite-preview",
"Gemini 3.1 Flash Lite Preview",
@@ -1562,6 +1579,14 @@ impl Database {
"0.02",
"0",
),
(
"step-3.5-flash-2603",
"Step 3.5 Flash 2603",
"0.10",
"0.30",
"0.02",
"0",
),
// ====== 国产模型 (USD/1M tokens) ======
// Doubao (字节跳动)
(
@@ -1588,6 +1613,14 @@ impl Database {
"0",
"0",
),
(
"doubao-seed-2-0-code-preview-latest",
"Doubao Seed 2.0 Code Preview",
"0.47",
"2.37",
"0",
"0",
),
(
"doubao-seed-2-0-lite",
"Doubao Seed 2.0 Lite",
@@ -1644,15 +1677,15 @@ impl Database {
"DeepSeek V4 Flash",
"0.14",
"0.28",
"0.028",
"0.0028",
"0",
),
(
"deepseek-v4-pro",
"DeepSeek V4 Pro",
"1.68",
"3.36",
"0.14",
"0.435",
"0.87",
"0.003625",
"0",
),
// Kimi (月之暗面)
@@ -1714,8 +1747,8 @@ impl Database {
// GLM (智谱)
("glm-4.7", "GLM-4.7", "0.39", "1.75", "0.04", "0"),
("glm-4.6", "GLM-4.6", "0.28", "1.11", "0.03", "0"),
("glm-5", "GLM-5", "0.72", "2.30", "0", "0"),
("glm-5.1", "GLM-5.1", "0.95", "3.15", "0", "0"),
("glm-5", "GLM-5", "1", "3.2", "0.2", "0"),
("glm-5.1", "GLM-5.1", "1.4", "4.4", "0.26", "0"),
// MiMo (小米)
(
"mimo-v2-flash",
@@ -1726,6 +1759,8 @@ impl Database {
"0",
),
("mimo-v2-pro", "MiMo V2 Pro", "1", "3", "0", "0"),
("mimo-v2.5", "MiMo V2.5", "0.09", "0.29", "0.009", "0"),
("mimo-v2.5-pro", "MiMo V2.5 Pro", "1", "3", "0", "0"),
// Qwen 系列 (阿里巴巴)
("qwen3.6-plus", "Qwen3.6 Plus", "0.325", "1.95", "0", "0"),
("qwen3.5-plus", "Qwen3.5 Plus", "0.26", "1.56", "0", "0"),
@@ -1746,6 +1781,22 @@ impl Database {
"0",
"0",
),
(
"qwen3-coder-480b",
"Qwen3 Coder 480B",
"0.65",
"3.25",
"0",
"0",
),
(
"qwen3-coder-480b-a35b-instruct",
"Qwen3 Coder 480B-A35B Instruct",
"0.65",
"3.25",
"0",
"0",
),
(
"qwen3-coder-flash",
"Qwen3 Coder Flash",
@@ -1801,12 +1852,13 @@ impl Database {
("grok-4", "Grok 4", "3", "15", "0.75", "0"),
(
"grok-code-fast-1",
"Grok Code Fast",
"Grok Build 0.1 (Code Fast Alias)",
"1",
"2",
"0.20",
"1.50",
"0.02",
"0",
),
("grok-build-0.1", "Grok Build 0.1", "1", "2", "0.20", "0"),
("grok-3", "Grok 3", "3", "15", "0.75", "0"),
("grok-3-mini", "Grok 3 Mini", "0.25", "0.50", "0.075", "0"),
// Mistral 系列
@@ -1898,6 +1950,96 @@ impl Database {
Ok(())
}
fn repair_current_model_pricing(conn: &Connection) -> Result<(), AppError> {
let pricing_fixes = [
(
"deepseek-v4-flash",
"DeepSeek V4 Flash",
"0.14",
"0.28",
"0.0028",
"0",
"0.14",
"0.28",
"0.028",
"0",
),
(
"deepseek-v4-pro",
"DeepSeek V4 Pro",
"0.435",
"0.87",
"0.003625",
"0",
"1.68",
"3.36",
"0.14",
"0",
),
(
"glm-5", "GLM-5", "1", "3.2", "0.2", "0", "0.72", "2.30", "0", "0",
),
(
"glm-5.1", "GLM-5.1", "1.4", "4.4", "0.26", "0", "0.95", "3.15", "0", "0",
),
(
"grok-code-fast-1",
"Grok Build 0.1 (Code Fast Alias)",
"1",
"2",
"0.20",
"0",
"0.20",
"1.50",
"0.02",
"0",
),
];
for (
model_id,
display_name,
input,
output,
cache_read,
cache_creation,
old_input,
old_output,
old_cache_read,
old_cache_creation,
) in pricing_fixes
{
conn.execute(
"UPDATE model_pricing SET
display_name = ?2,
input_cost_per_million = ?3,
output_cost_per_million = ?4,
cache_read_cost_per_million = ?5,
cache_creation_cost_per_million = ?6
WHERE model_id = ?1
AND input_cost_per_million = ?7
AND output_cost_per_million = ?8
AND cache_read_cost_per_million = ?9
AND cache_creation_cost_per_million = ?10",
rusqlite::params![
model_id,
display_name,
input,
output,
cache_read,
cache_creation,
old_input,
old_output,
old_cache_read,
old_cache_creation
],
)
.map_err(|e| AppError::Database(format!("修复模型 {model_id} 定价失败: {e}")))?;
}
Ok(())
}
/// 确保模型定价表具备默认数据
pub fn ensure_model_pricing_seeded(&self) -> Result<(), AppError> {
let conn = lock_conn!(self.conn);
@@ -1905,8 +2047,9 @@ impl Database {
}
fn ensure_model_pricing_seeded_on_conn(conn: &Connection) -> Result<(), AppError> {
// 每次启动都执行 INSERT OR IGNORE,增量追加新模型,已有数据不覆盖
Self::seed_model_pricing(conn)
// 每次启动都执行 INSERT OR IGNORE,增量追加新模型;仅修复仍等于旧内置值的定价。
Self::seed_model_pricing(conn)?;
Self::repair_current_model_pricing(conn)
}
// --- 辅助方法 ---
+60
View File
@@ -662,6 +662,66 @@ fn schema_model_pricing_is_seeded_on_init() {
);
}
#[test]
fn model_pricing_seed_repairs_known_outdated_builtin_prices() {
let db = Database::memory().expect("create memory db");
{
let conn = db.conn.lock().expect("lock conn");
conn.execute(
"UPDATE model_pricing
SET input_cost_per_million = '1.68',
output_cost_per_million = '3.36',
cache_read_cost_per_million = '0.14',
cache_creation_cost_per_million = '0'
WHERE model_id = 'deepseek-v4-pro'",
[],
)
.expect("restore old DeepSeek price");
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 = '0'
WHERE model_id = 'glm-5.1'",
[],
)
.expect("set custom GLM price");
}
db.ensure_model_pricing_seeded()
.expect("ensure pricing seeded");
let conn = db.conn.lock().expect("lock conn");
let deepseek: (String, String, String) = conn
.query_row(
"SELECT input_cost_per_million, output_cost_per_million, cache_read_cost_per_million
FROM model_pricing WHERE model_id = 'deepseek-v4-pro'",
[],
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
)
.expect("query DeepSeek price");
assert_eq!(
deepseek,
(
"0.435".to_string(),
"0.87".to_string(),
"0.003625".to_string()
)
);
let glm: (String, String, String) = conn
.query_row(
"SELECT input_cost_per_million, output_cost_per_million, cache_read_cost_per_million
FROM model_pricing WHERE model_id = 'glm-5.1'",
[],
|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
)
.expect("query GLM price");
assert_eq!(glm, ("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");