mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
feat(codex): 拆分openai:compact为独立端点,简化Codex请求为透传模式
- 新增openai:compact端点类型(EndpointKind.COMPACT),独立于openai:cli - OpenAICompactAdapter继承OpenAICliAdapter,自动标记compact模式 - Codex请求补丁改为纯透传:仅清理内部标记,不再修改客户端payload - stream_policy支持openai:compact独立策略,compact端点移除stream字段 - candidate_builder支持compact回退到cli端点 - auth_type: vertex_ai重命名为service_account,保持向后兼容 - Vertex Provider新增api_formats与auth_type组合校验 - KeyAllowedModels对话框改为从Provider获取模型,展示provider_model_name - Dialog内Select组件自动禁用Portal,修复层级遮挡问题 - 新增Codex compact端点回填迁移脚本
This commit is contained in:
@@ -199,24 +199,18 @@ class OpenAICliNormalizer(FormatNormalizer):
|
||||
|
||||
return internal
|
||||
|
||||
# Codex 需要的 include 项
|
||||
_CODEX_REQUIRED_INCLUDE = "reasoning.encrypted_content"
|
||||
|
||||
def request_from_internal(
|
||||
self,
|
||||
internal: InternalRequest,
|
||||
*,
|
||||
target_variant: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
_ = target_variant
|
||||
openai_cli_extra = internal.extra.get("openai_cli", {})
|
||||
is_compact = bool(openai_cli_extra.get("_aether_compact"))
|
||||
is_codex = str(target_variant or "").lower() == "codex" and not is_compact
|
||||
|
||||
result: dict[str, Any] = {
|
||||
"model": internal.model,
|
||||
"input": self._internal_messages_to_input(
|
||||
internal.messages, system_to_developer=is_codex
|
||||
),
|
||||
"input": self._internal_messages_to_input(internal.messages, system_to_developer=False),
|
||||
}
|
||||
|
||||
# 合并 instructions,如果没有则使用 system
|
||||
@@ -229,20 +223,17 @@ class OpenAICliNormalizer(FormatNormalizer):
|
||||
# 统一添加该字段以确保兼容性
|
||||
result["instructions"] = instructions_text or ""
|
||||
|
||||
# max_output_tokens/temperature/top_p: Codex 不支持,标准 API 可选
|
||||
if not is_codex:
|
||||
if internal.max_tokens is not None:
|
||||
# Responses API 使用 max_output_tokens
|
||||
result["max_output_tokens"] = internal.max_tokens
|
||||
if internal.temperature is not None:
|
||||
result["temperature"] = internal.temperature
|
||||
if internal.top_p is not None:
|
||||
result["top_p"] = internal.top_p
|
||||
if internal.max_tokens is not None:
|
||||
# Responses API 使用 max_output_tokens
|
||||
result["max_output_tokens"] = internal.max_tokens
|
||||
if internal.temperature is not None:
|
||||
result["temperature"] = internal.temperature
|
||||
if internal.top_p is not None:
|
||||
result["top_p"] = internal.top_p
|
||||
|
||||
if internal.stop_sequences:
|
||||
result["stop"] = list(internal.stop_sequences)
|
||||
# Codex 强制要求 stream=true;其他情况尊重客户端请求
|
||||
result["stream"] = True if is_codex else bool(internal.stream)
|
||||
result["stream"] = bool(internal.stream)
|
||||
|
||||
if internal.tools:
|
||||
# Responses API 使用扁平结构: {type, name, description, parameters}
|
||||
@@ -308,26 +299,10 @@ class OpenAICliNormalizer(FormatNormalizer):
|
||||
if key not in handled_keys and key not in result:
|
||||
result[key] = value
|
||||
|
||||
# 统一设置 store=false(Codex 强制要求,标准 API 兼容)
|
||||
# 标准 Responses API 默认设置 store=false
|
||||
if "store" not in result:
|
||||
result["store"] = False
|
||||
|
||||
# Codex 特定设置(覆盖/删除不支持的字段)
|
||||
if is_codex:
|
||||
result["parallel_tool_calls"] = True
|
||||
# 和 codex passthrough patch 保持一致:固定 include 列表
|
||||
result["include"] = [self._CODEX_REQUIRED_INCLUDE]
|
||||
# 删除 Codex 不支持的字段
|
||||
for key in (
|
||||
"previous_response_id",
|
||||
"service_tier",
|
||||
"max_completion_tokens",
|
||||
"truncation",
|
||||
"context_management",
|
||||
"user",
|
||||
):
|
||||
result.pop(key, None)
|
||||
|
||||
return result
|
||||
|
||||
# =========================
|
||||
|
||||
@@ -62,6 +62,10 @@ def _detect_data_format(
|
||||
return EndpointSignature(api_family=ApiFamily.CLAUDE, endpoint_kind=EndpointKind.CLI)
|
||||
return EndpointSignature(api_family=ApiFamily.CLAUDE, endpoint_kind=EndpointKind.CHAT)
|
||||
|
||||
# OpenAI compact: /responses/compact
|
||||
if "/responses/compact" in normalized:
|
||||
return EndpointSignature(api_family=ApiFamily.OPENAI, endpoint_kind=EndpointKind.COMPACT)
|
||||
|
||||
# OpenAI CLI: /responses
|
||||
if "/responses" in normalized:
|
||||
return EndpointSignature(api_family=ApiFamily.OPENAI, endpoint_kind=EndpointKind.CLI)
|
||||
|
||||
@@ -36,6 +36,7 @@ class EndpointKind(str, Enum):
|
||||
|
||||
CHAT = "chat"
|
||||
CLI = "cli"
|
||||
COMPACT = "compact"
|
||||
VIDEO = "video"
|
||||
IMAGE = "image"
|
||||
|
||||
|
||||
@@ -123,6 +123,19 @@ _ENDPOINT_DEFINITIONS: dict[tuple[ApiFamily, EndpointKind], EndpointDefinition]
|
||||
protected_keys=frozenset({"authorization", "content-type"}),
|
||||
data_format_id="openai_responses",
|
||||
),
|
||||
(ApiFamily.OPENAI, EndpointKind.COMPACT): EndpointDefinition(
|
||||
api_family=ApiFamily.OPENAI,
|
||||
endpoint_kind=EndpointKind.COMPACT,
|
||||
aliases=("openai_compact", "responses_compact"),
|
||||
default_path="/v1/responses/compact",
|
||||
auth_method=AuthMethod.BEARER,
|
||||
auth_header="Authorization",
|
||||
auth_type="bearer",
|
||||
protected_keys=frozenset({"authorization", "content-type"}),
|
||||
# compact endpoint is non-streaming by design.
|
||||
stream_in_body=False,
|
||||
data_format_id="openai_responses",
|
||||
),
|
||||
(ApiFamily.OPENAI, EndpointKind.VIDEO): EndpointDefinition(
|
||||
api_family=ApiFamily.OPENAI,
|
||||
endpoint_kind=EndpointKind.VIDEO,
|
||||
|
||||
Reference in New Issue
Block a user