Files
Aether/_deprecated_py_src/api/handlers/openai_cli/adapter.py

139 lines
4.4 KiB
Python
Raw Normal View History

2025-12-10 20:52:44 +08:00
"""
OpenAI CLI Adapter - 基于通用 CLI Adapter 基类的简化实现
继承 CliAdapterBase只需配置 FORMAT_ID HANDLER_CLASS
"""
from __future__ import annotations
from typing import Any
2025-12-10 20:52:44 +08:00
from src.api.base.context import ApiRequestContext
2025-12-10 20:52:44 +08:00
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
2025-12-10 20:52:44 +08:00
@register_cli_adapter
class OpenAICliAdapter(CliAdapterBase):
"""
OpenAI CLI API 适配器
处理 /v1/responses 端点的请求
"""
FORMAT_ID = "openai:cli"
API_FAMILY = ApiFamily.OPENAI
2025-12-10 20:52:44 +08:00
name = "openai.cli"
@property
def HANDLER_CLASS(self) -> type[CliMessageHandlerBase]:
2025-12-10 20:52:44 +08:00
"""延迟导入 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)
2025-12-10 20:52:44 +08:00
@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
2025-12-10 20:52:44 +08:00
__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")