From ac044eba3a6bf32ae597f94db30ffae5e90236e8 Mon Sep 17 00:00:00 2001 From: Chen <61995987@qq.com> Date: Mon, 16 Mar 2026 22:55:44 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=E5=85=BC=E5=AE=B9openai=E9=80=82?= =?UTF-8?q?=E9=85=8D=E5=99=A8=E7=9A=84=E9=9D=9E=E6=A0=87=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/provider/sources/openai_source.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index 2fae94e1a7..9500bdd9c1 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -307,6 +307,26 @@ async def _query_stream( state = ChatCompletionStreamState() async for chunk in stream: + # 兼容处理:部分非标准聚合平台(如通过newapi适配层转接的 Gemini)在流式返回 tool_calls 时, + # 可能会缺失 type 字段。由于 openai SDK 的 ChatCompletionStreamState.handle_chunk + # 内部有 assert tool.type == "function" 的断言,缺少该字段会导致 AssertionError。 + # 因此,若检测到 tool_call 且 type 为空,在此处手动补全为 "function"。 + for choice in chunk.choices or []: + if not choice.delta or not choice.delta.tool_calls: + continue + for tool_call in choice.delta.tool_calls: + # 使用 getattr 处理 type 字段可能完全缺失的情况 + tool_type = getattr(tool_call, "type", None) + if ( + tool_type is None or tool_type == "" + ) and tool_call.function is not None: + logger.debug( + f"[{self.get_model()}] tool_call.type is missing or empty in chunk {chunk_index} " + f"(provider: {self.provider_config.get('id', 'unknown')}), " + f"manually set to 'function'" + ) + tool_call.type = "function" + chunk_index += 1 try: state.handle_chunk(chunk) except Exception as e: From e68db90c4d39dbd27899d831db722e59ea9feead Mon Sep 17 00:00:00 2001 From: Chen <61995987@qq.com> Date: Mon, 16 Mar 2026 22:57:39 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=E8=A1=A5=E5=85=85=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84chunk=5Findex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astrbot/core/provider/sources/openai_source.py | 1 + 1 file changed, 1 insertion(+) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index 9500bdd9c1..ade59407b3 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -306,6 +306,7 @@ async def _query_stream( state = ChatCompletionStreamState() + chunk_index = 0 async for chunk in stream: # 兼容处理:部分非标准聚合平台(如通过newapi适配层转接的 Gemini)在流式返回 tool_calls 时, # 可能会缺失 type 字段。由于 openai SDK 的 ChatCompletionStreamState.handle_chunk From e7e67639b60e9df9f7a3b688921ad01745d8488f Mon Sep 17 00:00:00 2001 From: Chen <61995987@qq.com> Date: Mon, 16 Mar 2026 23:14:12 +0800 Subject: [PATCH 3/3] ruff --- astrbot/core/provider/sources/openai_source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index ade59407b3..c26a41ff8d 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -311,7 +311,7 @@ async def _query_stream( # 兼容处理:部分非标准聚合平台(如通过newapi适配层转接的 Gemini)在流式返回 tool_calls 时, # 可能会缺失 type 字段。由于 openai SDK 的 ChatCompletionStreamState.handle_chunk # 内部有 assert tool.type == "function" 的断言,缺少该字段会导致 AssertionError。 - # 因此,若检测到 tool_call 且 type 为空,在此处手动补全为 "function"。 + # 因此,若检测到 tool_call 且 type 为空,在此处手动补全为 "function" for choice in chunk.choices or []: if not choice.delta or not choice.delta.tool_calls: continue