refactor: 大规模模块拆分与重组,新增 aether-admin crate

- 新建独立 aether-admin crate 承载 admin 相关共享契约与纯辅助函数
- 拆分 ai_pipeline 下 kiro/private_envelope/conversion/planner 等大文件为子模块目录
- 重组 admin handlers 各业务域(billing/oauth/provider/system/users 等)为目录结构,移除 shared.rs/builders.rs 等反模式
- 移除 ai_pipeline runtime adapters 旧实现(claude/openai/gemini/kiro/vertex/antigravity 等),改由 provider transport 统一承载
- 移除 control_facade/execution_facade/auth_snapshot_facade 等冗余 facade 层
- 拆分 query/billing 与 query/monitoring 模块、state/runtime/payments 与 security 模块
- 扩展架构测试覆盖 admin_billing/admin_model/admin_users 等新模块
- 删除 docs/architecture/refactor-execution-plan.md 已完成的执行计划文档
This commit is contained in:
fawney19
2026-04-09 00:10:38 +08:00
parent 4fb9882b54
commit 4fc95adfb9
663 changed files with 48471 additions and 40232 deletions
@@ -0,0 +1,178 @@
use crate::handlers::admin::shared::unix_secs_to_rfc3339;
use crate::handlers::public::{
provider_key_api_formats, request_candidate_event_unix_secs, request_candidate_status_label,
};
use aether_data_contracts::repository::candidates::{
RequestCandidateStatus, StoredRequestCandidate,
};
use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
};
use serde_json::json;
use std::collections::BTreeMap;
fn json_truthy(value: &serde_json::Value) -> bool {
match value {
serde_json::Value::Null => false,
serde_json::Value::Bool(value) => *value,
serde_json::Value::Number(value) => value.as_f64().is_some_and(|value| value != 0.0),
serde_json::Value::String(value) => !value.trim().is_empty(),
serde_json::Value::Array(value) => !value.is_empty(),
serde_json::Value::Object(value) => !value.is_empty(),
}
}
fn endpoint_timestamp_or_now(value: Option<u64>, now_unix_secs: u64) -> serde_json::Value {
unix_secs_to_rfc3339(value.unwrap_or(now_unix_secs))
.map(serde_json::Value::String)
.unwrap_or(serde_json::Value::Null)
}
pub(crate) fn build_admin_provider_summary_value(
provider: &StoredProviderCatalogProvider,
endpoints: &[StoredProviderCatalogEndpoint],
keys: &[StoredProviderCatalogKey],
quota_snapshot: Option<&aether_data_contracts::repository::quota::StoredProviderQuotaSnapshot>,
model_stats: Option<
&aether_data_contracts::repository::global_models::StoredProviderModelStats,
>,
active_global_model_ids: Vec<String>,
now_unix_secs: u64,
) -> serde_json::Value {
let total_endpoints = endpoints.len();
let active_endpoints = endpoints
.iter()
.filter(|endpoint| endpoint.is_active)
.count();
let total_keys = keys.len();
let active_keys = keys.iter().filter(|key| key.is_active).count();
let total_models = model_stats
.map(|stats| stats.total_models as usize)
.unwrap_or(0);
let active_models = model_stats
.map(|stats| stats.active_models as usize)
.unwrap_or(0);
let api_formats = endpoints
.iter()
.map(|endpoint| endpoint.api_format.clone())
.collect::<Vec<_>>();
let format_to_endpoint_id = endpoints
.iter()
.map(|endpoint| (endpoint.api_format.clone(), endpoint.id.clone()))
.collect::<BTreeMap<_, _>>();
let mut keys_by_endpoint = BTreeMap::<String, Vec<&StoredProviderCatalogKey>>::new();
for endpoint in endpoints {
keys_by_endpoint.entry(endpoint.id.clone()).or_default();
}
for key in keys {
for api_format in provider_key_api_formats(key) {
if let Some(endpoint_id) = format_to_endpoint_id.get(&api_format) {
keys_by_endpoint
.entry(endpoint_id.clone())
.or_default()
.push(key);
}
}
}
let mut endpoint_health_scores = Vec::with_capacity(endpoints.len());
let endpoint_health_details = endpoints
.iter()
.map(|endpoint| {
let endpoint_keys = keys_by_endpoint
.get(&endpoint.id)
.cloned()
.unwrap_or_default();
let health_score = if endpoint_keys.is_empty() {
1.0
} else {
let mut scores = Vec::new();
for key in &endpoint_keys {
let score = key
.health_by_format
.as_ref()
.and_then(|value| value.get(&endpoint.api_format))
.and_then(|value| value.get("health_score"))
.and_then(serde_json::Value::as_f64)
.unwrap_or(1.0);
scores.push(score);
}
scores.iter().sum::<f64>() / scores.len() as f64
};
endpoint_health_scores.push(health_score);
json!({
"api_format": endpoint.api_format,
"health_score": health_score,
"is_active": endpoint.is_active,
"total_keys": endpoint_keys.len(),
"active_keys": endpoint_keys.iter().filter(|key| key.is_active).count(),
})
})
.collect::<Vec<_>>();
let avg_health_score = if endpoint_health_scores.is_empty() {
1.0
} else {
endpoint_health_scores.iter().sum::<f64>() / endpoint_health_scores.len() as f64
};
let unhealthy_endpoints = endpoint_health_scores
.iter()
.filter(|score| **score < 0.5)
.count();
let provider_config = provider.config.clone();
let config = provider_config
.as_ref()
.and_then(serde_json::Value::as_object);
let provider_ops_config = config.and_then(|cfg| cfg.get("provider_ops"));
let ops_configured = provider_ops_config.is_some_and(json_truthy);
let ops_architecture_id = provider_ops_config
.and_then(serde_json::Value::as_object)
.and_then(|cfg| cfg.get("architecture_id"))
.and_then(serde_json::Value::as_str)
.map(ToOwned::to_owned);
json!({
"id": provider.id.clone(),
"name": provider.name.clone(),
"provider_type": provider.provider_type.clone(),
"description": provider.description.clone(),
"website": provider.website.clone(),
"provider_priority": provider.provider_priority,
"keep_priority_on_conversion": provider.keep_priority_on_conversion,
"enable_format_conversion": provider.enable_format_conversion,
"is_active": provider.is_active,
"billing_type": quota_snapshot.map(|quota| quota.billing_type.clone()),
"monthly_quota_usd": quota_snapshot.and_then(|quota| quota.monthly_quota_usd),
"monthly_used_usd": quota_snapshot.map(|quota| quota.monthly_used_usd),
"quota_reset_day": quota_snapshot.and_then(|quota| quota.quota_reset_day),
"quota_last_reset_at": quota_snapshot
.and_then(|quota| quota.quota_last_reset_at_unix_secs)
.and_then(unix_secs_to_rfc3339),
"quota_expires_at": quota_snapshot
.and_then(|quota| quota.quota_expires_at_unix_secs)
.and_then(unix_secs_to_rfc3339),
"max_retries": provider.max_retries,
"proxy": provider.proxy.clone(),
"stream_first_byte_timeout": provider.stream_first_byte_timeout_secs,
"request_timeout": provider.request_timeout_secs,
"claude_code_advanced": config.and_then(|cfg| cfg.get("claude_code_advanced")).cloned(),
"pool_advanced": config.and_then(|cfg| cfg.get("pool_advanced")).cloned(),
"failover_rules": config.and_then(|cfg| cfg.get("failover_rules")).cloned(),
"total_endpoints": total_endpoints,
"active_endpoints": active_endpoints,
"total_keys": total_keys,
"active_keys": active_keys,
"total_models": total_models,
"active_models": active_models,
"global_model_ids": active_global_model_ids,
"avg_health_score": avg_health_score,
"unhealthy_endpoints": unhealthy_endpoints,
"api_formats": api_formats,
"endpoint_health_details": endpoint_health_details,
"ops_configured": ops_configured,
"ops_architecture_id": ops_architecture_id,
"created_at": endpoint_timestamp_or_now(provider.created_at_unix_secs, now_unix_secs),
"updated_at": endpoint_timestamp_or_now(provider.updated_at_unix_secs, now_unix_secs),
})
}