mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 16:56:16 +08:00
feat(usage): add Hermes Agent tracking + fix zero-cost bug + perf
Hermes: - Parse ~/.hermes/state.db sessions (incl. profiles/*/state.db) into proxy_request_logs with data_source='hermes_session', WAL-aware incremental sync, Hermes-reported cost preferred over model_pricing fallback Zero-cost bug (dashboard showed \$0 totals): - GPT-5.5 family default pricing (~83% of affected rows used GPT-5.5) - find_model_pricing_row: ASCII-lowercase normalization so "OpenAI/GPT-5.5@HIGH" matches seeded "gpt-5.5" - Startup cost backfill in async task: scan rows where total_cost <= 0 but tokens > 0, recompute via model_pricing in a single transaction Performance: - Add (app_type, created_at DESC) covering index for dashboard range queries - Add expression index on COALESCE(data_source, 'proxy') so dedup EXISTS subqueries use index lookup instead of full scan; drop superseded idx_request_logs_dedup_lookup Refactor: - row_to_request_log_detail helper (3-way de-dup; fixes cost_multiplier \"1\" vs \"1.0\" drift between callers) - Promote get_sync_state/update_sync_state to shared session_usage module (4 copies -> 1) - run_step helper in lib.rs replaces 9 if-let-Err blocks - maybe_backfill_log_costs returns bool to skip duplicate total_cost parsing in caller
This commit is contained in:
@@ -214,7 +214,7 @@ impl Database {
|
||||
[],
|
||||
)
|
||||
.map_err(|e| AppError::Database(e.to_string()))?;
|
||||
Self::create_request_logs_dedup_index_if_supported(conn)?;
|
||||
Self::create_request_logs_usage_indexes_if_supported(conn)?;
|
||||
|
||||
// 11. Model Pricing 表
|
||||
conn.execute(
|
||||
@@ -1108,7 +1108,7 @@ impl Database {
|
||||
"data_source",
|
||||
"TEXT NOT NULL DEFAULT 'proxy'",
|
||||
)?;
|
||||
Self::create_request_logs_dedup_index_if_supported(conn)?;
|
||||
Self::create_request_logs_usage_indexes_if_supported(conn)?;
|
||||
}
|
||||
|
||||
// 2. 创建会话日志同步状态表
|
||||
@@ -1298,6 +1298,13 @@ impl Database {
|
||||
"0.30",
|
||||
"3.75",
|
||||
),
|
||||
// GPT-5.5 系列
|
||||
("gpt-5.5", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
("gpt-5.5-low", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
("gpt-5.5-medium", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
("gpt-5.5-high", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
("gpt-5.5-xhigh", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
("gpt-5.5-minimal", "GPT-5.5", "5", "30", "0.50", "0"),
|
||||
// GPT-5.4 系列
|
||||
("gpt-5.4", "GPT-5.4", "2.50", "15", "0.25", "0"),
|
||||
("gpt-5.4-mini", "GPT-5.4 Mini", "0.75", "4.50", "0.075", "0"),
|
||||
@@ -1910,11 +1917,22 @@ impl Database {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_request_logs_dedup_index_if_supported(conn: &Connection) -> Result<(), AppError> {
|
||||
fn create_request_logs_usage_indexes_if_supported(conn: &Connection) -> Result<(), AppError> {
|
||||
if !Self::table_exists(conn, "proxy_request_logs")? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let has_app_type = Self::has_column(conn, "proxy_request_logs", "app_type")?;
|
||||
let has_created_at = Self::has_column(conn, "proxy_request_logs", "created_at")?;
|
||||
if has_app_type && has_created_at {
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_request_logs_app_created_at
|
||||
ON proxy_request_logs(app_type, created_at DESC)",
|
||||
[],
|
||||
)
|
||||
.map_err(|e| AppError::Database(format!("创建使用量应用时间索引失败: {e}")))?;
|
||||
}
|
||||
|
||||
let required_columns = [
|
||||
"app_type",
|
||||
"data_source",
|
||||
@@ -1930,13 +1948,20 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
conn.execute("DROP INDEX IF EXISTS idx_request_logs_dedup_lookup", [])
|
||||
.map_err(|e| AppError::Database(format!("删除旧使用量去重索引失败: {e}")))?;
|
||||
|
||||
// 查询层为了兼容历史 NULL data_source 行,会使用
|
||||
// COALESCE(data_source, 'proxy')。普通 data_source 索引无法匹配该表达式,
|
||||
// 会让跨源去重子查询退化成大量扫描;表达式索引让 SQLite 能按同一表达式查找。
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_request_logs_dedup_lookup
|
||||
ON proxy_request_logs(app_type, data_source, input_tokens, output_tokens,
|
||||
cache_read_tokens, created_at, cache_creation_tokens)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_request_logs_dedup_lookup_expr
|
||||
ON proxy_request_logs(app_type, COALESCE(data_source, 'proxy'), input_tokens,
|
||||
output_tokens, cache_read_tokens, created_at,
|
||||
cache_creation_tokens)",
|
||||
[],
|
||||
)
|
||||
.map_err(|e| AppError::Database(format!("创建使用量去重索引失败: {e}")))?;
|
||||
.map_err(|e| AppError::Database(format!("创建使用量去重表达式索引失败: {e}")))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user