feat(workflow): 增加会话级多智能体任务规划运行能力

提交范围聚焦于工作流编排新增:新增 workflow_planning 路由与前后端运行入口(workflow_planning.py、workflow_proposal_planner.py、workflow_deep_research_adapter.py),支持基于会话的提案-规划-执行流程,满足任务驱动式多智能体协作。

完成网关层运行时适配:扩展 workflow_resource_checks、workflow_executor、workflow_runs、workflow_agent_runner 与依赖注入,新增/更新配置(config.yaml、workflow_config),并补充 lead_agent 路径与节点实现,确保 Planner 与普通工作流运行态衔接一致。

补齐持久化与建模:新增 workflow_planning 持久化模块与 MySQL migration(20260831_01_workflow_planning_sessions),注册 SQL 与模型、内存 store,并扩展错误/表达式/validator/节点语义以承载新会话态输入输出。

增强文档与测试:新增会话式多智能体编排中文说明、更新开发文档与 AGENTS 指南、补充 workflow_engine/workflow_runs 回归测试,提高新路径的行为可验证性;同时留存 seed 资产(workflow-planner)便于一体化部署。
This commit is contained in:
董宏凯 committed 2026-09-01 11:47:30 +08:00
1 parent ac92f29db1
commit 1706a24182
39 files changed
+4896 -81

No files matched your search

@@ -7,6 +7,7 @@ from typing import Any
from fastapi import APIRouter, HTTPException, Request
from app.gateway.deps import get_current_user, get_local_provider
from app.gateway.routers._workflow_planner_seed import WORKFLOW_PLANNER_AGENT_ID
from deerflow.config.app_config import get_app_config
from deerflow.persistence.workflows import WorkflowStore
from deerflow.workflows.schemas import ALL_NODE_TYPES
@@ -22,6 +23,8 @@ _NODE_META: dict[str, dict[str, str]] = {
"sql_read": {"label": "SQL 只读", "category": "data"},
"code": {"label": "代码", "category": "data"},
"transform": {"label": "模板/转换", "category": "data"},
"evidence_normalizer": {"label": "证据归一化", "category": "data"},
"deep_research_write": {"label": "深度研究报告", "category": "ai"},
"condition": {"label": "条件", "category": "control"},
"merge": {"label": "合并", "category": "control"},
"human_input": {"label": "人工介入", "category": "control"},
@@ -105,6 +108,14 @@ async def list_agent_resources(request: Request) -> dict[str, Any]:
rows = await agent_store.list_all()
else:
rows = []
# This is a control-plane agent. It plans candidates through the
# planning endpoint and must never appear as a draggable worker.
rows = [
row
for row in rows or []
if isinstance(row, dict)
and str(row.get("id") or row.get("agent_id") or "") != WORKFLOW_PLANNER_AGENT_ID
]
creator_names = await _resolve_creator_names({str(row["user_id"]) for row in rows or [] if row.get("user_id") is not None})
agent_ids = [str(row.get("id") or row.get("agent_id") or "") for row in rows or []]
extras_by_agent: dict[str, dict[str, Any]] = {}