mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
fix(conversion): 修复 openai cli tool 调用空 call_id 导致上游失败
- 在 FormatConversionRegistry.convert_request 前统一修复 InternalRequest 中空的 tool_id/tool_use_id - 为空 ID 自动生成 call_auto_N,并将 tool_result 关联到最近待匹配的 tool_call - 修正 OpenAICliNormalizer 中 function_call_output 的内部角色为 USER,确保输出 openai:chat 时保留 tool_call_id - 新增 openai:cli <-> openai:chat 空 call_id 回归测试,覆盖工具调用关联场景
This commit is contained in:
@@ -1054,7 +1054,7 @@ class OpenAICliNormalizer(FormatNormalizer):
|
||||
content_text=content_text,
|
||||
extra={"openai_cli": self._extract_extra(item, {"type", "call_id", "id", "output"})},
|
||||
)
|
||||
return InternalMessage(role=Role.TOOL, content=[result_block])
|
||||
return InternalMessage(role=Role.USER, content=[result_block])
|
||||
|
||||
def _parse_reasoning_item(self, item: dict[str, Any]) -> InternalMessage:
|
||||
summary_parts: list[str] = []
|
||||
|
||||
@@ -15,6 +15,7 @@ from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
from typing import Any
|
||||
|
||||
from src.core.api_format.conversion.internal import InternalRequest, ToolResultBlock, ToolUseBlock
|
||||
from src.core.api_format.conversion.exceptions import FormatConversionError
|
||||
from src.core.api_format.conversion.normalizer import FormatNormalizer
|
||||
from src.core.api_format.conversion.stream_state import StreamState
|
||||
@@ -60,6 +61,40 @@ class FormatConversionRegistry:
|
||||
raise FormatConversionError(format_id, format_id, f"未注册 Normalizer: {format_id}")
|
||||
return normalizer
|
||||
|
||||
def _repair_internal_tool_call_ids(self, internal: InternalRequest) -> None:
|
||||
"""修复 InternalRequest 中空的 tool id/tool_use_id,避免上游校验报错。"""
|
||||
|
||||
pending_tool_ids: list[str] = []
|
||||
auto_counter = 0
|
||||
|
||||
def next_tool_id() -> str:
|
||||
nonlocal auto_counter
|
||||
auto_counter += 1
|
||||
return f"call_auto_{auto_counter}"
|
||||
|
||||
for message in internal.messages:
|
||||
for block in message.content:
|
||||
if isinstance(block, ToolUseBlock):
|
||||
tool_id = str(block.tool_id or "").strip()
|
||||
if not tool_id:
|
||||
tool_id = next_tool_id()
|
||||
block.tool_id = tool_id
|
||||
pending_tool_ids.append(tool_id)
|
||||
continue
|
||||
|
||||
if isinstance(block, ToolResultBlock):
|
||||
tool_use_id = str(block.tool_use_id or "").strip()
|
||||
if tool_use_id:
|
||||
block.tool_use_id = tool_use_id
|
||||
if tool_use_id in pending_tool_ids:
|
||||
pending_tool_ids.remove(tool_use_id)
|
||||
continue
|
||||
|
||||
if pending_tool_ids:
|
||||
block.tool_use_id = pending_tool_ids.pop(0)
|
||||
else:
|
||||
block.tool_use_id = next_tool_id()
|
||||
|
||||
# ==================== 请求/响应转换(严格) ====================
|
||||
|
||||
def convert_request(
|
||||
@@ -81,6 +116,7 @@ class FormatConversionRegistry:
|
||||
):
|
||||
try:
|
||||
internal = src.request_to_internal(request)
|
||||
self._repair_internal_tool_call_ids(internal)
|
||||
return tgt.request_from_internal(internal, target_variant=target_variant)
|
||||
except Exception as e:
|
||||
raise FormatConversionError(source_format, target_format, str(e)) from e
|
||||
|
||||
Reference in New Issue
Block a user