refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构

- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
fawney19
2026-04-03 16:26:16 +08:00
parent 8f26e1a31f
commit 1d9c77522a
868 changed files with 1735 additions and 2433 deletions

View File

@@ -0,0 +1,145 @@
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::gateway::api::ai::{
admin_default_body_rules_for_signature, admin_endpoint_signature_parts,
public_api_format_local_path,
};
use crate::gateway::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::gateway::constants::*;
use crate::gateway::headers::{
extract_or_generate_trace_id, header_value_str, should_skip_request_header,
};
use crate::gateway::provider_transport::{
fixed_provider_template, provider_type_enables_format_conversion_by_default,
provider_type_is_fixed,
};
use crate::gateway::scheduler::{
count_recent_rpm_requests_for_provider_key_since, is_provider_key_circuit_open,
provider_key_health_score,
};
use crate::gateway::{
allows_control_execute_emergency, execute_execution_runtime_stream,
execute_execution_runtime_sync, maybe_build_stream_decision_payload,
maybe_build_stream_plan_payload, maybe_build_sync_decision_payload,
maybe_build_sync_finalize_outcome, maybe_build_sync_plan_payload, maybe_execute_via_control,
maybe_execute_via_execution_runtime_stream, maybe_execute_via_execution_runtime_sync,
record_shadow_result_non_blocking, request_model_local_rejection,
resolve_public_request_context, should_buffer_request_for_local_auth,
trusted_auth_local_rejection, AppState, FrontdoorUserRpmOutcome, GatewayControlDecision,
GatewayError, GatewayFallbackMetricKind, GatewayFallbackReason, GatewayPublicRequestContext,
LocalProviderDeleteTaskState,
};
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_RUST_BACKEND_DETAIL: &str =
"Admin provider OAuth requires Rust maintenance backend";
pub(crate) mod admin;
pub(crate) mod internal;
pub(crate) mod proxy;
pub(crate) mod public;
pub(crate) mod shared;
pub(crate) use admin::*;
pub(crate) use internal::*;
pub(crate) use public::*;
pub(crate) use proxy::proxy_request;
pub(crate) use shared::*;
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>,
}
pub(crate) use self::shared::*;