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,277 @@
from __future__ import annotations
import re
from typing import Any
from pydantic import BaseModel, Field
_GEMINI_MODEL_ROUTE_RE = re.compile(
r"^/(v1|v1beta)/models/[^/]+:(generateContent|streamGenerateContent|predictLongRunning)$"
)
_GEMINI_MODEL_OPERATION_CANCEL_RE = re.compile(r"^/v1beta/models/[^/]+/operations/[^/]+:cancel$")
_GEMINI_OPERATION_CANCEL_RE = re.compile(r"^/v1beta/operations/[^/]+:cancel$")
_GEMINI_MODEL_OPERATION_ROUTE_RE = re.compile(r"^/v1beta/models/[^/]+/operations/[^/]+$")
_GEMINI_FILES_ROUTE_RE = re.compile(r"^/v1beta/files(?:/.+)?$")
_GEMINI_FILES_DOWNLOAD_ROUTE_RE = re.compile(r"^/v1beta/files/(?P<file_id>[^/]+):download$")
_GEMINI_FILES_RESOURCE_ROUTE_RE = re.compile(r"^/v1beta/files/(?P<file_name>.+)$")
_GEMINI_SYNC_ROUTE_RE = re.compile(
r"^/(?P<version>v1|v1beta)/models/(?P<model>[^/]+):(?P<action>generateContent|streamGenerateContent)$"
)
_OPENAI_VIDEO_CANCEL_ROUTE_RE = re.compile(r"^/v1/videos/(?P<task_id>[^/]+)/cancel$")
_OPENAI_VIDEO_REMIX_ROUTE_RE = re.compile(r"^/v1/videos/(?P<task_id>[^/]+)/remix$")
_OPENAI_VIDEO_CONTENT_ROUTE_RE = re.compile(r"^/v1/videos/(?P<task_id>[^/]+)/content$")
_OPENAI_VIDEO_TASK_ROUTE_RE = re.compile(r"^/v1/videos/(?P<task_id>[^/]+)$")
_GEMINI_VIDEO_CREATE_ROUTE_RE = re.compile(r"^/v1beta/models/(?P<model>[^/]+):predictLongRunning$")
_GEMINI_VIDEO_MODEL_OPERATION_ANY_RE = re.compile(
r"^/v1beta/models/(?P<model>[^/]+)/operations/(?P<operation_id>[^/]+)(?P<cancel>:cancel)?$"
)
CONTROL_EXECUTED_HEADER = "x-aether-control-executed"
CONTROL_ACTION_HEADER = "x-aether-control-action"
CONTROL_ACTION_PROXY_PUBLIC = "proxy_public"
class GatewayResolveRequest(BaseModel):
trace_id: str | None = Field(None, max_length=128)
method: str = Field(..., min_length=1, max_length=16)
path: str = Field(..., min_length=1, max_length=2048)
query_string: str | None = Field(None, max_length=8192)
headers: dict[str, str] = Field(default_factory=dict)
has_body: bool = False
content_type: str | None = Field(None, max_length=512)
content_length: int | None = Field(None, ge=0)
class GatewayAuthContextRequest(BaseModel):
trace_id: str | None = Field(None, max_length=128)
query_string: str | None = Field(None, max_length=8192)
headers: dict[str, str] = Field(default_factory=dict)
auth_endpoint_signature: str = Field(..., min_length=1, max_length=128)
class GatewayRouteDecision(BaseModel):
action: str = "proxy_public"
route_class: str
public_path: str
public_query_string: str | None = None
route_family: str | None = None
route_kind: str | None = None
auth_endpoint_signature: str | None = None
executor_candidate: bool = False
auth_context: dict[str, Any] | None = None
class GatewayAuthContext(BaseModel):
user_id: str
api_key_id: str
balance_remaining: float | None = None
access_allowed: bool = True
class GatewayExecuteRequest(BaseModel):
trace_id: str | None = Field(None, max_length=128)
method: str = Field(..., min_length=1, max_length=16)
path: str = Field(..., min_length=1, max_length=2048)
query_string: str | None = Field(None, max_length=8192)
headers: dict[str, str] = Field(default_factory=dict)
body_json: dict[str, Any] = Field(default_factory=dict)
body_base64: str | None = None
auth_context: GatewayAuthContext | None = None
class GatewayExecutionPlanResponse(BaseModel):
action: str
plan_kind: str
plan: dict[str, Any]
report_kind: str | None = None
report_context: dict[str, Any] | None = None
auth_context: GatewayAuthContext | None = None
class GatewayExecutionDecisionResponse(BaseModel):
action: str
decision_kind: str
request_id: str
candidate_id: str | None = None
provider_name: str
provider_id: str
endpoint_id: str
key_id: str
upstream_base_url: str
upstream_url: str | None = None
provider_request_method: str | None = None
auth_header: str
auth_value: str
provider_api_format: str
client_api_format: str
model_name: str
mapped_model: str | None = None
prompt_cache_key: str | None = None
extra_headers: dict[str, str] = Field(default_factory=dict)
provider_request_headers: dict[str, str] | None = None
provider_request_body: dict[str, Any] | None = None
content_type: str | None = None
proxy: dict[str, Any] | None = None
tls_profile: str | None = None
timeouts: dict[str, Any] | None = None
upstream_is_stream: bool | None = None
report_kind: str | None = None
report_context: dict[str, Any] | None = None
auth_context: GatewayAuthContext | None = None
class GatewaySyncReportRequest(BaseModel):
trace_id: str | None = Field(None, max_length=128)
report_kind: str = Field(..., min_length=1, max_length=128)
report_context: dict[str, Any] = Field(default_factory=dict)
status_code: int = Field(..., ge=100, le=599)
headers: dict[str, str] = Field(default_factory=dict)
body_json: Any = None
client_body_json: Any = None
body_base64: str | None = None
telemetry: dict[str, Any] | None = None
class GatewayStreamReportRequest(BaseModel):
trace_id: str | None = Field(None, max_length=128)
report_kind: str = Field(..., min_length=1, max_length=128)
report_context: dict[str, Any] = Field(default_factory=dict)
status_code: int = Field(..., ge=100, le=599)
headers: dict[str, str] = Field(default_factory=dict)
body_base64: str | None = None
telemetry: dict[str, Any] | None = None
def classify_gateway_route(
method: str,
path: str,
headers: dict[str, str] | None = None,
) -> GatewayRouteDecision:
normalized_method = str(method or "").strip().upper() or "GET"
normalized_path = str(path or "").strip() or "/"
normalized_headers = {str(k).lower(): str(v) for k, v in (headers or {}).items()}
if not normalized_path.startswith("/"):
normalized_path = f"/{normalized_path}"
if normalized_method == "POST" and normalized_path == "/v1/chat/completions":
return _ai_route(
normalized_path,
family="openai",
kind="chat",
auth_endpoint_signature="openai:chat",
)
if normalized_method == "POST" and normalized_path in {
"/v1/responses",
"/v1/responses/compact",
}:
route_kind = "compact" if normalized_path.endswith("/compact") else "cli"
auth_endpoint_signature = "openai:compact" if route_kind == "compact" else "openai:cli"
return _ai_route(
normalized_path,
family="openai",
kind=route_kind,
auth_endpoint_signature=auth_endpoint_signature,
)
if normalized_method == "POST" and normalized_path == "/v1/messages":
is_claude_cli = _is_claude_cli_request(normalized_headers)
return _ai_route(
normalized_path,
family="claude",
kind="cli" if is_claude_cli else "chat",
auth_endpoint_signature="claude:cli" if is_claude_cli else "claude:chat",
)
if normalized_path.startswith("/v1/videos"):
return _ai_route(
normalized_path,
family="openai",
kind="video",
auth_endpoint_signature="openai:video",
)
if _GEMINI_MODEL_ROUTE_RE.match(normalized_path):
if normalized_path.endswith(":predictLongRunning"):
return _ai_route(
normalized_path,
family="gemini",
kind="video",
auth_endpoint_signature="gemini:video",
)
is_gemini_cli = _is_gemini_cli_request(normalized_headers)
return _ai_route(
normalized_path,
family="gemini",
kind="cli" if is_gemini_cli else "chat",
auth_endpoint_signature="gemini:cli" if is_gemini_cli else "gemini:chat",
)
if (
_GEMINI_MODEL_OPERATION_CANCEL_RE.match(normalized_path)
or _GEMINI_OPERATION_CANCEL_RE.match(normalized_path)
or _GEMINI_MODEL_OPERATION_ROUTE_RE.match(normalized_path)
or normalized_path == "/v1beta/operations"
or normalized_path.startswith("/v1beta/operations/")
):
return _ai_route(
normalized_path,
family="gemini",
kind="video",
auth_endpoint_signature="gemini:video",
)
if normalized_method == "POST" and normalized_path == "/upload/v1beta/files":
return _ai_route(
normalized_path,
family="gemini",
kind="files",
auth_endpoint_signature="gemini:chat",
)
if _GEMINI_FILES_ROUTE_RE.match(normalized_path):
return _ai_route(
normalized_path,
family="gemini",
kind="files",
auth_endpoint_signature="gemini:chat",
)
return GatewayRouteDecision(
route_class="passthrough",
public_path=normalized_path,
executor_candidate=False,
)
def _ai_route(
path: str,
*,
family: str,
kind: str,
auth_endpoint_signature: str,
) -> GatewayRouteDecision:
return GatewayRouteDecision(
route_class="ai_public",
public_path=path,
route_family=family,
route_kind=kind,
auth_endpoint_signature=auth_endpoint_signature,
executor_candidate=True,
)
def _is_claude_cli_request(headers: dict[str, str]) -> bool:
auth_header = str(headers.get("authorization") or "").strip().lower()
has_bearer = auth_header.startswith("bearer ")
has_api_key = bool(str(headers.get("x-api-key") or "").strip())
return has_bearer and not has_api_key
def _is_gemini_cli_request(headers: dict[str, str]) -> bool:
x_app = str(headers.get("x-app") or "").lower()
if "cli" in x_app:
return True
user_agent = str(headers.get("user-agent") or "").lower()
return "geminicli" in user_agent or "gemini-cli" in user_agent