mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
fix(cli): 统一 CLI handler pending usage 的 api_format 来源
CLI stream/sync mixin 中创建 pending usage 记录时,api_format 取值 来源不一致(部分用 FORMAT_ID,部分用 allowed_api_formats[0])。 新增 primary_api_format 属性并统一使用,确保 pending 记录的格式 与实际客户端请求格式一致。
This commit is contained in:
@@ -49,6 +49,7 @@ class CliHandlerProtocol(Protocol):
|
|||||||
user_agent: str
|
user_agent: str
|
||||||
start_time: float
|
start_time: float
|
||||||
allowed_api_formats: list[str]
|
allowed_api_formats: list[str]
|
||||||
|
primary_api_format: str
|
||||||
redis: Redis # type: ignore[type-arg]
|
redis: Redis # type: ignore[type-arg]
|
||||||
telemetry: MessageTelemetry
|
telemetry: MessageTelemetry
|
||||||
perf_metrics: dict[str, Any] | None
|
perf_metrics: dict[str, Any] | None
|
||||||
|
|||||||
@@ -99,13 +99,14 @@ class CliStreamMixin:
|
|||||||
# 使用子类实现的方法提取 model(不同 API 格式的 model 位置不同)
|
# 使用子类实现的方法提取 model(不同 API 格式的 model 位置不同)
|
||||||
# 注意:使用 original_request_body,因为整流只修改 messages,不影响 model 字段
|
# 注意:使用 original_request_body,因为整流只修改 messages,不影响 model 字段
|
||||||
model = self.extract_model_from_request(original_request_body, path_params)
|
model = self.extract_model_from_request(original_request_body, path_params)
|
||||||
|
client_api_format = self.primary_api_format
|
||||||
|
|
||||||
# 提前创建 pending 记录,让前端可以立即看到"处理中"
|
# 提前创建 pending 记录,让前端可以立即看到"处理中"
|
||||||
self._create_pending_usage(
|
self._create_pending_usage(
|
||||||
model=model,
|
model=model,
|
||||||
is_stream=True,
|
is_stream=True,
|
||||||
request_type="chat",
|
request_type="chat",
|
||||||
api_format=self.FORMAT_ID,
|
api_format=client_api_format,
|
||||||
request_headers=original_headers,
|
request_headers=original_headers,
|
||||||
request_body=original_request_body,
|
request_body=original_request_body,
|
||||||
)
|
)
|
||||||
@@ -113,7 +114,7 @@ class CliStreamMixin:
|
|||||||
# 创建流上下文
|
# 创建流上下文
|
||||||
ctx = StreamContext(
|
ctx = StreamContext(
|
||||||
model=model,
|
model=model,
|
||||||
api_format=self.allowed_api_formats[0],
|
api_format=client_api_format,
|
||||||
api_family=self.api_family,
|
api_family=self.api_family,
|
||||||
endpoint_kind=self.endpoint_kind,
|
endpoint_kind=self.endpoint_kind,
|
||||||
request_id=self.request_id,
|
request_id=self.request_id,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class CliSyncMixin:
|
|||||||
|
|
||||||
# 使用子类实现的方法提取 model(不同 API 格式的 model 位置不同)
|
# 使用子类实现的方法提取 model(不同 API 格式的 model 位置不同)
|
||||||
model = self.extract_model_from_request(original_request_body, path_params)
|
model = self.extract_model_from_request(original_request_body, path_params)
|
||||||
api_format = self.allowed_api_formats[0]
|
api_format = self.primary_api_format
|
||||||
sync_start_time = time.time()
|
sync_start_time = time.time()
|
||||||
|
|
||||||
# 提前创建 pending 记录,让前端可以立即看到"处理中"
|
# 提前创建 pending 记录,让前端可以立即看到"处理中"
|
||||||
@@ -86,7 +86,7 @@ class CliSyncMixin:
|
|||||||
model=model,
|
model=model,
|
||||||
is_stream=False,
|
is_stream=False,
|
||||||
request_type="chat",
|
request_type="chat",
|
||||||
api_format=self.FORMAT_ID,
|
api_format=api_format,
|
||||||
request_headers=original_headers,
|
request_headers=original_headers,
|
||||||
request_body=original_request_body,
|
request_body=original_request_body,
|
||||||
)
|
)
|
||||||
|
|||||||
74
tests/api/handlers/base/test_cli_pending_usage_format.py
Normal file
74
tests/api/handlers/base/test_cli_pending_usage_format.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from src.api.handlers.base.cli_stream_mixin import CliStreamMixin
|
||||||
|
from src.api.handlers.base.cli_sync_mixin import CliSyncMixin
|
||||||
|
|
||||||
|
|
||||||
|
class _StopExecution(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class _DummySyncHandler(CliSyncMixin):
|
||||||
|
FORMAT_ID = "openai:cli"
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.allowed_api_formats = ["openai:compact"]
|
||||||
|
self.primary_api_format = "openai:compact"
|
||||||
|
self.pending_calls: list[dict[str, object]] = []
|
||||||
|
|
||||||
|
def extract_model_from_request(
|
||||||
|
self, request_body: dict[str, object], path_params: dict[str, object] | None
|
||||||
|
) -> str:
|
||||||
|
return str(request_body.get("model") or "unknown")
|
||||||
|
|
||||||
|
def _create_pending_usage(self, **kwargs: object) -> None:
|
||||||
|
self.pending_calls.append(kwargs)
|
||||||
|
raise _StopExecution()
|
||||||
|
|
||||||
|
|
||||||
|
class _DummyStreamHandler(CliStreamMixin):
|
||||||
|
FORMAT_ID = "openai:cli"
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.allowed_api_formats = ["openai:compact"]
|
||||||
|
self.primary_api_format = "openai:compact"
|
||||||
|
self.pending_calls: list[dict[str, object]] = []
|
||||||
|
|
||||||
|
def extract_model_from_request(
|
||||||
|
self, request_body: dict[str, object], path_params: dict[str, object] | None
|
||||||
|
) -> str:
|
||||||
|
return str(request_body.get("model") or "unknown")
|
||||||
|
|
||||||
|
def _create_pending_usage(self, **kwargs: object) -> None:
|
||||||
|
self.pending_calls.append(kwargs)
|
||||||
|
raise _StopExecution()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_sync_pending_usage_uses_primary_api_format() -> None:
|
||||||
|
handler = _DummySyncHandler()
|
||||||
|
|
||||||
|
with pytest.raises(_StopExecution):
|
||||||
|
await handler.process_sync( # type: ignore[misc]
|
||||||
|
original_request_body={"model": "gpt-5.3-codex"},
|
||||||
|
original_headers={},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert handler.pending_calls
|
||||||
|
assert handler.pending_calls[0]["api_format"] == "openai:compact"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_stream_pending_usage_uses_primary_api_format() -> None:
|
||||||
|
handler = _DummyStreamHandler()
|
||||||
|
|
||||||
|
with pytest.raises(_StopExecution):
|
||||||
|
await handler.process_stream( # type: ignore[misc]
|
||||||
|
original_request_body={"model": "gpt-5.3-codex"},
|
||||||
|
original_headers={},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert handler.pending_calls
|
||||||
|
assert handler.pending_calls[0]["api_format"] == "openai:compact"
|
||||||
Reference in New Issue
Block a user