Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions python/dify_plugin/interfaces/model/large_language_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<think>\n" + reasoning_content
is_reasoning = True
Expand All @@ -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</think>"
output = "\n</think>"
if content:
output += content

Expand Down
21 changes: 10 additions & 11 deletions python/tests/interfaces/model/test_wrap_think.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": "{"}}]},
]

Expand All @@ -86,13 +90,8 @@ def test_wrap_thinking_logic_closure(self):
# Verify results
print(f"DEBUG Output: {full_output!r}")

assert "<think>" in full_output
assert "Thinking started. Still thinking." in full_output
assert "</think>" in full_output, "Should verify <think> tag is closed properly"

# Verify the position of the closing tag: should be after the thinking content
expected_part = "Thinking started. Still thinking.\n</think>"
assert expected_part in full_output
expected_output = "<think>\nThinking started. Still thinking #1. Still thinking #2.\n</think>"
self.assertEqual(full_output, expected_output)

def test_standard_reasoning_flow(self):
"""Test standard reasoning -> text flow"""
Expand Down