From a53a1ca49b15c037ef996dc0894f613337821b40 Mon Sep 17 00:00:00 2001 From: Jason <101583541+JasonOA888@users.noreply.github.com> Date: Mon, 9 Mar 2026 00:17:11 +0800 Subject: [PATCH] fix(provider): handle MiniMax ThinkingBlock when max_tokens reached (#5913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(provider): handle MiniMax ThinkingBlock when max_tokens reached Fixes #5912 Problem: MiniMax API returns ThinkingBlock when stop_reason='max_tokens', but AstrBot throws 'completion 无法解析' exception because both completion_text and tools_call_args are empty. Root cause: The validation logic didn't consider ThinkingBlock (reasoning_content) as valid content. Fix: When completion_text and tools_call_args are empty but reasoning_content is present, treat it as valid instead of throwing exception. This happens when the model thinks but runs out of tokens before generating the actual response. Impact: MiniMax models now work correctly when responses are truncated due to max_tokens limit. * refactor: address review feedback 1. Use getattr for safe stop_reason access (prevent AttributeError) 2. Use ValueError instead of generic Exception for better error handling Thanks @gemini-code-assist and @sourcery-ai for the review! * refactor: flatten nested if/else with guard clause Address Gemini Code Assist feedback: - Use guard clause for early return - Flattened nested conditional for better readability Logic unchanged, just cleaner code structure. * fix(provider): improve logging for ThinkingBlock completions in ProviderAnthropic --------- Co-authored-by: Soulter <905617992@qq.com> --- .../core/provider/sources/anthropic_source.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/astrbot/core/provider/sources/anthropic_source.py b/astrbot/core/provider/sources/anthropic_source.py index ec3c395a4..be70fdc74 100644 --- a/astrbot/core/provider/sources/anthropic_source.py +++ b/astrbot/core/provider/sources/anthropic_source.py @@ -276,9 +276,24 @@ class ProviderAnthropic(Provider): llm_response.id = completion.id llm_response.usage = self._extract_usage(completion.usage) - # TODO(Soulter): 处理 end_turn 情况 + # Handle cases where completion only contains ThinkingBlock (e.g., MiniMax max_tokens) + # When stop_reason='max_tokens', the model may return only thinking content + # This is valid and should not raise an exception if not llm_response.completion_text and not llm_response.tools_call_args: - raise Exception(f"Anthropic API 返回的 completion 无法解析:{completion}。") + # Guard clause: raise early if no valid content at all + if not llm_response.reasoning_content: + raise ValueError( + f"Anthropic API returned unparsable completion: " + f"no text, tool_use, or thinking content found. " + f"Completion: {completion}" + ) + + # We have reasoning content (ThinkingBlock) - this is valid + stop_reason = getattr(completion, "stop_reason", "unknown") + logger.debug( + f"Completion contains only ThinkingBlock (stop_reason={stop_reason})" + ) + llm_response.completion_text = "" # Ensure empty string, not None return llm_response