refactor: 大规模模块拆分与代码精简,新增 ai-pipeline/data-contracts 独立 crate

- 新增 aether-ai-pipeline 和 aether-data-contracts crate,将 pipeline 逻辑与数据契约从 gateway 中解耦
- 重构 admin handlers:拆分单体模块为 auth/billing/endpoint/features/model/observability/provider/system 等独立子模块
- 合并 chat/cli 重复代码路径:精简 conversion、finalize、planner 中的 sync/chat/cli 分支
- 重构 scheduler/executor/data 层,引入 facade 模式降低模块间耦合
- 移除冗余的 intent 模块,将 plan_fallback/policy/stream_path/sync_path 迁移至 executor
- 前端适配:调整 admin API 调用和 provider 模型测试对话框
This commit is contained in:
fawney19
2026-04-07 02:50:19 +08:00
parent 763ff03a7b
commit 5d96d6673b
732 changed files with 28593 additions and 20666 deletions

View File

@@ -1,149 +1,5 @@
use std::collections::{BTreeMap, BTreeSet};
use std::fs;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use aether_contracts::{ExecutionPlan, ExecutionResult, ExecutionTimeouts, RequestBody};
#[cfg(test)]
use aether_crypto::DEVELOPMENT_ENCRYPTION_KEY;
use aether_crypto::{decrypt_python_fernet_ciphertext, encrypt_python_fernet_plaintext};
use aether_data::redis::{RedisKeyspace, RedisKvRunner};
use aether_data::repository::candidate_selection::StoredMinimalCandidateSelectionRow;
use aether_data::repository::candidates::{
PublicHealthTimelineBucket, RequestCandidateStatus, StoredRequestCandidate,
};
use aether_data::repository::global_models::{
AdminGlobalModelListQuery, AdminProviderModelListQuery, CreateAdminGlobalModelRecord,
PublicGlobalModelQuery, StoredAdminGlobalModel, StoredAdminProviderModel,
StoredPublicGlobalModel, UpdateAdminGlobalModelRecord, UpsertAdminProviderModelRecord,
};
use aether_data::repository::management_tokens::{
CreateManagementTokenRecord, ManagementTokenListQuery, RegenerateManagementTokenSecret,
StoredManagementToken, StoredManagementTokenUserSummary, UpdateManagementTokenRecord,
};
use aether_data::repository::oauth_providers::{
EncryptedSecretUpdate, UpsertOAuthProviderConfigRecord,
};
use aether_data::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
};
use aether_data::repository::proxy_nodes::{
ProxyNodeHeartbeatMutation, ProxyNodeTunnelStatusMutation, StoredProxyNode,
StoredProxyNodeEvent,
};
use aether_runtime::{maybe_hold_axum_response_permit, AdmissionPermit};
use axum::body::{to_bytes, Body, Bytes};
use axum::extract::{ConnectInfo, Request, State};
use axum::http::header::{HeaderName, HeaderValue};
use axum::http::Response;
use axum::response::IntoResponse;
use axum::Json;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use base64::Engine as _;
use chrono::{Datelike, SecondsFormat, Utc};
use futures_util::TryStreamExt;
use regex::Regex;
pub(crate) use serde::Deserialize;
pub(crate) use serde_json::{json, Value};
use sha2::{Digest, Sha256};
use tracing::info;
pub(crate) use tracing::warn;
use url::form_urlencoded;
use url::Url;
use uuid::Uuid;
use crate::ai_pipeline::finalize::maybe_build_sync_finalize_outcome;
use crate::ai_pipeline::planner::{
maybe_build_stream_decision_payload, maybe_build_stream_plan_payload,
maybe_build_sync_decision_payload, maybe_build_sync_plan_payload,
};
use crate::api::ai::{
admin_default_body_rules_for_signature, admin_endpoint_signature_parts,
public_api_format_local_path,
};
use crate::api::response::{
build_client_response, build_local_auth_rejection_response, build_local_http_error_response,
build_local_overloaded_response, build_local_user_rpm_limited_response,
};
use crate::audit::record_shadow_result_non_blocking;
use crate::constants::*;
use crate::control::{
allows_control_execute_emergency, maybe_execute_via_control, request_model_local_rejection,
resolve_public_request_context, should_buffer_request_for_local_auth,
trusted_auth_local_rejection, GatewayControlDecision, GatewayPublicRequestContext,
};
use crate::execution_runtime::{
execute_execution_runtime_stream, execute_execution_runtime_sync,
maybe_execute_via_execution_runtime_stream, maybe_execute_via_execution_runtime_sync,
};
use crate::fallback_metrics::{GatewayFallbackMetricKind, GatewayFallbackReason};
use crate::headers::{
extract_or_generate_trace_id, header_value_str, should_skip_request_header,
};
use crate::provider_transport::provider_types::{
fixed_provider_template, provider_type_enables_format_conversion_by_default,
provider_type_is_fixed,
};
use crate::rate_limit::FrontdoorUserRpmOutcome;
use crate::scheduler::{
count_recent_rpm_requests_for_provider_key_since, is_provider_key_circuit_open,
provider_key_health_score,
};
use crate::state::{AppState, LocalProviderDeleteTaskState};
use crate::GatewayError;
const ADMIN_PROVIDER_MAPPING_PREVIEW_MAX_KEYS: usize = 200;
const ADMIN_PROVIDER_MAPPING_PREVIEW_MAX_MODELS: usize = 500;
const ADMIN_PROVIDER_MAPPING_PREVIEW_FETCH_LIMIT: usize = 10_000;
const ADMIN_PROVIDER_POOL_SCAN_BATCH: u64 = 200;
const ADMIN_EXTERNAL_MODELS_CACHE_KEY: &str = "aether:external:models_dev";
const ADMIN_EXTERNAL_MODELS_CACHE_TTL_SECS: u64 = 15 * 60;
const ADMIN_PROVIDER_OAUTH_DATA_UNAVAILABLE_DETAIL: &str = "Admin provider OAuth data unavailable";
pub(crate) mod admin;
pub(crate) mod internal;
pub(crate) mod proxy;
pub(crate) mod public;
pub(crate) mod shared;
pub(crate) use admin::stats::{
admin_stats_bad_request_response, list_usage_for_optional_range, parse_bounded_u32, round_to,
AdminStatsTimeRange, AdminStatsUsageFilter,
};
pub(crate) use shared::*;
pub(crate) const OFFICIAL_EXTERNAL_MODEL_PROVIDERS: &[&str] = &[
"anthropic",
"openai",
"google",
"google-vertex",
"azure",
"amazon-bedrock",
"xai",
"meta",
"deepseek",
"mistral",
"cohere",
"zhipuai",
"alibaba",
"minimax",
"moonshot",
"baichuan",
"ai21",
];
#[derive(Debug, Clone, Copy)]
pub(crate) struct AdminProviderPoolConfig {
pub(crate) lru_enabled: bool,
pub(crate) cost_window_seconds: u64,
pub(crate) cost_limit_per_key_tokens: Option<u64>,
}
#[derive(Debug, Default)]
pub(crate) struct AdminProviderPoolRuntimeState {
pub(crate) total_sticky_sessions: usize,
pub(crate) sticky_sessions_by_key: BTreeMap<String, usize>,
pub(crate) cooldown_reason_by_key: BTreeMap<String, String>,
pub(crate) cooldown_ttl_by_key: BTreeMap<String, u64>,
pub(crate) cost_window_usage_by_key: BTreeMap<String, u64>,
pub(crate) lru_score_by_key: BTreeMap<String, f64>,
}