feat(usage): show reasoning and fast badges in usage records

- extract provider reasoning effort from request body metadata
- extract priority service tier and expose it as service_tier
- show reasoning level and fast badges after model names
- include badges in active request updates and usage list payloads
- add targeted backend and frontend coverage
This commit is contained in:
AAEE86
2026-05-27 00:36:52 +08:00
parent e21cd72181
commit e27ca671fd
16 changed files with 371 additions and 13 deletions
@@ -1,6 +1,7 @@
mod types;
pub use types::{
extract_provider_reasoning_effort_from_body, extract_provider_service_tier_from_body,
parse_usage_body_ref, usage_body_ref, usage_request_metadata_client_family,
ApiKeyLastUsedDelta, ManagementTokenCounterDelta, PendingUsageCleanupSummary,
ProviderApiKeyWindowUsageRequest, ProxyNodeCounterDelta, StoredProviderApiKeyUsageSummary,
@@ -27,5 +28,6 @@ pub use types::{
UsageLeaderboardQuery, UsageMonitoringErrorCountQuery, UsageMonitoringErrorListQuery,
UsagePerformancePercentilesQuery, UsageProviderPerformanceQuery, UsageReadRepository,
UsageRepository, UsageSettledCostSummaryQuery, UsageTimeSeriesGranularity,
UsageTimeSeriesQuery, UsageWriteRepository,
UsageTimeSeriesQuery, UsageWriteRepository, PROVIDER_REASONING_EFFORT_METADATA_KEY,
PROVIDER_SERVICE_TIER_METADATA_KEY,
};
@@ -2,6 +2,48 @@ use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde_json::Value;
pub const PROVIDER_REASONING_EFFORT_METADATA_KEY: &str = "provider_reasoning_effort";
pub const PROVIDER_SERVICE_TIER_METADATA_KEY: &str = "provider_service_tier";
pub fn extract_provider_reasoning_effort_from_body(value: Option<&Value>) -> Option<String> {
let object = value.and_then(Value::as_object)?;
object
.get("reasoning_effort")
.and_then(Value::as_str)
.or_else(|| {
object
.get("reasoning")
.and_then(Value::as_object)
.and_then(|reasoning| reasoning.get("effort"))
.and_then(Value::as_str)
})
.and_then(normalize_provider_reasoning_effort)
}
fn normalize_provider_reasoning_effort(value: &str) -> Option<String> {
let normalized = value.trim().to_ascii_lowercase();
if normalized.is_empty() || normalized.len() > 64 {
return None;
}
Some(normalized)
}
pub fn extract_provider_service_tier_from_body(value: Option<&Value>) -> Option<String> {
value
.and_then(Value::as_object)
.and_then(|object| object.get("service_tier"))
.and_then(Value::as_str)
.and_then(normalize_provider_service_tier)
}
fn normalize_provider_service_tier(value: &str) -> Option<String> {
let normalized = value.trim().to_ascii_lowercase();
if normalized.is_empty() || normalized.len() > 64 {
return None;
}
Some(normalized)
}
/// Joined usage read model assembled from the accounting row plus the newer audit/snapshot
/// satellite tables.
///
@@ -375,6 +417,22 @@ impl StoredRequestUsageAudit {
self.request_metadata_string("trace_id")
}
pub fn provider_reasoning_effort(&self) -> Option<String> {
self.request_metadata_string(PROVIDER_REASONING_EFFORT_METADATA_KEY)
.and_then(normalize_provider_reasoning_effort)
.or_else(|| {
extract_provider_reasoning_effort_from_body(self.provider_request_body.as_ref())
})
}
pub fn provider_service_tier(&self) -> Option<String> {
self.request_metadata_string(PROVIDER_SERVICE_TIER_METADATA_KEY)
.and_then(normalize_provider_service_tier)
.or_else(|| {
extract_provider_service_tier_from_body(self.provider_request_body.as_ref())
})
}
pub fn body_ref(&self, field: UsageBodyField) -> Option<&str> {
match field {
UsageBodyField::RequestBody => self.request_body_ref.as_deref(),
@@ -2339,6 +2397,35 @@ mod tests {
assert_eq!(result.request_capture_source(), "stored_original");
}
#[test]
fn provider_reasoning_effort_reads_metadata_and_provider_request_body() {
let mut usage = sample_usage();
usage.provider_request_body = Some(json!({
"reasoning": { "effort": "XHigh" },
"service_tier": "Priority"
}));
assert_eq!(usage.provider_reasoning_effort().as_deref(), Some("xhigh"));
assert_eq!(usage.provider_service_tier().as_deref(), Some("priority"));
usage.request_metadata = Some(json!({
"provider_reasoning_effort": "max",
"provider_service_tier": "standard"
}));
assert_eq!(usage.provider_reasoning_effort().as_deref(), Some("max"));
assert_eq!(usage.provider_service_tier().as_deref(), Some("standard"));
usage.request_metadata = None;
usage.provider_request_body = Some(json!({
"reasoning_effort": "High",
"service_tier": "priority"
}));
assert_eq!(usage.provider_reasoning_effort().as_deref(), Some("high"));
assert_eq!(usage.provider_service_tier().as_deref(), Some("priority"));
}
#[test]
fn request_body_capture_json_entry_includes_capture_source_and_body_ref() {
let mut usage = sample_usage();