From e7d9e0adce17c854e13694e025c977bd1afaaf3e Mon Sep 17 00:00:00 2001 From: Yuichiro Utsumi Date: Thu, 8 Jan 2026 05:14:14 +0000 Subject: [PATCH] fix: close `` block only when `reasoning_content` is None Signed-off-by: Yuichiro Utsumi --- .../interfaces/model/large_language_model.py | 5 ++--- .../tests/interfaces/model/test_wrap_think.py | 21 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/python/dify_plugin/interfaces/model/large_language_model.py b/python/dify_plugin/interfaces/model/large_language_model.py index e239b37a..5f50d8ad 100644 --- a/python/dify_plugin/interfaces/model/large_language_model.py +++ b/python/dify_plugin/interfaces/model/large_language_model.py @@ -537,7 +537,7 @@ def _wrap_thinking_by_reasoning_content(self, delta: dict, is_reasoning: bool) - content = delta.get("content") or "" reasoning_content = delta.get("reasoning_content") output = content - if reasoning_content: + if reasoning_content is not None: if not is_reasoning: output = "\n" + reasoning_content is_reasoning = True @@ -546,8 +546,7 @@ def _wrap_thinking_by_reasoning_content(self, delta: dict, is_reasoning: bool) - else: if is_reasoning: is_reasoning = False - if not reasoning_content: - output = "\n" + output = "\n" if content: output += content diff --git a/python/tests/interfaces/model/test_wrap_think.py b/python/tests/interfaces/model/test_wrap_think.py index 9264ca75..1bb932a5 100644 --- a/python/tests/interfaces/model/test_wrap_think.py +++ b/python/tests/interfaces/model/test_wrap_think.py @@ -62,12 +62,16 @@ def test_wrap_thinking_logic_closure(self): chunks = [ # Chunk 1: Thinking started {"reasoning_content": "Thinking started.", "content": ""}, - # Chunk 2: Still thinking - {"reasoning_content": " Still thinking.", "content": ""}, - # Chunk 3: Thinking ended, transitioned to Tool Call (reasoning_content=None, content=None/Empty) + # Chunk 2: Still thinking #1 + {"reasoning_content": " Still thinking #1.", "content": ""}, + # Chunk 3: Still thinking (reasoning_content=Empty) + {"reasoning_content": "", "content": ""}, + # Chunk 4: Still thinking #2 + {"reasoning_content": " Still thinking #2.", "content": ""}, + # Chunk 5: Thinking ended, transitioned to Tool Call (reasoning_content=None, content=None/Empty) # This is a critical point, old logic would fail here because content is empty {"reasoning_content": None, "content": "", "tool_calls": [{"id": "call_1", "function": {}}]}, - # Chunk 4: Subsequent tool parameter stream + # Chunk 6: Subsequent tool parameter stream {"reasoning_content": None, "content": "", "tool_calls": [{"function": {"arguments": "{"}}]}, ] @@ -86,13 +90,8 @@ def test_wrap_thinking_logic_closure(self): # Verify results print(f"DEBUG Output: {full_output!r}") - assert "" in full_output - assert "Thinking started. Still thinking." in full_output - assert "" in full_output, "Should verify tag is closed properly" - - # Verify the position of the closing tag: should be after the thinking content - expected_part = "Thinking started. Still thinking.\n" - assert expected_part in full_output + expected_output = "\nThinking started. Still thinking #1. Still thinking #2.\n" + self.assertEqual(full_output, expected_output) def test_standard_reasoning_flow(self): """Test standard reasoning -> text flow"""