fix: resolve CI failures for Python style, DB migration, and unit tests

- Fix type errors in dify_graph/nodes/agent/agent_node.py:
  - Add missing user_id param to get_agent_tool_runtime call
  - Use create_plugin_provider_manager instead of bare ProviderManager()
  - Pass provider_manager to ModelManager constructor
  - Add access_controller param to file_factory.build_from_mapping
  - Fix return type annotation for _fetch_memory
- Fix DB migration chain: update workflow_comments migration to point
  to correct parent after sandbox migration removal
- Fix test_app_generate_service: set AGENT_V2_TRANSPARENT_UPGRADE=False
  in mock config to prevent transparent upgrade intercepting test flow
- Fix test_app_generator: add scalar method to mock db.session
- Fix test_app_models: add AppMode.AGENT to expected modes set
- Remove unnecessary db.session.close() from agent_chat app_runner

Made-with: Cursor
This commit is contained in:
Yansong Zhang 2026-04-13 15:07:16 +08:00
parent b804c7ed47
commit 971828615e
6 changed files with 28 additions and 20 deletions

View File

@ -189,7 +189,6 @@ class AgentChatAppRunner(AppRunner):
message_result = db.session.scalar(msg_stmt)
if message_result is None:
raise ValueError("Message not found")
db.session.close()
runner = AgentAppRunner(
tenant_id=app_config.tenant_id,

View File

@ -16,7 +16,7 @@ from core.memory.node_token_buffer_memory import NodeTokenBufferMemory
from core.memory.token_buffer_memory import TokenBufferMemory
from core.model_manager import ModelInstance, ModelManager
from core.prompt.entities.advanced_prompt_entities import MemoryMode
from core.provider_manager import ProviderManager
from core.plugin.impl.model_runtime_factory import create_plugin_provider_manager
from core.tools.entities.tool_entities import (
ToolIdentity,
ToolInvokeMessage,
@ -63,9 +63,12 @@ from graphon.nodes.base.node import Node
from graphon.nodes.base.variable_template_parser import VariableTemplateParser
from graphon.runtime import VariablePool
from graphon.variables.segments import ArrayFileSegment, StringSegment
from core.app.file_access.controller import DatabaseFileAccessController
from extensions.ext_database import db
from factories import file_factory
from factories.agent_factory import get_plugin_agent_strategy
_file_access_controller = DatabaseFileAccessController()
from models import ToolFile
from models.model import Conversation
from services.tools.builtin_tools_manage_service import BuiltinToolManageService
@ -303,6 +306,7 @@ class AgentNode(Node[AgentNodeData]):
dify_ctx.tenant_id,
dify_ctx.app_id,
entity,
dify_ctx.user_id,
dify_ctx.invoke_from,
runtime_variable_pool,
)
@ -428,7 +432,7 @@ class AgentNode(Node[AgentNodeData]):
icon = None
return icon
def _fetch_memory(self, model_instance: ModelInstance) -> BaseMemory | None:
def _fetch_memory(self, model_instance: ModelInstance) -> BaseMemory | TokenBufferMemory | None:
"""
Fetch memory based on configuration mode.
@ -470,7 +474,9 @@ class AgentNode(Node[AgentNodeData]):
def _fetch_model(self, value: dict[str, Any]) -> tuple[ModelInstance, AIModelEntity | None]:
dify_ctx = self.require_dify_context()
provider_manager = ProviderManager()
provider_manager = create_plugin_provider_manager(
tenant_id=dify_ctx.tenant_id, user_id=dify_ctx.user_id
)
provider_model_bundle = provider_manager.get_provider_model_bundle(
tenant_id=dify_ctx.tenant_id, provider=value.get("provider", ""), model_type=ModelType.LLM
)
@ -480,7 +486,7 @@ class AgentNode(Node[AgentNodeData]):
)
provider_name = provider_model_bundle.configuration.provider.provider
model_type_instance = provider_model_bundle.model_type_instance
model_instance = ModelManager().get_model_instance(
model_instance = ModelManager(provider_manager).get_model_instance(
tenant_id=dify_ctx.tenant_id,
provider=provider_name,
model_type=ModelType(value.get("model_type", "")),
@ -516,7 +522,6 @@ class AgentNode(Node[AgentNodeData]):
Fetch memory instance for saving node memory.
This is a simplified version that doesn't require model_instance.
"""
from core.model_manager import ModelManager
from graphon.model_runtime.entities.model_entities import ModelType
node_data = self.node_data
@ -531,10 +536,9 @@ class AgentNode(Node[AgentNodeData]):
# Return appropriate memory type based on mode
if node_data.memory.mode == MemoryMode.NODE:
# For node memory, we need a model_instance for token counting
# Use a simple default model for this purpose
try:
model_instance = ModelManager().get_default_model_instance(
provider_manager = create_plugin_provider_manager(tenant_id=self.tenant_id)
model_instance = ModelManager(provider_manager).get_default_model_instance(
tenant_id=self.tenant_id,
model_type=ModelType.LLM,
)
@ -706,6 +710,7 @@ class AgentNode(Node[AgentNodeData]):
file = file_factory.build_from_mapping(
mapping=mapping,
tenant_id=tenant_id,
access_controller=_file_access_controller,
)
files.append(file)
elif message.type == ToolInvokeMessage.MessageType.BLOB:
@ -729,6 +734,7 @@ class AgentNode(Node[AgentNodeData]):
file_factory.build_from_mapping(
mapping=mapping,
tenant_id=tenant_id,
access_controller=_file_access_controller,
)
)
elif message.type == ToolInvokeMessage.MessageType.TEXT:

View File

@ -1,7 +1,7 @@
"""Add workflow comments table
Revision ID: 227822d22895
Revises: aab323465866
Revises: 6b5f9f8b1a2c
Create Date: 2026-02-09 17:26:15.255980
"""
@ -13,7 +13,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "227822d22895"
down_revision = "aab323465866"
down_revision = "6b5f9f8b1a2c"
branch_labels = None
depends_on = None

View File

@ -100,6 +100,8 @@ class TestAppGenerateService:
mock_dify_config.APP_MAX_ACTIVE_REQUESTS = 100
mock_dify_config.APP_DEFAULT_ACTIVE_REQUESTS = 100
mock_dify_config.APP_DAILY_RATE_LIMIT = 1000
mock_dify_config.AGENT_V2_TRANSPARENT_UPGRADE = False
mock_dify_config.AGENT_V2_REPLACES_LLM = False
mock_global_dify_config.BILLING_ENABLED = False
mock_global_dify_config.APP_MAX_ACTIVE_REQUESTS = 100

View File

@ -146,7 +146,7 @@ class TestAdvancedChatAppGeneratorInternals:
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.sessionmaker", lambda **kwargs: SimpleNamespace()
@ -576,7 +576,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.Session", _Session)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
with pytest.raises(ValueError, match="Workflow not found"):
@ -640,7 +640,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.Session", _Session)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
with pytest.raises(ValueError, match="App not found"):
@ -713,7 +713,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.AdvancedChatAppRunner", _Runner)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
generator._generate_worker(
@ -797,7 +797,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.AdvancedChatAppRunner", _Runner)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
generator._generate_worker(
@ -878,7 +878,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.dify_config", SimpleNamespace(DEBUG=True))
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
generator._generate_worker(
@ -1069,7 +1069,7 @@ class TestAdvancedChatAppGeneratorInternals:
monkeypatch.setattr("core.app.apps.advanced_chat.app_generator.Session", _Session)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
generator._generate_worker(
@ -1131,7 +1131,7 @@ class TestAdvancedChatAppGeneratorInternals:
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.sessionmaker",
@ -1210,7 +1210,7 @@ class TestAdvancedChatAppGeneratorInternals:
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.db",
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None)),
SimpleNamespace(engine=object(), session=SimpleNamespace(close=lambda: None, scalar=lambda *a, **kw: None)),
)
monkeypatch.setattr(
"core.app.apps.advanced_chat.app_generator.sessionmaker",

View File

@ -97,6 +97,7 @@ class TestAppModelValidation:
"workflow",
"advanced-chat",
"agent-chat",
"agent",
"channel",
"rag-pipeline",
}