From 5e210326c2f0db370f8fdc0cd966274a99a7b304 Mon Sep 17 00:00:00 2001 From: Stable Genius <259448942+stablegenius49@users.noreply.github.com> Date: Thu, 12 Mar 2026 02:46:00 -0700 Subject: [PATCH] fix: accept reasoning-only OpenAI completions --- .../core/provider/sources/openai_source.py | 6 +++- tests/test_openai_source.py | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index adee24073d..f223b5300b 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -534,7 +534,11 @@ async def _parse_openai_completion( raise Exception( "API 返回的 completion 由于内容安全过滤被拒绝(非 AstrBot)。", ) - if llm_response.completion_text is None and not llm_response.tools_call_args: + if ( + llm_response.completion_text is None + and not llm_response.tools_call_args + and not llm_response.reasoning_content + ): logger.error(f"API 返回的 completion 无法解析:{completion}。") raise Exception(f"API 返回的 completion 无法解析:{completion}。") diff --git a/tests/test_openai_source.py b/tests/test_openai_source.py index 3172097c72..5afa458b46 100644 --- a/tests/test_openai_source.py +++ b/tests/test_openai_source.py @@ -198,6 +198,37 @@ def test_extract_error_text_candidates_truncates_long_response_text(): ) +@pytest.mark.asyncio +async def test_parse_openai_completion_accepts_reasoning_only_response(monkeypatch): + provider = _make_provider() + try: + completion = SimpleNamespace( + id="chatcmpl-test", + choices=[ + SimpleNamespace( + finish_reason="stop", + message=SimpleNamespace(content=None, tool_calls=[]), + ) + ], + usage=None, + ) + monkeypatch.setattr( + provider, + "_extract_reasoning_content", + lambda _completion: "我先思考一下这个问题", + ) + + llm_response = await provider._parse_openai_completion(completion, tools=None) + + assert llm_response.role == "assistant" + assert llm_response.completion_text is None + assert llm_response.reasoning_content == "我先思考一下这个问题" + assert llm_response.raw_completion is completion + assert llm_response.id == "chatcmpl-test" + finally: + await provider.terminate() + + @pytest.mark.asyncio async def test_handle_api_error_content_moderated_without_images_raises(): provider = _make_provider(