From 96374d7f6a93cec2a0bd3950ac2eb2d0b6a15b1e Mon Sep 17 00:00:00 2001 From: Yansong Zhang <916125788@qq.com> Date: Thu, 9 Apr 2026 09:42:23 +0800 Subject: [PATCH] refactor(api): replace legacy agent runners with StrategyFactory in AgentChatAppRunner (Phase 4) Replace the hardcoded FunctionCallAgentRunner / CotChatAgentRunner / CotCompletionAgentRunner selection in AgentChatAppRunner with the new AgentAppRunner class that uses StrategyFactory from Phase 1. Before: AgentChatAppRunner manually selects FC/CoT runner class based on model features and LLM mode, then instantiates it directly. After: AgentChatAppRunner instantiates AgentAppRunner (from sandbox branch), which internally uses StrategyFactory.create_strategy() to auto-select the right strategy, and uses ToolInvokeHook for proper agent_invoke with file handling and thought persistence. This unifies the agent execution engine: both the new Agent V2 workflow node and the legacy agent-chat app now use the same StrategyFactory and AgentPattern implementations. Also fix: command and file_upload nodes use string node_type instead of BuiltinNodeTypes.COMMAND/FILE_UPLOAD (not in current graphon version). 46 tests pass. Flask starts successfully. Made-with: Cursor --- api/core/app/apps/agent_chat/app_runner.py | 24 +++------------------ api/core/workflow/nodes/command/node.py | 2 +- api/core/workflow/nodes/file_upload/node.py | 2 +- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/api/core/app/apps/agent_chat/app_runner.py b/api/core/app/apps/agent_chat/app_runner.py index a20d3f3c38..600010faf3 100644 --- a/api/core/app/apps/agent_chat/app_runner.py +++ b/api/core/app/apps/agent_chat/app_runner.py @@ -1,15 +1,12 @@ import logging from typing import cast -from graphon.model_runtime.entities.llm_entities import LLMMode -from graphon.model_runtime.entities.model_entities import ModelFeature, ModelPropertyKey +from graphon.model_runtime.entities.model_entities import ModelFeature from graphon.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel from sqlalchemy import select -from core.agent.cot_chat_agent_runner import CotChatAgentRunner -from core.agent.cot_completion_agent_runner import CotCompletionAgentRunner +from core.agent.agent_app_runner import AgentAppRunner from core.agent.entities import AgentEntity -from core.agent.fc_agent_runner import FunctionCallAgentRunner from core.app.apps.agent_chat.app_config_manager import AgentChatAppConfig from core.app.apps.base_app_queue_manager import AppQueueManager, PublishFrom from core.app.apps.base_app_runner import AppRunner @@ -194,22 +191,7 @@ class AgentChatAppRunner(AppRunner): raise ValueError("Message not found") db.session.close() - runner_cls: type[FunctionCallAgentRunner] | type[CotChatAgentRunner] | type[CotCompletionAgentRunner] - # start agent runner - if agent_entity.strategy == AgentEntity.Strategy.CHAIN_OF_THOUGHT: - # check LLM mode - if model_schema.model_properties.get(ModelPropertyKey.MODE) == LLMMode.CHAT: - runner_cls = CotChatAgentRunner - elif model_schema.model_properties.get(ModelPropertyKey.MODE) == LLMMode.COMPLETION: - runner_cls = CotCompletionAgentRunner - else: - raise ValueError(f"Invalid LLM mode: {model_schema.model_properties.get(ModelPropertyKey.MODE)}") - elif agent_entity.strategy == AgentEntity.Strategy.FUNCTION_CALLING: - runner_cls = FunctionCallAgentRunner - else: - raise ValueError(f"Invalid agent strategy: {agent_entity.strategy}") - - runner = runner_cls( + runner = AgentAppRunner( tenant_id=app_config.tenant_id, application_generate_entity=application_generate_entity, conversation=conversation_result, diff --git a/api/core/workflow/nodes/command/node.py b/api/core/workflow/nodes/command/node.py index a56c4870b5..f6c05e674c 100644 --- a/api/core/workflow/nodes/command/node.py +++ b/api/core/workflow/nodes/command/node.py @@ -22,7 +22,7 @@ COMMAND_NODE_TIMEOUT_SECONDS = 60 * 10 class CommandNode(Node[CommandNodeData]): - node_type = BuiltinNodeTypes.COMMAND + node_type = "command" def _render_template(self, template: str) -> str: parser = VariableTemplateParser(template=template) diff --git a/api/core/workflow/nodes/file_upload/node.py b/api/core/workflow/nodes/file_upload/node.py index 7742f1eb41..7994cec1c1 100644 --- a/api/core/workflow/nodes/file_upload/node.py +++ b/api/core/workflow/nodes/file_upload/node.py @@ -29,7 +29,7 @@ class FileUploadNode(Node[FileUploadNodeData]): files, it generates storage-backed presigned URLs and lets sandbox download directly. """ - node_type = BuiltinNodeTypes.FILE_UPLOAD + node_type = "file-upload" @classmethod def version(cls) -> str: