fix(libsql): parse scientific notation cost aggregates (#3296)

This commit is contained in:
firat.sertgoz
2026-05-06 15:43:31 +03:00
committed by GitHub
parent 53e18ec4b2
commit b0cb2335dc
2 changed files with 58 additions and 12 deletions

View File

@@ -1091,6 +1091,50 @@ mod admin_api_contracts {
assert_rfc3339(user.last_active_at.as_deref().unwrap());
}
#[tokio::test]
async fn test_admin_user_list_handles_tiny_costs_from_libsql() {
let (db, _dir) = test_db().await;
db.create_user(&test_user(
"carol",
"Carol",
Some("carol@example.com"),
"active",
"member",
serde_json::json!({}),
))
.await
.unwrap();
let job_id = db.create_system_job("carol", "test").await.unwrap();
db.record_llm_call(&crate::history::LlmCallRecord {
job_id: Some(job_id),
conversation_id: None,
provider: "test",
model: "tiny-cost-model",
input_tokens: 1,
output_tokens: 1,
cost: rust_decimal::Decimal::from_str_exact("0.000075").unwrap(),
purpose: Some("test"),
})
.await
.unwrap();
let state = build_state(Some(db), None);
let app = admin_router(state, two_user_auth());
let req = Request::builder()
.uri("/api/admin/users")
.header("Authorization", "Bearer tok-alice")
.body(Body::empty())
.unwrap();
let resp = app.oneshot(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body: AdminUserListResponse = parse_json(resp).await;
let user = body.users.iter().find(|u| u.id == "carol").unwrap();
assert_eq!(user.job_count, 1);
assert_eq!(user.total_cost, "0.000075");
}
#[tokio::test]
async fn test_admin_user_detail_response_contract() {
let (db, _dir) = test_db().await;

View File

@@ -45,6 +45,17 @@ fn row_to_api_token(row: &libsql::Row) -> Result<ApiTokenRecord, DatabaseError>
})
}
fn parse_libsql_decimal_text(
value: &str,
field_name: &str,
) -> Result<rust_decimal::Decimal, DatabaseError> {
rust_decimal::Decimal::from_str_exact(value)
.or_else(|_| rust_decimal::Decimal::from_scientific(value))
.map_err(|e| {
DatabaseError::Query(format!("invalid {} value '{}': {}", field_name, value, e))
})
}
pub(crate) async fn seed_initial_assistant_thread(
conn: &libsql::Connection,
user_id: &str,
@@ -658,9 +669,7 @@ impl UserStore for LibSqlBackend {
.map_err(|e| DatabaseError::Query(e.to_string()))?
{
let cost_str = get_text(&row, 5);
let total_cost = rust_decimal::Decimal::from_str_exact(&cost_str).map_err(|e| {
DatabaseError::Query(format!("invalid cost value '{}': {}", cost_str, e))
})?;
let total_cost = parse_libsql_decimal_text(&cost_str, "cost")?;
stats.push(crate::db::UserUsageStats {
user_id: get_text(&row, 0),
model: get_text(&row, 1),
@@ -836,9 +845,7 @@ impl UserStore for LibSqlBackend {
.map_err(|e| DatabaseError::Query(e.to_string()))?
{
let cost_str = get_text(&row, 2);
let total_cost = rust_decimal::Decimal::from_str_exact(&cost_str).map_err(|e| {
DatabaseError::Query(format!("invalid cost value '{}': {}", cost_str, e))
})?;
let total_cost = parse_libsql_decimal_text(&cost_str, "cost")?;
stats.push(crate::db::UserSummaryStats {
user_id: get_text(&row, 0),
job_count: row
@@ -896,12 +903,7 @@ impl UserStore for LibSqlBackend {
})?;
let usage_cost_str = get_text(&row, 8);
let usage_cost = rust_decimal::Decimal::from_str_exact(&usage_cost_str).map_err(|e| {
DatabaseError::Query(format!(
"invalid usage_cost value '{}': {}",
usage_cost_str, e
))
})?;
let usage_cost = parse_libsql_decimal_text(&usage_cost_str, "usage_cost")?;
Ok(AdminUsageSummary {
total_users: row