Add workflow support and enhance runtime configuration in models and services

- Introduce RuntimeModelResource and RuntimeKnowledgeBase classes to manage workflow resources.
- Update AssistantConfig to include workflow_model_resources and workflow_knowledge_bases for better integration.
- Refactor validation and processing logic in routes and services to accommodate workflow types.
- Implement dynamic variable support for workflow assistants and enhance graph normalization.
- Add ToolExecutor for reusable tool execution across different assistant types.
- Update various services to ensure compatibility with new workflow features and improve error handling.
This commit is contained in:
Xin Wang
2026-07-13 16:13:27 +08:00
parent 6108b00007
commit 32aef14ddb
27 changed files with 2563 additions and 910 deletions

View File

@@ -12,7 +12,13 @@ from db.models import (
ModelResource,
Tool,
)
from models import AssistantConfig, RuntimeTool
from models import (
AssistantConfig,
RuntimeKnowledgeBase,
RuntimeModelResource,
RuntimeTool,
)
from services.node_specs import graph_references, normalize_graph
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -83,7 +89,7 @@ def _secret(resource: ModelResource | None, key: str, default: str = "") -> str:
async def _tools_for(session: AsyncSession, assistant: Assistant) -> list[RuntimeTool]:
if assistant.type != "prompt":
if assistant.type not in {"prompt", "workflow"}:
return []
tools = (
await session.execute(
@@ -134,6 +140,43 @@ async def resolve_runtime_config(
else None
)
graph = normalize_graph(assistant.graph or {}) if assistant.type == "workflow" else {}
refs = graph_references(graph) if graph else {
"model_resources": set(),
"knowledge_bases": set(),
}
workflow_resources: dict[str, RuntimeModelResource] = {}
if refs["model_resources"]:
resources = (
await session.execute(
select(ModelResource).where(ModelResource.id.in_(refs["model_resources"]))
)
).scalars().all()
workflow_resources = {
resource.id: RuntimeModelResource(
id=resource.id,
name=resource.name,
capability=resource.capability,
interface_type=resource.interface_type,
values=resource.values or {},
secrets=resource.secrets or {},
)
for resource in resources
if resource.enabled
}
workflow_knowledge: dict[str, RuntimeKnowledgeBase] = {}
if refs["knowledge_bases"]:
knowledge_rows = (
await session.execute(
select(KnowledgeBase).where(KnowledgeBase.id.in_(refs["knowledge_bases"]))
)
).scalars().all()
workflow_knowledge = {
kb.id: RuntimeKnowledgeBase(id=kb.id, name=kb.name, description=kb.description)
for kb in knowledge_rows
if kb.status == "active"
}
return AssistantConfig(
name=assistant.name,
type=assistant.type,
@@ -150,7 +193,9 @@ async def resolve_runtime_config(
knowledge_base_description=knowledge_base.description if knowledge_base else "",
knowledge_retrieval_config=assistant.knowledge_retrieval_config or {},
# workflow 图:仅 workflow 类型非空,引擎据此启用图驱动对话
graph=(assistant.graph or {}) if assistant.type == "workflow" else {},
graph=graph,
workflow_model_resources=workflow_resources,
workflow_knowledge_bases=workflow_knowledge,
# 外部托管类型连接信息(DB 存真 key,直接注入)
dify_api_url=str(_value(agent_resource, "apiUrl", assistant.api_url)),
dify_api_key=_secret(agent_resource, "apiKey", assistant.api_key),