mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
fix(compatibility): 同族格式透传不再依赖格式转换开关
将 data_format_id 相同的格式对(如 claude:chat / claude:cli)的透传判断 提前到三层开关检查之前,使其无需开关即可直接透传。 同时用 pytest.mark.parametrize 精简同族格式测试用例。
This commit is contained in:
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
转换逻辑:
|
转换逻辑:
|
||||||
1. 格式完全匹配 -> 透传(无需转换)
|
1. 格式完全匹配 -> 透传(无需转换)
|
||||||
2. 格式不同 -> 需要检查三层开关
|
2. data_format_id 相同 -> 透传(无需数据转换,如 claude:chat / claude:cli)
|
||||||
- data_format_id 相同 -> 可透传(无需数据转换)
|
3. 格式不同且 data_format_id 不同 -> 需要检查三层开关
|
||||||
- data_format_id 不同 -> 需要转换,检查转换器能力
|
- 通过开关检查后,检查转换器能力
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -78,20 +78,25 @@ def is_format_compatible(
|
|||||||
if provider_key == client_key:
|
if provider_key == client_key:
|
||||||
return True, False, None
|
return True, False, None
|
||||||
|
|
||||||
# 2. 格式不同 -> 需要检查格式转换开关(分层开关)
|
# 2. data_format_id 相同 -> 透传(无需数据转换,也无需格式转换开关)
|
||||||
|
# 例如:claude:chat / claude:cli 的 data_format_id 都是 “claude”,只是认证方式不同
|
||||||
|
if can_passthrough_endpoint(client_key, provider_key):
|
||||||
|
return True, False, None
|
||||||
|
|
||||||
|
# 3. 格式不同且 data_format_id 不同 -> 需要检查格式转换开关(分层开关)
|
||||||
#
|
#
|
||||||
# 设计语义(与模块顶部注释一致):
|
# 设计语义(与模块顶部注释一致):
|
||||||
# - 全局开关 ON -> 强制允许跨格式(通常 caller 会传 skip_endpoint_check=True)
|
# - 全局开关 ON -> 强制允许跨格式(通常 caller 会传 skip_endpoint_check=True)
|
||||||
# - 全局开关 OFF -> 不再“一刀切”拒绝,而是回退到 provider/endpoint 开关:
|
# - 全局开关 OFF -> 不再”一刀切”拒绝,而是回退到 provider/endpoint 开关:
|
||||||
# - provider 开关 ON -> 强制允许(skip_endpoint_check=True,跳过端点检查)
|
# - provider 开关 ON -> 强制允许(skip_endpoint_check=True,跳过端点检查)
|
||||||
# - provider 开关 OFF -> 由端点 format_acceptance_config 决定(skip_endpoint_check=False)
|
# - provider 开关 OFF -> 由端点 format_acceptance_config 决定(skip_endpoint_check=False)
|
||||||
#
|
#
|
||||||
# 说明:
|
# 说明:
|
||||||
# - effective_conversion_enabled 表示“全局默认允许”,不是“全局总闸/kill switch”
|
# - effective_conversion_enabled 表示”全局默认允许”,不是”全局总闸/kill switch”
|
||||||
# - 当它为 False 时,我们仍然会继续执行后续检查(provider/endpoint),
|
# - 当它为 False 时,我们仍然会继续执行后续检查(provider/endpoint),
|
||||||
# 兼容“按 Provider/Endpoint 精细化开启转换”的场景。
|
# 兼容”按 Provider/Endpoint 精细化开启转换”的场景。
|
||||||
|
|
||||||
# 3. 如果全局或提供商开关为 ON,跳过端点配置检查
|
# 4. 如果全局或提供商开关为 ON,跳过端点配置检查
|
||||||
if not skip_endpoint_check:
|
if not skip_endpoint_check:
|
||||||
# 检查端点配置(第三层开关)
|
# 检查端点配置(第三层开关)
|
||||||
if endpoint_format_acceptance_config is None:
|
if endpoint_format_acceptance_config is None:
|
||||||
@@ -117,13 +122,6 @@ def is_format_compatible(
|
|||||||
if is_stream and not config.get("stream_conversion", True):
|
if is_stream and not config.get("stream_conversion", True):
|
||||||
return False, False, "端点不支持流式格式转换"
|
return False, False, "端点不支持流式格式转换"
|
||||||
|
|
||||||
# 4. 检查是否可以透传(data_format_id 相同)
|
|
||||||
# 例如:claude:chat / claude:cli 的 data_format_id 都是 "claude",数据格式相同可透传
|
|
||||||
# openai:chat 是 "openai_chat",openai:cli 是 "openai_responses",需要转换
|
|
||||||
if can_passthrough_endpoint(client_key, provider_key):
|
|
||||||
# data_format_id 相同,可透传(无需数据转换)
|
|
||||||
return True, False, None
|
|
||||||
|
|
||||||
# 5. 需要数据转换的情况(data_format_id 不同)
|
# 5. 需要数据转换的情况(data_format_id 不同)
|
||||||
# 检查转换器能力
|
# 检查转换器能力
|
||||||
if not registry.can_convert_full(
|
if not registry.can_convert_full(
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ is_format_compatible 单元测试
|
|||||||
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from src.core.api_format.conversion.compatibility import is_format_compatible
|
from src.core.api_format.conversion.compatibility import is_format_compatible
|
||||||
|
|
||||||
|
|
||||||
@@ -186,81 +188,31 @@ def test_conversion_allowed_when_converter_supports_full() -> None:
|
|||||||
# ==================== 同族格式测试 ====================
|
# ==================== 同族格式测试 ====================
|
||||||
|
|
||||||
|
|
||||||
def test_claude_cli_to_claude_no_conversion_needed() -> None:
|
@pytest.mark.parametrize(
|
||||||
"""CLAUDE 和 CLAUDE_CLI 格式相同,只是认证不同,可透传(需开关启用)"""
|
"client_format, endpoint_format",
|
||||||
|
[
|
||||||
|
("claude:cli", "claude:chat"),
|
||||||
|
("claude:chat", "claude:cli"),
|
||||||
|
("gemini:cli", "gemini:chat"),
|
||||||
|
("gemini:chat", "gemini:cli"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_same_data_format_passthrough(client_format: str, endpoint_format: str) -> None:
|
||||||
|
"""data_format_id 相同的格式对(如 claude:chat / claude:cli)无需开关即可透传"""
|
||||||
|
# 即使全局开关 OFF、端点未配置,也应直接透传
|
||||||
ok, needs_conv, reason = is_format_compatible(
|
ok, needs_conv, reason = is_format_compatible(
|
||||||
"claude:cli",
|
client_format,
|
||||||
"claude:chat",
|
endpoint_format,
|
||||||
endpoint_format_acceptance_config={"enabled": True},
|
endpoint_format_acceptance_config=None,
|
||||||
is_stream=False,
|
|
||||||
effective_conversion_enabled=True,
|
|
||||||
registry=MagicMock(),
|
|
||||||
)
|
|
||||||
assert ok is True
|
|
||||||
assert needs_conv is False
|
|
||||||
assert reason is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_claude_to_claude_cli_no_conversion_needed() -> None:
|
|
||||||
"""CLAUDE 和 CLAUDE_CLI 格式相同,只是认证不同,可透传(需开关启用)"""
|
|
||||||
ok, needs_conv, reason = is_format_compatible(
|
|
||||||
"claude:chat",
|
|
||||||
"claude:cli",
|
|
||||||
endpoint_format_acceptance_config={"enabled": True},
|
|
||||||
is_stream=False,
|
|
||||||
effective_conversion_enabled=True,
|
|
||||||
registry=MagicMock(),
|
|
||||||
)
|
|
||||||
assert ok is True
|
|
||||||
assert needs_conv is False
|
|
||||||
assert reason is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_gemini_cli_to_gemini_no_conversion_needed() -> None:
|
|
||||||
"""GEMINI 和 GEMINI_CLI 格式相同,只是认证不同,可透传(需开关启用)"""
|
|
||||||
ok, needs_conv, reason = is_format_compatible(
|
|
||||||
"gemini:cli",
|
|
||||||
"gemini:chat",
|
|
||||||
endpoint_format_acceptance_config={"enabled": True},
|
|
||||||
is_stream=False,
|
|
||||||
effective_conversion_enabled=True,
|
|
||||||
registry=MagicMock(),
|
|
||||||
)
|
|
||||||
assert ok is True
|
|
||||||
assert needs_conv is False
|
|
||||||
assert reason is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_claude_cli_to_claude_allowed_when_endpoint_enabled() -> None:
|
|
||||||
"""透传格式(CLAUDE_CLI -> CLAUDE)全局 OFF 时回退到端点配置"""
|
|
||||||
ok, needs_conv, reason = is_format_compatible(
|
|
||||||
"claude:cli",
|
|
||||||
"claude:chat",
|
|
||||||
endpoint_format_acceptance_config={"enabled": True},
|
|
||||||
is_stream=False,
|
is_stream=False,
|
||||||
effective_conversion_enabled=False,
|
effective_conversion_enabled=False,
|
||||||
registry=MagicMock(),
|
registry=MagicMock(),
|
||||||
)
|
)
|
||||||
# 全局 OFF + 端点 enabled -> 允许(同族透传无需转换)
|
|
||||||
assert ok is True
|
assert ok is True
|
||||||
assert needs_conv is False
|
assert needs_conv is False
|
||||||
assert reason is None
|
assert reason is None
|
||||||
|
|
||||||
|
|
||||||
def test_claude_cli_to_claude_blocked_when_endpoint_not_configured() -> None:
|
|
||||||
"""透传格式(CLAUDE_CLI -> CLAUDE)也需要端点配置"""
|
|
||||||
ok, needs_conv, reason = is_format_compatible(
|
|
||||||
"claude:cli",
|
|
||||||
"claude:chat",
|
|
||||||
endpoint_format_acceptance_config=None,
|
|
||||||
is_stream=False,
|
|
||||||
effective_conversion_enabled=True,
|
|
||||||
registry=MagicMock(),
|
|
||||||
)
|
|
||||||
assert ok is False
|
|
||||||
assert reason and "未配置" in reason
|
|
||||||
|
|
||||||
|
|
||||||
def test_openai_cli_to_openai_needs_conversion() -> None:
|
def test_openai_cli_to_openai_needs_conversion() -> None:
|
||||||
"""OPENAI 和 OPENAI_CLI 格式不同(Chat Completions vs Responses API),需要转换"""
|
"""OPENAI 和 OPENAI_CLI 格式不同(Chat Completions vs Responses API),需要转换"""
|
||||||
registry = MagicMock()
|
registry = MagicMock()
|
||||||
|
|||||||
Reference in New Issue
Block a user