|
|
|
|
@ -662,3 +662,153 @@ class TestSaveMultimodalOutputAndConvertResultToMarkdown:
|
|
|
|
|
assert list(gen) == []
|
|
|
|
|
mock_file_saver.save_binary_string.assert_not_called()
|
|
|
|
|
mock_file_saver.save_remote_url.assert_not_called()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestThinkingTagsRemoval:
|
|
|
|
|
"""Test cases for thinking tags removal functionality in LLM Node."""
|
|
|
|
|
|
|
|
|
|
def test_remove_single_thinking_tag(self, llm_node):
|
|
|
|
|
"""Test removal of single thinking tag block."""
|
|
|
|
|
input_text = "<think>This is my thinking process</think>Hello, how can I help you?"
|
|
|
|
|
expected = "Hello, how can I help you?"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_remove_multiple_thinking_tags(self, llm_node):
|
|
|
|
|
"""Test removal of multiple thinking tag blocks."""
|
|
|
|
|
input_text = "<think>First thought</think>Hello<think>Second thought</think> World!"
|
|
|
|
|
expected = "Hello World!"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_remove_multiline_thinking_tag(self, llm_node):
|
|
|
|
|
"""Test removal of multiline thinking tag blocks."""
|
|
|
|
|
input_text = """<think>
|
|
|
|
|
This is a multiline
|
|
|
|
|
thinking process
|
|
|
|
|
with multiple lines
|
|
|
|
|
</think>Final answer here."""
|
|
|
|
|
expected = "Final answer here."
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_case_insensitive_removal(self, llm_node):
|
|
|
|
|
"""Test case-insensitive thinking tag removal."""
|
|
|
|
|
input_text = "<THINK>Uppercase thinking</THINK>Response"
|
|
|
|
|
expected = "Response"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_mixed_case_removal(self, llm_node):
|
|
|
|
|
"""Test mixed case thinking tag removal."""
|
|
|
|
|
input_text = "<Think>Mixed case thinking</Think>Response"
|
|
|
|
|
expected = "Response"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_no_thinking_tags(self, llm_node):
|
|
|
|
|
"""Test text without thinking tags remains unchanged."""
|
|
|
|
|
input_text = "Hello, this is a normal response without thinking tags."
|
|
|
|
|
expected = input_text
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_empty_string(self, llm_node):
|
|
|
|
|
"""Test empty string handling."""
|
|
|
|
|
input_text = ""
|
|
|
|
|
expected = ""
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_only_thinking_tag(self, llm_node):
|
|
|
|
|
"""Test string with only thinking tag."""
|
|
|
|
|
input_text = "<think>Only thinking, no response</think>"
|
|
|
|
|
expected = ""
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_whitespace_handling(self, llm_node):
|
|
|
|
|
"""Test proper whitespace handling after tag removal."""
|
|
|
|
|
input_text = "<think>Thinking</think> Response with spaces"
|
|
|
|
|
expected = "Response with spaces"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_whitespace_after_tag(self, llm_node):
|
|
|
|
|
"""Test whitespace removal after thinking tags."""
|
|
|
|
|
input_text = "<think>Thinking</think> \n \t Final response"
|
|
|
|
|
expected = "Final response"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_none_input(self, llm_node):
|
|
|
|
|
"""Test None input handling."""
|
|
|
|
|
result = llm_node._remove_thinking_tags(None)
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
def test_non_string_input(self, llm_node):
|
|
|
|
|
"""Test non-string input handling."""
|
|
|
|
|
result = llm_node._remove_thinking_tags(123)
|
|
|
|
|
assert result == 123
|
|
|
|
|
|
|
|
|
|
def test_complex_real_world_example(self, llm_node):
|
|
|
|
|
"""Test with a complex real-world example from DeepSeek-R1."""
|
|
|
|
|
input_text = """<think>
|
|
|
|
|
|
|
|
|
|
Okay, let me try to figure out what the user is asking here. The message is just "gdgd".
|
|
|
|
|
That's pretty short and doesn't make much sense on its own. I need to consider different
|
|
|
|
|
possibilities.
|
|
|
|
|
|
|
|
|
|
First, maybe it's a typo or a shorthand. "GDGD" could be an acronym. Let me think about
|
|
|
|
|
common acronyms. "GDGD" might stand for "Good Good Good Good" but that seems unlikely.
|
|
|
|
|
|
|
|
|
|
</think>It looks like your message might be incomplete or unclear. Could you please provide
|
|
|
|
|
more context or rephrase your question? I'm here to help!"""
|
|
|
|
|
|
|
|
|
|
expected = (
|
|
|
|
|
"It looks like your message might be incomplete or unclear. Could you please "
|
|
|
|
|
"provide more context or rephrase your question? I'm here to help!"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
def test_multiple_whitespace_tags(self, llm_node):
|
|
|
|
|
"""Test multiple thinking tags with various whitespace."""
|
|
|
|
|
input_text = "<think>First</think> \n<think>Second</think> Final"
|
|
|
|
|
expected = "Final"
|
|
|
|
|
|
|
|
|
|
result = llm_node._remove_thinking_tags(input_text)
|
|
|
|
|
assert result == expected
|
|
|
|
|
|
|
|
|
|
@mock.patch.dict("os.environ", {"LLM_NODE_THINKING_TAGS_ENABLED": "true"})
|
|
|
|
|
def test_environment_variable_enabled(self):
|
|
|
|
|
"""Test that environment variable is properly read when enabled."""
|
|
|
|
|
from core.workflow.nodes.llm.node import LLM_NODE_THINKING_TAGS_ENABLED
|
|
|
|
|
assert LLM_NODE_THINKING_TAGS_ENABLED is True
|
|
|
|
|
|
|
|
|
|
@mock.patch.dict("os.environ", {"LLM_NODE_THINKING_TAGS_ENABLED": "false"})
|
|
|
|
|
def test_environment_variable_disabled(self):
|
|
|
|
|
"""Test that environment variable is properly read when disabled."""
|
|
|
|
|
# Need to reimport to get the updated value
|
|
|
|
|
import importlib
|
|
|
|
|
import core.workflow.nodes.llm.node
|
|
|
|
|
importlib.reload(core.workflow.nodes.llm.node)
|
|
|
|
|
from core.workflow.nodes.llm.node import LLM_NODE_THINKING_TAGS_ENABLED
|
|
|
|
|
assert LLM_NODE_THINKING_TAGS_ENABLED is False
|
|
|
|
|
|
|
|
|
|
def test_environment_variable_default(self):
|
|
|
|
|
"""Test that environment variable defaults to True."""
|
|
|
|
|
from core.workflow.nodes.llm.node import LLM_NODE_THINKING_TAGS_ENABLED
|
|
|
|
|
# Default should be True for backward compatibility
|
|
|
|
|
assert LLM_NODE_THINKING_TAGS_ENABLED is True
|
|
|
|
|
|