Merge upstream main into feat/500-api-key-ip-whitelist

This commit is contained in:
RWDai
2026-05-20 10:26:56 +08:00
501 changed files with 47013 additions and 3667 deletions

View File

@@ -727,6 +727,7 @@ pub fn build_admin_monitoring_system_status_payload_response(
active_streams: usize,
path_prefixes: &[&str],
recent_errors: usize,
usage_counter: Value,
) -> Response<Body> {
Json(json!({
"timestamp": timestamp.to_rfc3339(),
@@ -757,6 +758,7 @@ pub fn build_admin_monitoring_system_status_payload_response(
"path_prefixes": path_prefixes,
},
"recent_errors": recent_errors,
"usage_counter": usage_counter,
}))
.into_response()
}

View File

@@ -667,7 +667,9 @@ pub fn admin_stats_performance_percentiles_empty_response() -> Response<Body> {
Json(json!([])).into_response()
}
pub fn admin_stats_provider_performance_empty_response() -> Response<Body> {
pub fn admin_stats_provider_performance_empty_response(
usage_counter: serde_json::Value,
) -> Response<Body> {
Json(json!({
"summary": {
"request_count": 0,
@@ -678,6 +680,7 @@ pub fn admin_stats_provider_performance_empty_response() -> Response<Body> {
},
"providers": [],
"timeline": [],
"usage_counter": usage_counter,
}))
.into_response()
}
@@ -1093,6 +1096,7 @@ pub fn build_admin_stats_performance_percentiles_response_from_summaries(
pub fn build_admin_stats_provider_performance_response(
performance: &StoredUsageProviderPerformance,
usage_counter: serde_json::Value,
) -> Response<Body> {
let summary = &performance.summary;
let providers = performance
@@ -1158,6 +1162,7 @@ pub fn build_admin_stats_provider_performance_response(
},
"providers": providers,
"timeline": timeline,
"usage_counter": usage_counter,
}))
.into_response()
}

View File

