feat(coordinator): 添加团队节点默认最大工具迭代次数配置
添加 DEFAULT_TEAM_NODE_MAX_TOOL_ITERATIONS 配置项以控制团队节点的最大工具迭代次数, 并修改 LocalAgentRunner 中的逻辑来使用此默认值当 envelope 中未指定时。 fix(runtime): 修复团队节点运行成功判断逻辑 更新运行成功判断条件,将 finish_reason 为 "max_tool_iterations_finalized" 的情况 视为运行失败,并添加对原始工具调用输出的检测,避免将其误判为成功完成。 feat(mcp): 添加团队工作流MCP工具类别支持 增加新的本地MCP工具类别 "team_workflow" 及其对应的工具创建功能, 为团队工作流提供本地工具支持。 refactor(engine): 调整AgentLoop最大工具迭代次数设置 将 AgentProfile 中的默认 max_tool_iterations 从 30 增加到 100, 同时移除 TaskExecutionPlanner 构造函数中的重复参数传递。 perf(mcp): 优化MCP连接管理避免重复连接 添加 mcp_connected 标志来跟踪MCP连接状态,确保 connect_all 只执行一次, 提高性能并避免不必要的重复连接。 refactor(skills): 移除技能团队模板相关功能 移除与技能团队模板相关的代码,包括解析、存储和处理逻辑, 简化技能记录结构和加载流程。 feat(process): 增强会话过程投影器功能 添加技能激活快照事件处理,改进团队运行完成消息显示, 并增强技能激活事件的时间戳记录功能。 refactor(tasks): 简化任务尝试编排器团队执行逻辑 移除团队执行相关代码,将所有任务统一按单步执行处理, 简化任务编排器的复杂度并提升执行效率。 fix(evidence): 修复节点证据评估中需求验证逻辑 更新节点证据评估逻辑,跳过自然语言证据需求的确定性验证, 只执行机器可读的需求验证,避免因自然语言需求导致的节点失败。
This commit is contained in:
261
app-instance/backend/beaver/team_workflows/mcp_tools.py
Normal file
261
app-instance/backend/beaver/team_workflows/mcp_tools.py
Normal file
@ -0,0 +1,261 @@
|
||||
"""MCP schema tools for local team workflow graph builders."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Callable
|
||||
|
||||
from beaver.coordinator.models import ExecutionGraph
|
||||
from beaver.tools.base import BaseTool, ToolContext, ToolResult, ToolSpec
|
||||
|
||||
from . import agent_rearrange, concurrent, graph, mixture_of_agents, sequential
|
||||
|
||||
GraphBuilder = Callable[..., ExecutionGraph]
|
||||
|
||||
|
||||
def create_team_workflow_tools() -> list[BaseTool]:
|
||||
return [
|
||||
TeamWorkflowSchemaTool(
|
||||
name="SequentialWorkflow",
|
||||
description=(
|
||||
"Build a sequential Beaver team workflow graph. Use this for staged work "
|
||||
"where each agent depends on the previous agent's output."
|
||||
),
|
||||
input_schema=_sequential_schema(),
|
||||
builder=sequential.build_graph,
|
||||
),
|
||||
TeamWorkflowSchemaTool(
|
||||
name="ConcurrentWorkflow",
|
||||
description=(
|
||||
"Build a concurrent Beaver team workflow graph. Use this only when agents "
|
||||
"can work independently on the same task."
|
||||
),
|
||||
input_schema=_concurrent_schema(),
|
||||
builder=concurrent.build_graph,
|
||||
),
|
||||
TeamWorkflowSchemaTool(
|
||||
name="MixtureOfAgents",
|
||||
description=(
|
||||
"Build a mixture-of-agents Beaver team workflow graph where independent "
|
||||
"expert agents feed one aggregator agent."
|
||||
),
|
||||
input_schema=_mixture_schema(),
|
||||
builder=mixture_of_agents.build_graph,
|
||||
),
|
||||
TeamWorkflowSchemaTool(
|
||||
name="AgentRearrange",
|
||||
description=(
|
||||
"Build a Beaver team workflow graph from strict flow syntax. Use '->' for "
|
||||
"stage order and ',' for agents in the same parallel stage."
|
||||
),
|
||||
input_schema=_agent_rearrange_schema(),
|
||||
builder=agent_rearrange.build_graph,
|
||||
),
|
||||
TeamWorkflowSchemaTool(
|
||||
name="GraphWorkflow",
|
||||
description=(
|
||||
"Build an explicit Beaver DAG workflow graph. Use this advanced tool only "
|
||||
"when the dependency edges must be specified directly."
|
||||
),
|
||||
input_schema=_graph_schema(),
|
||||
builder=graph.build_graph,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class TeamWorkflowSchemaTool(BaseTool):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
name: str,
|
||||
description: str,
|
||||
input_schema: dict[str, Any],
|
||||
builder: GraphBuilder,
|
||||
) -> None:
|
||||
self._spec = ToolSpec(
|
||||
name=name,
|
||||
description=description,
|
||||
input_schema=input_schema,
|
||||
toolset="team_workflow",
|
||||
always_available=False,
|
||||
metadata={"category": "team_workflow"},
|
||||
)
|
||||
self._builder = builder
|
||||
|
||||
@property
|
||||
def spec(self) -> ToolSpec:
|
||||
return self._spec
|
||||
|
||||
async def invoke(self, arguments: dict[str, Any], context: ToolContext) -> ToolResult:
|
||||
del context
|
||||
try:
|
||||
graph = self._builder(**dict(arguments or {}))
|
||||
payload = {
|
||||
"success": True,
|
||||
"workflow": self.spec.name,
|
||||
"graph": _graph_to_dict(graph),
|
||||
}
|
||||
return ToolResult(
|
||||
success=True,
|
||||
content=json.dumps(payload, ensure_ascii=False),
|
||||
tool_name=self.spec.name,
|
||||
raw_output=payload,
|
||||
)
|
||||
except Exception as exc:
|
||||
payload = {"success": False, "workflow": self.spec.name, "error": str(exc)}
|
||||
return ToolResult(
|
||||
success=False,
|
||||
content=json.dumps(payload, ensure_ascii=False),
|
||||
tool_name=self.spec.name,
|
||||
error=str(exc),
|
||||
raw_output=payload,
|
||||
)
|
||||
|
||||
|
||||
def _graph_to_dict(graph: ExecutionGraph) -> dict[str, Any]:
|
||||
return {
|
||||
"strategy": graph.strategy,
|
||||
"nodes": [
|
||||
{
|
||||
"node_id": node.node_id,
|
||||
"task": node.task,
|
||||
"depends_on": list(node.depends_on),
|
||||
"allowed_tool_names": (
|
||||
None if node.allowed_tool_names is None else list(node.allowed_tool_names)
|
||||
),
|
||||
"required_evidence": list(node.required_evidence),
|
||||
"evidence_contract": dict(node.evidence_contract),
|
||||
"validation_rules": list(node.validation_rules),
|
||||
"required_for_completion": node.required_for_completion,
|
||||
"block_downstream_on_partial": node.block_downstream_on_partial,
|
||||
"max_tool_iterations": node.max_tool_iterations,
|
||||
"metadata": dict(node.agent.metadata),
|
||||
}
|
||||
for node in graph.nodes
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _sequential_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": _task_schema(),
|
||||
"agents": _agents_schema(),
|
||||
},
|
||||
"required": ["task", "agents"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
|
||||
def _concurrent_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": _task_schema(),
|
||||
"agents": _agents_schema(),
|
||||
},
|
||||
"required": ["task", "agents"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
|
||||
def _mixture_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": _task_schema(),
|
||||
"agents": _agents_schema(description="Expert agents that run independently before aggregation."),
|
||||
"aggregator": _agent_schema(description="Aggregator agent that synthesizes expert outputs."),
|
||||
},
|
||||
"required": ["task", "agents", "aggregator"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
|
||||
def _agent_rearrange_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": _task_schema(),
|
||||
"agents": _agents_schema(),
|
||||
"flow": {
|
||||
"type": "string",
|
||||
"description": "Strict flow syntax, e.g. 'collector -> tactics, players -> synthesizer'.",
|
||||
},
|
||||
},
|
||||
"required": ["task", "agents", "flow"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
|
||||
def _graph_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": _task_schema(),
|
||||
"agents": _agents_schema(),
|
||||
"edges": {
|
||||
"type": "array",
|
||||
"description": "Directed dependency edges as [source_agent, target_agent] pairs.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {"type": "string"},
|
||||
},
|
||||
},
|
||||
"output_agent": {
|
||||
"type": "string",
|
||||
"description": "Final output/synthesis agent. Must be reachable from upstream agents.",
|
||||
},
|
||||
"allow_disconnected": {
|
||||
"type": "boolean",
|
||||
"description": "Allow agents that are not connected to output_agent. Defaults to false.",
|
||||
},
|
||||
},
|
||||
"required": ["task", "agents", "edges", "output_agent"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
|
||||
def _task_schema() -> dict[str, Any]:
|
||||
return {
|
||||
"type": "string",
|
||||
"description": "Overall user task this workflow supports.",
|
||||
}
|
||||
|
||||
|
||||
def _agents_schema(*, description: str = "Workflow agents in the order or set used by this workflow.") -> dict[str, Any]:
|
||||
return {
|
||||
"type": "array",
|
||||
"description": description,
|
||||
"items": _agent_schema(),
|
||||
"minItems": 1,
|
||||
}
|
||||
|
||||
|
||||
def _agent_schema(*, description: str = "One workflow agent slot.") -> dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"description": description,
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"instruction": {"type": "string"},
|
||||
"use_skill": {"type": "string"},
|
||||
"skill_query": {"type": "string"},
|
||||
"allowed_tool_names": {"type": "array", "items": {"type": "string"}},
|
||||
"required_evidence": {"type": "array", "items": {"type": "string"}},
|
||||
"evidence_contract": {"type": "object"},
|
||||
"validation_rules": {"type": "array", "items": {"type": "string"}},
|
||||
"required_for_completion": {"type": "boolean"},
|
||||
"block_downstream_on_partial": {"type": "boolean"},
|
||||
"max_tool_iterations": {"type": "integer"},
|
||||
"constraints": {"type": "array", "items": {"type": "string"}},
|
||||
"expected_output": {"type": "string"},
|
||||
"input_contract": {"type": "object"},
|
||||
"output_contract": {"type": "object"},
|
||||
},
|
||||
"required": ["name", "instruction"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
Reference in New Issue
Block a user