mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
- 删除全部 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)
139 lines
4.4 KiB
Python
139 lines
4.4 KiB
Python
"""
|
||
OpenAI CLI Adapter - 基于通用 CLI Adapter 基类的简化实现
|
||
|
||
继承 CliAdapterBase,只需配置 FORMAT_ID 和 HANDLER_CLASS。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from src.api.base.context import ApiRequestContext
|
||
from src.api.handlers.base.cli_adapter_base import CliAdapterBase, register_cli_adapter
|
||
from src.api.handlers.base.cli_handler_base import CliMessageHandlerBase
|
||
from src.config.settings import config
|
||
from src.core.api_format import ApiFamily, EndpointKind
|
||
from src.core.provider_types import ProviderType
|
||
from src.utils.url_utils import is_codex_url
|
||
|
||
|
||
@register_cli_adapter
|
||
class OpenAICliAdapter(CliAdapterBase):
|
||
"""
|
||
OpenAI CLI API 适配器
|
||
|
||
处理 /v1/responses 端点的请求。
|
||
"""
|
||
|
||
FORMAT_ID = "openai:cli"
|
||
API_FAMILY = ApiFamily.OPENAI
|
||
name = "openai.cli"
|
||
|
||
@property
|
||
def HANDLER_CLASS(self) -> type[CliMessageHandlerBase]:
|
||
"""延迟导入 Handler 类避免循环依赖"""
|
||
from src.api.handlers.openai_cli.handler import OpenAICliMessageHandler
|
||
|
||
return OpenAICliMessageHandler
|
||
|
||
def __init__(
|
||
self,
|
||
allowed_api_formats: list[str] | None = None,
|
||
*,
|
||
compact: bool = False,
|
||
):
|
||
super().__init__(allowed_api_formats)
|
||
self._compact = compact
|
||
|
||
async def handle(self, context: ApiRequestContext) -> Any:
|
||
"""处理 CLI API 请求。"""
|
||
if self._compact:
|
||
from src.services.provider.adapters.codex.context import (
|
||
CodexRequestContext,
|
||
set_codex_request_context,
|
||
)
|
||
|
||
# Keep compact routing state out of the request body. Transport/policy layers
|
||
# read this request-scoped flag directly when legacy compact fallback is needed.
|
||
set_codex_request_context(CodexRequestContext(is_compact=True))
|
||
|
||
body = await context.ensure_json_body_async()
|
||
# compact 端点永远非流式
|
||
body.pop("stream", None)
|
||
return await super().handle(context)
|
||
|
||
@classmethod
|
||
def build_endpoint_url(
|
||
cls,
|
||
base_url: str,
|
||
request_data: dict[str, Any],
|
||
model_name: str | None = None,
|
||
*,
|
||
compact: bool = False,
|
||
provider_type: str | None = None,
|
||
) -> str:
|
||
"""构建OpenAI CLI API端点URL(使用 Responses API)
|
||
|
||
对于 Codex OAuth 端点(如 chatgpt.com/backend-api/codex),直接追加 /responses;
|
||
对于标准 OpenAI API,使用 /v1/responses。
|
||
compact=True 时追加 /compact 后缀。
|
||
|
||
provider_type 优先:仅当 provider_type 为 codex 时才使用 Codex 路由规则;
|
||
未传入 provider_type 时回退到 URL 模式匹配(兼容旧调用方)。
|
||
"""
|
||
suffix = "/responses/compact" if compact else "/responses"
|
||
base_url = base_url.rstrip("/")
|
||
# 判断是否按 Codex 规则构建 URL
|
||
is_codex = (
|
||
(provider_type or "").lower() == ProviderType.CODEX
|
||
if provider_type
|
||
else is_codex_url(base_url)
|
||
)
|
||
if is_codex:
|
||
return f"{base_url}{suffix}"
|
||
# 标准 OpenAI API
|
||
if base_url.endswith("/v1"):
|
||
return f"{base_url}{suffix}"
|
||
else:
|
||
return f"{base_url}/v1{suffix}"
|
||
|
||
# build_request_body 使用基类实现
|
||
# OpenAI CLI normalizer 会自动添加 instructions 字段
|
||
|
||
@classmethod
|
||
def build_request_body(
|
||
cls,
|
||
request_data: dict[str, Any] | None = None,
|
||
*,
|
||
base_url: str | None = None,
|
||
provider_type: str | None = None,
|
||
) -> dict[str, Any]:
|
||
"""构建测试请求体。"""
|
||
from src.api.handlers.base.request_builder import build_test_request_body
|
||
|
||
del base_url, provider_type
|
||
return build_test_request_body(cls.FORMAT_ID, request_data)
|
||
|
||
@classmethod
|
||
def get_cli_user_agent(cls) -> str | None:
|
||
"""获取OpenAI CLI User-Agent"""
|
||
return config.internal_user_agent_openai_cli
|
||
|
||
|
||
__all__ = ["OpenAICliAdapter"]
|
||
|
||
|
||
@register_cli_adapter
|
||
class OpenAICompactAdapter(OpenAICliAdapter):
|
||
"""OpenAI Compact Responses adapter (/v1/responses/compact)."""
|
||
|
||
FORMAT_ID = "openai:compact"
|
||
ENDPOINT_KIND = EndpointKind.COMPACT
|
||
name = "openai.compact"
|
||
|
||
def __init__(self, allowed_api_formats: list[str] | None = None):
|
||
super().__init__(allowed_api_formats=allowed_api_formats, compact=True)
|
||
|
||
|
||
__all__.append("OpenAICompactAdapter")
|