@@ -1059,6 +1059,71 @@ fn admin_usage_upstream_is_stream(item: &StoredRequestUsageAudit) -> bool {
.unwrap_or(item.is_stream)
}
fn admin_usage_metadata_string<'a>(
item: &'a StoredRequestUsageAudit,
key: &str,
) -> Option<&'a str> {
item.request_metadata
.as_ref()
.and_then(Value::as_object)
.and_then(|metadata| metadata.get(key))
.and_then(Value::as_str)
.map(str::trim)
.filter(|value| !value.is_empty())
}
fn infer_client_family_from_user_agent(user_agent: &str) -> Option<&'static str> {
let normalized = user_agent.trim().to_ascii_lowercase();
if normalized.is_empty() {
return None;
}
if normalized.starts_with("codex_vscode") {
return Some("codex_vscode");
}
if normalized.starts_with("codex") {
return Some("codex");
}
if normalized.contains("claude-code") || normalized.contains("claude_code") {
return Some("claude_code");
}
if normalized.contains("opencode") {
return Some("opencode");
}
if normalized.contains("geminicli") || normalized.contains("gemini-cli") {
return Some("gemini_cli");
}
if normalized.starts_with("openai/js") {
return Some("openai_js_sdk");
}
None
}
pub fn admin_usage_client_family(item: &StoredRequestUsageAudit) -> Option<&str> {
item.client_family
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.or_else(|| {
item.request_metadata
.as_ref()
.and_then(Value::as_object)
.and_then(|metadata| {
metadata
.get("client_session_affinity")
.and_then(Value::as_object)
.and_then(|affinity| affinity.get("client_family"))
.and_then(Value::as_str)
.or_else(|| metadata.get("client_family").and_then(Value::as_str))
})
.map(str::trim)
.filter(|value| !value.is_empty())
})
.or_else(|| {
admin_usage_metadata_string(item, "user_agent")
.and_then(infer_client_family_from_user_agent)
})
}
fn admin_usage_active_request_json(
item: &StoredRequestUsageAudit,
api_key_name: Option<String>,
@@ -1091,6 +1156,11 @@ fn admin_usage_active_request_json(
"upstream_is_stream": upstream_is_stream,
"client_requested_stream": client_is_stream,
"client_is_stream": client_is_stream,
"client_family": admin_usage_client_family(item),
"client_ip": admin_usage_metadata_string(item, "client_ip"),
"user_agent": admin_usage_metadata_string(item, "user_agent"),
"request_path": admin_usage_metadata_string(item, "request_path"),
"request_path_and_query": admin_usage_metadata_string(item, "request_path_and_query"),
"has_fallback": admin_usage_has_fallback(item),
});
if let Some(api_format) = item.api_format.as_ref() {
@@ -1192,6 +1262,27 @@ pub fn admin_usage_record_json(
json!(client_is_stream),
);
object.insert("client_is_stream".to_string(), json!(client_is_stream));
maybe_insert_string_field(object, "client_family", admin_usage_client_family(item));
maybe_insert_string_field(
object,
"client_ip",
admin_usage_metadata_string(item, "client_ip"),
);
maybe_insert_string_field(
object,
"user_agent",
admin_usage_metadata_string(item, "user_agent"),
);
maybe_insert_string_field(
object,
"request_path",
admin_usage_metadata_string(item, "request_path"),
);
maybe_insert_string_field(
object,
"request_path_and_query",
admin_usage_metadata_string(item, "request_path_and_query"),
);
payload
}
@@ -2443,6 +2534,74 @@ mod tests {
assert_eq!(record["client_is_stream"], false);
}
#[test]
fn admin_usage_record_infers_client_family_from_user_agent() {
let item = StoredRequestUsageAudit {
request_metadata: Some(json!({
"client_ip": "192.168.0.28",
"user_agent": "codex_vscode/0.131.0-alpha.9 (Windows 10.0.26200; x86_64)"
})),
..sample_usage("completed", Some(200), None)
};
let record = admin_usage_record_json(
&item,
&BTreeMap::new(),
&BTreeMap::new(),
false,
false,
None,
);
let active = admin_usage_active_request_json(&item, None, None, None);
assert_eq!(record["client_family"], "codex_vscode");
assert_eq!(record["client_ip"], "192.168.0.28");
assert_eq!(active["client_family"], "codex_vscode");
}
#[test]
fn admin_usage_record_labels_openai_js_user_agent_as_sdk() {
let item = StoredRequestUsageAudit {
request_metadata: Some(json!({
"user_agent": "OpenAI/JS 6.34.0"
})),
..sample_usage("completed", Some(200), None)
};
let record = admin_usage_record_json(
&item,
&BTreeMap::new(),
&BTreeMap::new(),
false,
false,
None,
);
assert_eq!(record["client_family"], "openai_js_sdk");
}
#[test]
fn admin_usage_record_prefers_typed_client_family() {
let item = StoredRequestUsageAudit {
client_family: Some("codex".to_string()),
request_metadata: Some(json!({
"user_agent": "OpenAI/JS 6.34.0"
})),
..sample_usage("completed", Some(200), None)
};
let record = admin_usage_record_json(
&item,
&BTreeMap::new(),
&BTreeMap::new(),
false,
false,
None,
);
assert_eq!(record["client_family"], "codex");
}
#[test]
fn client_requested_stream_uses_stream_generate_content_path_over_stale_metadata_flag() {
let item = StoredRequestUsageAudit {

View File

@@ -6,6 +6,10 @@ use chrono::{TimeZone, Utc};
use serde_json::{json, Value};
use std::collections::BTreeMap;
pub fn normalize_endpoint_api_format(api_format: &str) -> String {
aether_ai_formats::normalize_api_format_alias(api_format)
}
fn unix_secs_to_rfc3339(unix_secs: u64) -> Option<String> {
Utc.timestamp_opt(unix_secs as i64, 0)
.single()
@@ -45,7 +49,7 @@ pub fn key_api_formats_without_entry(
fn active_endpoint_api_formats(endpoints: &[StoredProviderCatalogEndpoint]) -> Vec<String> {
let mut formats = Vec::new();
for endpoint in endpoints.iter().filter(|endpoint| endpoint.is_active) {
let api_format = aether_ai_formats::normalize_api_format_alias(&endpoint.api_format);
let api_format = normalize_endpoint_api_format(&endpoint.api_format);
if !formats.iter().any(|existing| existing == &api_format) {
formats.push(api_format);
}
@@ -63,7 +67,7 @@ fn configured_key_api_formats(key: &StoredProviderCatalogKey) -> Vec<String> {
};
let mut normalized = Vec::new();
for api_format in formats.iter().filter_map(serde_json::Value::as_str) {
let api_format = aether_ai_formats::normalize_api_format_alias(api_format);
let api_format = normalize_endpoint_api_format(api_format);
if !normalized.iter().any(|existing| existing == &api_format) {
normalized.push(api_format);
}

View File

@@ -736,7 +736,7 @@ const ADMIN_API_FORMAT_DEFINITIONS: &[AdminApiFormatDefinition] = &[
AdminApiFormatDefinition {
value: "gemini:embedding",
label: "Gemini Embedding",
default_path: "/v1/embeddings",
default_path: "/v1beta/models/{model}:{action}",
aliases: &["gemini_embedding"],
},
AdminApiFormatDefinition {
@@ -861,6 +861,7 @@ pub fn build_admin_system_stats_payload(
active_providers: u64,
total_api_keys: u64,
total_requests: u64,
usage_counter: serde_json::Value,
) -> serde_json::Value {
json!({
"users": {
@@ -873,6 +874,7 @@ pub fn build_admin_system_stats_payload(
},
"api_keys": total_api_keys,
"requests": total_requests,
"usage_counter": usage_counter,
})
}