Merge branch 'feat/queue-based-graph-engine' into feat/rag-2

This commit is contained in:
-LAN-
2025-09-08 14:30:43 +08:00
828 changed files with 7240 additions and 2951 deletions

View File

@ -23,7 +23,7 @@ class TestWorkflowResponseConverterFetchFilesFromVariableValue:
storage_key="storage_key_123",
)
def create_file_dict(self, file_id: str = "test_file_dict") -> dict:
def create_file_dict(self, file_id: str = "test_file_dict"):
"""Create a file dictionary with correct dify_model_identity"""
return {
"dify_model_identity": FILE_MODEL_IDENTITY,

View File

@ -83,7 +83,7 @@ def test_client_session_initialize():
# Create message handler
def message_handler(
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
):
if isinstance(message, Exception):
raise message

View File

@ -26,14 +26,13 @@ def _gen_id():
class TestFileSaverImpl:
def test_save_binary_string(self, monkeypatch):
def test_save_binary_string(self, monkeypatch: pytest.MonkeyPatch):
user_id = _gen_id()
tenant_id = _gen_id()
file_type = FileType.IMAGE
mime_type = "image/png"
mock_signed_url = "https://example.com/image.png"
mock_tool_file = ToolFile(
id=_gen_id(),
user_id=user_id,
tenant_id=tenant_id,
conversation_id=None,
@ -43,6 +42,7 @@ class TestFileSaverImpl:
name=f"{_gen_id()}.png",
size=len(_PNG_DATA),
)
mock_tool_file.id = _gen_id()
mocked_tool_file_manager = mock.MagicMock(spec=ToolFileManager)
mocked_engine = mock.MagicMock(spec=Engine)
@ -80,7 +80,7 @@ class TestFileSaverImpl:
)
mocked_sign_file.assert_called_once_with(mock_tool_file.id, ".png")
def test_save_remote_url_request_failed(self, monkeypatch):
def test_save_remote_url_request_failed(self, monkeypatch: pytest.MonkeyPatch):
_TEST_URL = "https://example.com/image.png"
mock_request = httpx.Request("GET", _TEST_URL)
mock_response = httpx.Response(
@ -99,7 +99,7 @@ class TestFileSaverImpl:
mock_get.assert_called_once_with(_TEST_URL)
assert exc.value.response.status_code == 401
def test_save_remote_url_success(self, monkeypatch):
def test_save_remote_url_success(self, monkeypatch: pytest.MonkeyPatch):
_TEST_URL = "https://example.com/image.png"
mime_type = "image/png"
user_id = _gen_id()
@ -115,7 +115,6 @@ class TestFileSaverImpl:
file_saver = FileSaverImpl(user_id=user_id, tenant_id=tenant_id)
mock_tool_file = ToolFile(
id=_gen_id(),
user_id=user_id,
tenant_id=tenant_id,
conversation_id=None,
@ -125,6 +124,7 @@ class TestFileSaverImpl:
name=f"{_gen_id()}.png",
size=len(_PNG_DATA),
)
mock_tool_file.id = _gen_id()
mock_get = mock.MagicMock(spec=ssrf_proxy.get, return_value=mock_response)
monkeypatch.setattr(ssrf_proxy, "get", mock_get)
mock_save_binary_string = mock.MagicMock(spec=file_saver.save_binary_string, return_value=mock_tool_file)

View File

@ -66,6 +66,7 @@ def llm_node_data() -> LLMNodeData:
detail=ImagePromptMessageContent.DETAIL.HIGH,
),
),
reasoning_format="tagged",
)
@ -676,3 +677,66 @@ class TestSaveMultimodalOutputAndConvertResultToMarkdown:
assert list(gen) == []
mock_file_saver.save_binary_string.assert_not_called()
mock_file_saver.save_remote_url.assert_not_called()
class TestReasoningFormat:
"""Test cases for reasoning_format functionality"""
def test_split_reasoning_separated_mode(self):
"""Test separated mode: tags are removed and content is extracted"""
text_with_think = """
<think>I need to explain what Dify is. It's an open source AI platform.
</think>Dify is an open source AI platform.
"""
clean_text, reasoning_content = LLMNode._split_reasoning(text_with_think, "separated")
assert clean_text == "Dify is an open source AI platform."
assert reasoning_content == "I need to explain what Dify is. It's an open source AI platform."
def test_split_reasoning_tagged_mode(self):
"""Test tagged mode: original text is preserved"""
text_with_think = """
<think>I need to explain what Dify is. It's an open source AI platform.
</think>Dify is an open source AI platform.
"""
clean_text, reasoning_content = LLMNode._split_reasoning(text_with_think, "tagged")
# Original text unchanged
assert clean_text == text_with_think
# Empty reasoning content in tagged mode
assert reasoning_content == ""
def test_split_reasoning_no_think_blocks(self):
"""Test behavior when no <think> tags are present"""
text_without_think = "This is a simple answer without any thinking blocks."
clean_text, reasoning_content = LLMNode._split_reasoning(text_without_think, "separated")
assert clean_text == text_without_think
assert reasoning_content == ""
def test_reasoning_format_default_value(self):
"""Test that reasoning_format defaults to 'tagged' for backward compatibility"""
node_data = LLMNodeData(
title="Test LLM",
model=ModelConfig(provider="openai", name="gpt-3.5-turbo", mode="chat", completion_params={}),
prompt_template=[],
context=ContextConfig(enabled=False),
)
assert node_data.reasoning_format == "tagged"
text_with_think = """
<think>I need to explain what Dify is. It's an open source AI platform.
</think>Dify is an open source AI platform.
"""
clean_text, reasoning_content = LLMNode._split_reasoning(text_with_think, node_data.reasoning_format)
assert clean_text == text_with_think
assert reasoning_content == ""

View File

@ -274,7 +274,7 @@ def test_array_file_contains_file_name():
assert result.outputs["result"] is True
def _get_test_conditions() -> list:
def _get_test_conditions():
conditions = [
# Test boolean "is" operator
{"comparison_operator": "is", "variable_selector": ["start", "bool_true"], "value": "true"},

View File

@ -362,7 +362,7 @@ class TestVariablePoolSerialization:
self._assert_pools_equal(reconstructed_dict, reconstructed_json)
# TODO: assert the data for file object...
def _assert_pools_equal(self, pool1: VariablePool, pool2: VariablePool) -> None:
def _assert_pools_equal(self, pool1: VariablePool, pool2: VariablePool):
"""Assert that two VariablePools contain equivalent data"""
# Compare system variables

View File

@ -41,6 +41,7 @@ class TestWorkflowEntryRedisChannel:
user_from=UserFrom.ACCOUNT,
invoke_from=InvokeFrom.DEBUGGER,
call_depth=0,
variable_pool=mock_variable_pool,
graph_runtime_state=mock_graph_runtime_state,
command_channel=redis_channel, # Provide Redis channel
)
@ -81,6 +82,7 @@ class TestWorkflowEntryRedisChannel:
user_from=UserFrom.ACCOUNT,
invoke_from=InvokeFrom.DEBUGGER,
call_depth=0,
variable_pool=mock_variable_pool,
graph_runtime_state=mock_graph_runtime_state,
command_channel=None, # No channel provided
)
@ -128,6 +130,7 @@ class TestWorkflowEntryRedisChannel:
user_from=UserFrom.ACCOUNT,
invoke_from=InvokeFrom.DEBUGGER,
call_depth=0,
variable_pool=mock_variable_pool,
graph_runtime_state=mock_graph_runtime_state,
command_channel=redis_channel,
)