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:
173
_deprecated_py_src/services/provider/stream_policy.py
Normal file
173
_deprecated_py_src/services/provider/stream_policy.py
Normal file
@@ -0,0 +1,173 @@
|
||||
"""Upstream streaming execution policy (per endpoint).
|
||||
|
||||
This is about how we talk to the upstream provider, not what the client asked for.
|
||||
|
||||
Motivation:
|
||||
- Some upstreams require streaming only (e.g. Codex Responses OAuth endpoint).
|
||||
- Some upstreams do not support streaming (or are flaky with SSE).
|
||||
|
||||
We allow forcing upstream request mode per ProviderEndpoint, while the gateway still
|
||||
returns what the client requested by doing internal sync<->stream bridging.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from src.core.api_format.metadata import resolve_endpoint_definition
|
||||
from src.core.provider_types import ProviderType
|
||||
from src.services.provider.adapters.codex.context import is_codex_compact_request
|
||||
from src.services.provider.provider_context import resolve_provider_type
|
||||
|
||||
|
||||
class UpstreamStreamPolicy(str, Enum):
|
||||
AUTO = "auto" # follow client request
|
||||
FORCE_STREAM = "force_stream"
|
||||
FORCE_NON_STREAM = "force_non_stream"
|
||||
|
||||
|
||||
def parse_upstream_stream_policy(value: Any) -> UpstreamStreamPolicy:
|
||||
if value is None:
|
||||
return UpstreamStreamPolicy.AUTO
|
||||
|
||||
if isinstance(value, bool):
|
||||
return UpstreamStreamPolicy.FORCE_STREAM if value else UpstreamStreamPolicy.FORCE_NON_STREAM
|
||||
|
||||
raw = str(value).strip().lower()
|
||||
if raw in {"", "auto", "follow", "client", "default"}:
|
||||
return UpstreamStreamPolicy.AUTO
|
||||
if raw in {"force_stream", "stream", "sse", "true", "1", "yes"}:
|
||||
return UpstreamStreamPolicy.FORCE_STREAM
|
||||
if raw in {"force_non_stream", "force_sync", "non_stream", "sync", "false", "0", "no"}:
|
||||
return UpstreamStreamPolicy.FORCE_NON_STREAM
|
||||
|
||||
return UpstreamStreamPolicy.AUTO
|
||||
|
||||
|
||||
def get_upstream_stream_policy(
|
||||
endpoint: Any,
|
||||
*,
|
||||
provider_type: str | None = None,
|
||||
endpoint_sig: str | None = None,
|
||||
) -> UpstreamStreamPolicy:
|
||||
"""Resolve policy for an endpoint.
|
||||
|
||||
Config source: endpoint.config["upstream_stream_policy"] (preferred).
|
||||
|
||||
Defaults:
|
||||
- Codex + openai:cli: FORCE_STREAM (Codex upstream requires stream=true).
|
||||
- Codex + openai:compact: follow endpoint/client policy (no hard force).
|
||||
"""
|
||||
|
||||
# Prefer the caller-supplied provider_type; fall back to detached-safe provider lookup.
|
||||
pt = (
|
||||
resolve_provider_type(
|
||||
endpoint=endpoint,
|
||||
explicit_provider_type=provider_type,
|
||||
)
|
||||
or ""
|
||||
)
|
||||
sig = str(endpoint_sig or getattr(endpoint, "api_format", "") or "").strip().lower()
|
||||
is_codex_cli = pt == ProviderType.CODEX and sig == "openai:cli"
|
||||
is_codex_compact = pt == ProviderType.CODEX and sig == "openai:compact"
|
||||
if is_codex_cli:
|
||||
is_codex_compact = is_codex_compact_request(endpoint_sig=sig)
|
||||
|
||||
# Explicit config wins (unless upstream has a hard constraint).
|
||||
cfg = getattr(endpoint, "config", None)
|
||||
if isinstance(cfg, dict):
|
||||
val = (
|
||||
cfg.get("upstream_stream_policy")
|
||||
or cfg.get("upstreamStreamPolicy")
|
||||
or cfg.get("upstream_stream")
|
||||
)
|
||||
parsed = parse_upstream_stream_policy(val)
|
||||
if parsed != UpstreamStreamPolicy.AUTO:
|
||||
# Codex upstream requires streaming; do not allow forcing non-stream.
|
||||
if (
|
||||
is_codex_cli
|
||||
and parsed == UpstreamStreamPolicy.FORCE_NON_STREAM
|
||||
and not is_codex_compact
|
||||
):
|
||||
return UpstreamStreamPolicy.FORCE_STREAM
|
||||
if pt == ProviderType.KIRO and parsed == UpstreamStreamPolicy.FORCE_NON_STREAM:
|
||||
return UpstreamStreamPolicy.FORCE_STREAM
|
||||
return parsed
|
||||
|
||||
# Safe-by-default: Codex Responses OAuth behaves like SSE-only.
|
||||
if is_codex_cli:
|
||||
return (
|
||||
UpstreamStreamPolicy.FORCE_NON_STREAM
|
||||
if is_codex_compact
|
||||
else UpstreamStreamPolicy.FORCE_STREAM
|
||||
)
|
||||
|
||||
# Kiro upstream streams binary AWS Event Stream; treat as stream-only.
|
||||
if pt == ProviderType.KIRO:
|
||||
return UpstreamStreamPolicy.FORCE_STREAM
|
||||
|
||||
return UpstreamStreamPolicy.AUTO
|
||||
|
||||
|
||||
def resolve_upstream_is_stream(
|
||||
*,
|
||||
client_is_stream: bool,
|
||||
policy: UpstreamStreamPolicy,
|
||||
) -> bool:
|
||||
if policy == UpstreamStreamPolicy.FORCE_STREAM:
|
||||
return True
|
||||
if policy == UpstreamStreamPolicy.FORCE_NON_STREAM:
|
||||
return False
|
||||
return bool(client_is_stream)
|
||||
|
||||
|
||||
def enforce_stream_mode_for_upstream(
|
||||
request_body: dict[str, Any],
|
||||
*,
|
||||
provider_api_format: str,
|
||||
upstream_is_stream: bool,
|
||||
) -> dict[str, Any]:
|
||||
"""Force upstream stream/sync mode in request body (best-effort).
|
||||
|
||||
Note: Some formats (Gemini) do not use a `stream` field in body; for those we
|
||||
remove it to avoid leaking client intent.
|
||||
"""
|
||||
|
||||
meta = resolve_endpoint_definition(provider_api_format)
|
||||
provider_uses_stream = meta.stream_in_body if meta is not None else True
|
||||
|
||||
provider_fmt = str(provider_api_format or "").strip().lower()
|
||||
# OpenAI compact endpoint: keep request body stream field absent.
|
||||
if provider_fmt == "openai:compact":
|
||||
request_body.pop("stream", None)
|
||||
return request_body
|
||||
|
||||
# Backward compatibility: Codex compact routed through openai:cli + context marker.
|
||||
if provider_fmt == "openai:cli" and is_codex_compact_request(endpoint_sig=provider_fmt):
|
||||
request_body.pop("stream", None)
|
||||
return request_body
|
||||
|
||||
if provider_uses_stream:
|
||||
request_body["stream"] = bool(upstream_is_stream)
|
||||
else:
|
||||
request_body.pop("stream", None)
|
||||
|
||||
# OpenAI Chat Completions: request usage in streaming mode.
|
||||
if upstream_is_stream and provider_fmt == "openai:chat":
|
||||
stream_options = request_body.get("stream_options")
|
||||
if not isinstance(stream_options, dict):
|
||||
stream_options = {}
|
||||
stream_options["include_usage"] = True
|
||||
request_body["stream_options"] = stream_options
|
||||
|
||||
return request_body
|
||||
|
||||
|
||||
__all__ = [
|
||||
"UpstreamStreamPolicy",
|
||||
"enforce_stream_mode_for_upstream",
|
||||
"get_upstream_stream_policy",
|
||||
"parse_upstream_stream_policy",
|
||||
"resolve_upstream_is_stream",
|
||||
]
|
||||
Reference in New Issue
Block a user