refactor: unify system tools as resources

This commit is contained in:
Xin Wang
2026-08-04 17:05:26 +08:00
parent d1b05f16c7
commit 74a8be2357
26 changed files with 788 additions and 507 deletions

View File

@@ -17,6 +17,7 @@ from schemas import AssistantOut, AssistantUpsert
from services.auth import require_admin
from services.masking import mask, resolve_incoming_key
from services.node_specs import graph_references, normalize_graph, validate_graph
from services.system_tools import system_tool_kind
from services.tool_policy import policy_for_tool
from services.workflow_engine import WorkflowEngine
from sqlalchemy import select
@@ -58,13 +59,6 @@ def _validate_workflow(body: AssistantUpsert) -> None:
f"Agent 节点 {node_id} 授权了未声明变量:"
+ ",".join(unknown)
)
if (
"update_state" in (data.get("systemTools") or [])
and not authorized
):
errors.append(
f"Agent 节点 {node_id} 启用更新状态工具时必须授权至少一个变量"
)
if errors:
raise HTTPException(400, "工作流校验失败:" + ";".join(errors))
# Graph settings are the source of truth. The flat flag is only a session
@@ -141,6 +135,60 @@ async def _validate_workflow_references(
raise HTTPException(400, f"Workflow 引用了无效知识库:{knowledge_id}")
async def _validate_system_tool_selection(
session: AsyncSession,
body: AssistantUpsert,
) -> None:
"""Validate System resources in the same selection path as every other tool."""
selected_ids = list(dict.fromkeys(body.tool_ids))
if not selected_ids or body.type not in {"prompt", "workflow"}:
return
rows = (
await session.execute(select(Tool).where(Tool.id.in_(selected_ids)))
).scalars().all()
tools_by_id = {tool.id: tool for tool in rows if tool.status == "active"}
system_kinds = {
tool.id: system_tool_kind(tool.definition or {})
for tool in rows
if tool.status == "active" and tool.type == "system"
}
invalid = [tool_id for tool_id, kind in system_kinds.items() if kind is None]
if invalid:
raise HTTPException(400, "系统工具配置无效: " + ", ".join(invalid))
if body.type == "prompt":
if body.runtime_mode == "realtime" and system_kinds:
raise HTTPException(400, "Prompt Realtime 模式暂不支持系统工具")
if (
"update_state" in system_kinds.values()
and not body.dynamic_variable_definitions
):
raise HTTPException(400, "启用更新状态工具前必须声明至少一个动态变量")
return
engine = WorkflowEngine(body.graph)
for node_id, node in engine.nodes.items():
node_type = node.get("type")
data = node.get("data") or {}
if node_type == "agent":
stage = engine.agent_stage_config(node_id)
kinds = {
system_kinds[tool_id]
for tool_id in stage.tool_ids
if tool_id in system_kinds
}
if "update_state" in kinds and not stage.state_variable_names:
raise HTTPException(
400,
f"Agent 节点 {node_id} 启用更新状态工具时必须授权至少一个变量",
)
elif node_type == "action":
tool_id = str(data.get("toolId") or "")
tool = tools_by_id.get(tool_id)
if tool and tool.type == "system":
raise HTTPException(400, f"Action 节点 {node_id} 不能调用系统工具")
async def _validate_startup_actions(
session: AsyncSession,
body: AssistantUpsert,
@@ -312,7 +360,6 @@ async def _to_out(session: AsyncSession, assistant: Assistant) -> AssistantOut:
enable_interrupt=assistant.enable_interrupt,
turn_config=assistant.turn_config or {},
startup=assistant.startup or {},
system_tools=assistant.system_tools or [],
vision_enabled=assistant.vision_enabled,
vision_model_resource_id=assistant.vision_model_resource_id,
model_resource_ids=await _resource_ids(session, assistant.id),
@@ -347,6 +394,7 @@ async def create_assistant(
):
_validate_workflow(body)
await _validate_workflow_references(session, body)
await _validate_system_tool_selection(session, body)
await _validate_startup_actions(session, body)
await _validate_vision_model(session, body)
await _validate_knowledge_base(session, body)
@@ -389,7 +437,6 @@ async def duplicate_assistant(
enable_interrupt=source.enable_interrupt,
turn_config=dict(source.turn_config or {}),
startup=dict(source.startup or {}),
system_tools=list(source.system_tools or []),
vision_enabled=source.vision_enabled,
vision_model_resource_id=source.vision_model_resource_id,
knowledge_base_id=source.knowledge_base_id,
@@ -423,6 +470,7 @@ async def update_assistant(
raise HTTPException(404, "助手不存在")
_validate_workflow(body)
await _validate_workflow_references(session, body)
await _validate_system_tool_selection(session, body)
await _validate_startup_actions(session, body)
await _validate_vision_model(session, body)
await _validate_knowledge_base(session, body)