From d8218b748ab599e4d97075a0bd04b960fac79369 Mon Sep 17 00:00:00 2001 From: Abdelhadi Salmaoui Date: Wed, 25 Mar 2026 05:06:34 +0100 Subject: [PATCH] fix(llm): support 'reasoning' field from Ollama in streaming responses Ollama sends 'delta.reasoning' for Qwen3 models with thinking content, but the streaming code only checked for 'delta.reasoning_content' (used by vLLM/Qwen). This caused thinking content to be silently dropped during streaming. Use getattr() to check both field names, supporting both 'reasoning_content' (vLLM/Qwen) and 'reasoning' (Ollama) in both delta_stream and full accumulation modes. Fixes QwenLM/Qwen-Agent#789 --- qwen_agent/llm/oai.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/qwen_agent/llm/oai.py b/qwen_agent/llm/oai.py index 2498ef5d..1dbd10b1 100644 --- a/qwen_agent/llm/oai.py +++ b/qwen_agent/llm/oai.py @@ -108,26 +108,26 @@ def _chat_stream( if delta_stream: for chunk in response: if chunk.choices: - if hasattr(chunk.choices[0].delta, - 'reasoning_content') and chunk.choices[0].delta.reasoning_content: - yield [ - Message(role=ASSISTANT, - content='', - reasoning_content=chunk.choices[0].delta.reasoning_content) - ] - if hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content: - yield [Message(role=ASSISTANT, content=chunk.choices[0].delta.content)] + delta = chunk.choices[0].delta + # Support both 'reasoning_content' (vLLM/Qwen) and 'reasoning' (Ollama) fields + reasoning = getattr(delta, 'reasoning_content', None) or getattr(delta, 'reasoning', None) + if reasoning: + yield [Message(role=ASSISTANT, content='', reasoning_content=reasoning)] + if getattr(delta, 'content', None): + yield [Message(role=ASSISTANT, content=delta.content)] else: full_response = '' full_reasoning_content = '' full_tool_calls = [] for chunk in response: if chunk.choices: - if hasattr(chunk.choices[0].delta, - 'reasoning_content') and chunk.choices[0].delta.reasoning_content: - full_reasoning_content += chunk.choices[0].delta.reasoning_content - if hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content: - full_response += chunk.choices[0].delta.content + delta = chunk.choices[0].delta + # Support both 'reasoning_content' (vLLM/Qwen) and 'reasoning' (Ollama) fields + reasoning = getattr(delta, 'reasoning_content', None) or getattr(delta, 'reasoning', None) + if reasoning: + full_reasoning_content += reasoning + if getattr(delta, 'content', None): + full_response += delta.content if hasattr(chunk.choices[0].delta, 'tool_calls') and chunk.choices[0].delta.tool_calls: for tc in chunk.choices[0].delta.tool_calls: if full_tool_calls and (not tc.id or