mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
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:
274
_deprecated_py_src/services/request/execution_runtime_plan.py
Normal file
274
_deprecated_py_src/services/request/execution_runtime_plan.py
Normal file
@@ -0,0 +1,274 @@
|
||||
"""
|
||||
Execution runtime 计划契约
|
||||
|
||||
用于在 Python 控制面和 Rust execution runtime 之间传递稳定的请求执行信息。
|
||||
当前阶段先服务于非流式 chat 路径的计划构建与本地执行拆分。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import json
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _drop_none(value: Any) -> Any:
|
||||
"""递归移除 None 字段,便于序列化为紧凑 payload。"""
|
||||
if isinstance(value, dict):
|
||||
return {key: _drop_none(item) for key, item in value.items() if item is not None}
|
||||
if isinstance(value, list):
|
||||
return [_drop_none(item) for item in value]
|
||||
return value
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ExecutionPlanTimeouts:
|
||||
connect_ms: int | None = None
|
||||
read_ms: int | None = None
|
||||
write_ms: int | None = None
|
||||
pool_ms: int | None = None
|
||||
total_ms: int | None = None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ExecutionPlanBody:
|
||||
json_body: Any = None
|
||||
body_bytes_b64: str | None = None
|
||||
body_ref: str | None = None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ExecutionProxySnapshot:
|
||||
enabled: bool
|
||||
mode: str | None = None
|
||||
node_id: str | None = None
|
||||
label: str | None = None
|
||||
url: str | None = None
|
||||
extra: dict[str, Any] | None = None
|
||||
|
||||
@classmethod
|
||||
def from_proxy_info(
|
||||
cls,
|
||||
proxy_info: dict[str, Any] | None,
|
||||
*,
|
||||
proxy_url: str | None = None,
|
||||
mode_override: str | None = None,
|
||||
node_id_override: str | None = None,
|
||||
extra: dict[str, Any] | None = None,
|
||||
) -> ExecutionProxySnapshot | None:
|
||||
if not proxy_info and not proxy_url:
|
||||
return None
|
||||
mode = (
|
||||
mode_override
|
||||
or str(proxy_info.get("type") or proxy_info.get("mode") or "").strip()
|
||||
or None
|
||||
)
|
||||
if not mode and proxy_url:
|
||||
mode = proxy_url.split("://", 1)[0].strip().lower() or None
|
||||
return cls(
|
||||
enabled=True,
|
||||
mode=mode,
|
||||
node_id=node_id_override
|
||||
or str((proxy_info or {}).get("node_id") or "").strip()
|
||||
or None,
|
||||
label=str((proxy_info or {}).get("label") or "").strip() or None,
|
||||
url=str(proxy_url or (proxy_info or {}).get("url") or "").strip() or None,
|
||||
extra=extra or None,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ExecutionPlan:
|
||||
request_id: str
|
||||
candidate_id: str | None
|
||||
provider_name: str
|
||||
provider_id: str
|
||||
endpoint_id: str
|
||||
key_id: str
|
||||
method: str
|
||||
url: str
|
||||
headers: dict[str, str]
|
||||
body: ExecutionPlanBody
|
||||
stream: bool
|
||||
provider_api_format: str
|
||||
client_api_format: str
|
||||
model_name: str
|
||||
content_type: str | None = None
|
||||
content_encoding: str | None = None
|
||||
proxy: ExecutionProxySnapshot | None = None
|
||||
tls_profile: str | None = None
|
||||
timeouts: ExecutionPlanTimeouts | None = None
|
||||
|
||||
def to_payload(self) -> dict[str, Any]:
|
||||
return _drop_none(asdict(self))
|
||||
|
||||
|
||||
_REMOTE_EXECUTION_RUNTIME_BYPASS_FORMATS = {"openai:cli", "openai:compact"}
|
||||
|
||||
|
||||
def should_bypass_remote_execution_runtime_url(
|
||||
url: str | None,
|
||||
*,
|
||||
provider_api_format: str | None = None,
|
||||
client_api_format: str | None = None,
|
||||
) -> bool:
|
||||
normalized_url = str(url or "").strip().lower()
|
||||
if not normalized_url:
|
||||
return False
|
||||
|
||||
normalized_provider_api_format = str(provider_api_format or "").strip().lower()
|
||||
normalized_client_api_format = str(client_api_format or "").strip().lower()
|
||||
if (
|
||||
normalized_provider_api_format not in _REMOTE_EXECUTION_RUNTIME_BYPASS_FORMATS
|
||||
and normalized_client_api_format not in _REMOTE_EXECUTION_RUNTIME_BYPASS_FORMATS
|
||||
):
|
||||
return False
|
||||
|
||||
return "/backend-api/codex" in normalized_url or "/backendapi/codex" in normalized_url
|
||||
|
||||
|
||||
def should_bypass_remote_execution_runtime(contract: ExecutionPlan) -> bool:
|
||||
return should_bypass_remote_execution_runtime_url(
|
||||
contract.url,
|
||||
provider_api_format=contract.provider_api_format,
|
||||
client_api_format=contract.client_api_format,
|
||||
)
|
||||
|
||||
|
||||
def is_remote_execution_runtime_proxy_supported(proxy: ExecutionProxySnapshot | None) -> bool:
|
||||
proxy_mode = str((proxy.mode if proxy else "") or "").strip().lower()
|
||||
return (
|
||||
proxy is None
|
||||
or (str(proxy.url or "").strip() != "" and proxy_mode not in {"tunnel"})
|
||||
or (proxy_mode == "tunnel" and str(proxy.node_id or "").strip() != "")
|
||||
)
|
||||
|
||||
|
||||
def is_remote_execution_runtime_contract_eligible(contract: ExecutionPlan) -> bool:
|
||||
content_encoding = str(contract.content_encoding or "").strip().lower()
|
||||
has_json_body = contract.body.json_body is not None
|
||||
has_raw_body = bool(str(contract.body.body_bytes_b64 or "").strip())
|
||||
has_body = has_json_body or has_raw_body
|
||||
return (
|
||||
((not has_body and content_encoding == "") or has_body)
|
||||
and (not has_json_body or content_encoding in {"", "gzip"} or has_raw_body)
|
||||
and is_remote_execution_runtime_proxy_supported(contract.proxy)
|
||||
and not should_bypass_remote_execution_runtime(contract)
|
||||
)
|
||||
|
||||
|
||||
def build_execution_plan_body(
|
||||
payload: Any,
|
||||
*,
|
||||
content_type: str | None = None,
|
||||
) -> ExecutionPlanBody:
|
||||
normalized_content_type = str(content_type or "").strip().lower()
|
||||
|
||||
if isinstance(payload, dict):
|
||||
return ExecutionPlanBody(json_body=payload)
|
||||
|
||||
if isinstance(payload, list) and "json" in normalized_content_type:
|
||||
return ExecutionPlanBody(json_body=payload)
|
||||
|
||||
if isinstance(payload, (bytes, bytearray, memoryview)):
|
||||
return ExecutionPlanBody(body_bytes_b64=base64.b64encode(bytes(payload)).decode("ascii"))
|
||||
|
||||
if isinstance(payload, str):
|
||||
return ExecutionPlanBody(
|
||||
body_bytes_b64=base64.b64encode(payload.encode("utf-8")).decode("ascii")
|
||||
)
|
||||
|
||||
if payload is None:
|
||||
return ExecutionPlanBody()
|
||||
|
||||
return ExecutionPlanBody(
|
||||
body_bytes_b64=base64.b64encode(
|
||||
json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
|
||||
).decode("ascii")
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class PreparedExecutionPlan:
|
||||
"""本地执行所需的运行时上下文;`contract` 是可序列化的稳定边界。"""
|
||||
|
||||
contract: ExecutionPlan
|
||||
payload: dict[str, Any]
|
||||
headers: dict[str, str]
|
||||
upstream_is_stream: bool
|
||||
needs_conversion: bool
|
||||
provider_type: str
|
||||
request_timeout: float
|
||||
delegate_config: dict[str, Any] | None = None
|
||||
proxy_config: dict[str, Any] | None = None
|
||||
envelope: Any = None
|
||||
selected_base_url: str | None = None
|
||||
client_content_encoding: str | None = None
|
||||
proxy_info: dict[str, Any] | None = None
|
||||
|
||||
@property
|
||||
def remote_eligible(self) -> bool:
|
||||
return is_remote_execution_runtime_contract_eligible(self.contract)
|
||||
|
||||
|
||||
async def build_proxy_snapshot(
|
||||
proxy_config: dict[str, Any] | None,
|
||||
*,
|
||||
label: str = "adapter",
|
||||
) -> ExecutionProxySnapshot | None:
|
||||
if not proxy_config:
|
||||
return None
|
||||
|
||||
try:
|
||||
from src.services.proxy_node.resolver import (
|
||||
build_proxy_url_async,
|
||||
resolve_delegate_config_async,
|
||||
resolve_proxy_info_async,
|
||||
)
|
||||
|
||||
delegate_cfg = await resolve_delegate_config_async(proxy_config)
|
||||
proxy_url: str | None = None
|
||||
if proxy_config and not (delegate_cfg and delegate_cfg.get("tunnel")):
|
||||
proxy_url = await build_proxy_url_async(proxy_config)
|
||||
proxy_info = await resolve_proxy_info_async(proxy_config)
|
||||
return ExecutionProxySnapshot.from_proxy_info(
|
||||
proxy_info,
|
||||
proxy_url=proxy_url,
|
||||
mode_override="tunnel" if delegate_cfg and delegate_cfg.get("tunnel") else None,
|
||||
node_id_override=(
|
||||
str(delegate_cfg.get("node_id") or "").strip() or None
|
||||
if delegate_cfg and delegate_cfg.get("tunnel")
|
||||
else None
|
||||
),
|
||||
)
|
||||
except Exception as exc:
|
||||
from src.core.logger import logger
|
||||
|
||||
logger.warning("Build {} proxy snapshot failed: {}", label, exc)
|
||||
return None
|
||||
|
||||
|
||||
# Compatibility aliases for older call sites still using executor terminology.
|
||||
should_bypass_remote_executor_url = should_bypass_remote_execution_runtime_url
|
||||
should_bypass_remote_executor = should_bypass_remote_execution_runtime
|
||||
is_remote_proxy_supported = is_remote_execution_runtime_proxy_supported
|
||||
is_remote_contract_eligible = is_remote_execution_runtime_contract_eligible
|
||||
|
||||
__all__ = [
|
||||
"ExecutionPlan",
|
||||
"ExecutionPlanBody",
|
||||
"ExecutionPlanTimeouts",
|
||||
"ExecutionProxySnapshot",
|
||||
"PreparedExecutionPlan",
|
||||
"build_execution_plan_body",
|
||||
"build_proxy_snapshot",
|
||||
"is_remote_contract_eligible",
|
||||
"is_remote_execution_runtime_contract_eligible",
|
||||
"is_remote_execution_runtime_proxy_supported",
|
||||
"is_remote_proxy_supported",
|
||||
"should_bypass_remote_execution_runtime",
|
||||
"should_bypass_remote_execution_runtime_url",
|
||||
"should_bypass_remote_executor",
|
||||
"should_bypass_remote_executor_url",
|
||||
]
|
||||
Reference in New Issue
Block a user