F1: add reusable task backend resources and migrate task tools
This commit is contained in:
@@ -26,6 +26,7 @@ from services.state_expressions import StateExpressionError, validate_update_rul
|
||||
from services.system_tools import RESERVED_TOOL_NAMES
|
||||
from services.tool_policy import policy_for_tool
|
||||
from services.tool_executor import ToolExecutor
|
||||
from services.task_backend_resources import validate_backend_binding
|
||||
from services.workflow_engine import WorkflowEngine
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@@ -242,11 +243,12 @@ async def _validate_tool_bindings(
|
||||
missing = sorted(tool_ids - set(tools))
|
||||
if missing:
|
||||
raise HTTPException(400, "工具不存在或未启用: " + ", ".join(missing))
|
||||
task_tools = [tool for tool in tools.values() if tool.type == "task"]
|
||||
if task_tools and (body.type != "prompt" or body.runtime_mode != "pipeline"):
|
||||
raise HTTPException(400, "后台任务工具仅支持提示词 Pipeline")
|
||||
if len(task_tools) > 1:
|
||||
raise HTTPException(400, "每个助手最多绑定一个后台任务工具")
|
||||
if any(tool.type not in {"http", "mcp", "client"} for tool in tools.values()):
|
||||
for scope, raw in raw_bindings:
|
||||
tool = tools.get(raw.get("tool_id") or raw.get("toolId"))
|
||||
if scope.startswith(("Action ", "Startup ")) and tool and tool.type == "task":
|
||||
raise HTTPException(400, "任务后端不支持启动 Action")
|
||||
raise HTTPException(400, "普通工具仅支持 HTTP/MCP/Client;任务请配置任务后端")
|
||||
reserved = sorted(
|
||||
tool.function_name
|
||||
for tool in tools.values()
|
||||
@@ -287,10 +289,6 @@ async def _validate_tool_bindings(
|
||||
type=tool.type,
|
||||
definition=tool.definition or {},
|
||||
)
|
||||
if tool.type == "task" and binding.result_assignments:
|
||||
raise HTTPException(400, "后台任务结果通过任务通知返回,不支持结果变量映射")
|
||||
if tool.type == "task" and scope.startswith(("Action ", "Startup ")):
|
||||
raise HTTPException(400, "后台任务工具不支持启动 Action")
|
||||
properties, required = ToolExecutor.input_schema(runtime_tool)
|
||||
unknown = sorted(set(binding.argument_bindings) - set(properties))
|
||||
if unknown:
|
||||
@@ -506,6 +504,13 @@ async def _validate_knowledge_base(session: AsyncSession, body: AssistantUpsert)
|
||||
raise HTTPException(400, "知识库不存在")
|
||||
|
||||
|
||||
async def _validate_task_backend(session: AsyncSession, body: AssistantUpsert) -> None:
|
||||
try:
|
||||
await validate_backend_binding(session, body)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(400, str(exc)) from exc
|
||||
|
||||
|
||||
async def _sync_bindings(
|
||||
session: AsyncSession, assistant_id: str, resource_ids: dict[str, str]
|
||||
) -> None:
|
||||
@@ -641,6 +646,7 @@ async def _to_out(session: AsyncSession, assistant: Assistant) -> AssistantOut:
|
||||
else []
|
||||
),
|
||||
built_in_tools=assistant.built_in_tools or {},
|
||||
task_backend=getattr(assistant, "task_backend", None),
|
||||
prompt=assistant.prompt,
|
||||
dynamic_variable_definitions=assistant.dynamic_variable_definitions or {},
|
||||
analysis_config=assistant.analysis_config or {},
|
||||
@@ -681,6 +687,7 @@ async def create_assistant(
|
||||
await _validate_vision_model(session, body)
|
||||
await _validate_analysis_model(session, body)
|
||||
await _validate_knowledge_base(session, body)
|
||||
await _validate_task_backend(session, body)
|
||||
data = body.model_dump()
|
||||
resource_ids = data.pop("model_resource_ids")
|
||||
tool_bindings = body.tool_bindings
|
||||
@@ -721,6 +728,7 @@ async def duplicate_assistant(
|
||||
raise HTTPException(404, "助手不存在")
|
||||
if source.type not in SUPPORTED_ASSISTANT_TYPES:
|
||||
raise HTTPException(410, "该助手类型已下线")
|
||||
await _validate_task_backend(session, source)
|
||||
assistant = Assistant(
|
||||
id=f"asst_{uuid.uuid4().hex[:12]}",
|
||||
name=f"{source.name} 副本",
|
||||
@@ -739,6 +747,7 @@ async def duplicate_assistant(
|
||||
prompt=source.prompt,
|
||||
dynamic_variable_definitions=dict(source.dynamic_variable_definitions or {}),
|
||||
built_in_tools=dict(source.built_in_tools or {}),
|
||||
task_backend=dict(source.task_backend) if source.task_backend else None,
|
||||
analysis_config=dict(source.analysis_config or {}),
|
||||
api_url=source.api_url,
|
||||
api_key=source.api_key,
|
||||
@@ -780,6 +789,7 @@ async def update_assistant(
|
||||
await _validate_vision_model(session, body)
|
||||
await _validate_analysis_model(session, body)
|
||||
await _validate_knowledge_base(session, body)
|
||||
await _validate_task_backend(session, body)
|
||||
data = body.model_dump()
|
||||
resource_ids = data.pop("model_resource_ids")
|
||||
tool_bindings = body.tool_bindings
|
||||
|
||||
Reference in New Issue
Block a user