feat(engine): 添加MCP连接管理和工具集成功能

- 集成MCP连接管理器,支持MCP服务器连接
- 添加多种内置工具:ClarifyTool、CronTool、DelegateTool、ExecuteCodeTool、
  PatchFileTool、ProcessTool、SendMessageTool、SpawnTool、TerminalTool、
  TodoTool、WebFetchTool、WebSearchTool、WriteFileTool等
- 实现工具注册和装配功能
- 添加技能选择上下文参数
- 支持思考模式控制参数thinking_enabled

feat(coordinator): 重构任务执行计划器参数命名

- 将learning_candidate_enabled重命名为allow_candidate_generation
- 更新TeamGraphScheduler中的参数传递
- 修改LocalAgentRunner中的相关参数处理
- 更新README文档中的相应描述

refactor(context): 标准化工具调用参数格式

- 添加_json导入用于参数序列化
- 实现_provider_tool_calls方法标准化OpenAI兼容的工具调用载荷
- 修复工具调用中参数非字符串类型的序列化问题

refactor(session): 优化消息历史记录过滤逻辑

- 修改get_messages_as_conversation为基于运行状态过滤消息
- 排除未完成、失败或错误结束的运行记录
- 改进对话历史的可见性控制机制

fix(store): 修复FTS索引重建逻辑

- 添加异常处理防止FTS索引创建失败
- 实现_rebuild_fts_index方法重新构建全文搜索索引
- 优化索引触发器和表的维护流程
This commit is contained in:
2026-05-14 09:43:48 +08:00
parent 8a12c30141
commit 30ab74ffb2
149 changed files with 12293 additions and 2812 deletions

View File

@ -32,7 +32,7 @@ class TeamGraphScheduler:
provider_bundle_factory: Callable[[ExecutionNode], ProviderBundle | None] | None = None,
inherited_pinned_skills: list[str] | None = None,
inherited_pinned_skill_contexts: list["SkillContext"] | None = None,
learning_candidate_enabled: bool = False,
allow_candidate_generation: bool = False,
) -> TeamRunResult:
graph.validate()
if provider_bundle is not None and len(graph.nodes) > 1:
@ -49,7 +49,7 @@ class TeamGraphScheduler:
provider_bundle_factory=provider_bundle_factory,
inherited_pinned_skills=inherited,
inherited_pinned_skill_contexts=inherited_contexts,
learning_candidate_enabled=learning_candidate_enabled,
allow_candidate_generation=allow_candidate_generation,
)
elif graph.strategy == "parallel":
results = await self._run_parallel(
@ -61,7 +61,7 @@ class TeamGraphScheduler:
provider_bundle_factory=provider_bundle_factory,
inherited_pinned_skills=inherited,
inherited_pinned_skill_contexts=inherited_contexts,
learning_candidate_enabled=learning_candidate_enabled,
allow_candidate_generation=allow_candidate_generation,
)
else:
results = await self._run_dag(
@ -73,7 +73,7 @@ class TeamGraphScheduler:
provider_bundle_factory=provider_bundle_factory,
inherited_pinned_skills=inherited,
inherited_pinned_skill_contexts=inherited_contexts,
learning_candidate_enabled=learning_candidate_enabled,
allow_candidate_generation=allow_candidate_generation,
)
return self._summarize(results, task_id=parent_task_id)
@ -162,7 +162,7 @@ class TeamGraphScheduler:
provider_bundle_factory: Callable[[ExecutionNode], ProviderBundle | None] | None,
inherited_pinned_skills: list[str],
inherited_pinned_skill_contexts: list["SkillContext"],
learning_candidate_enabled: bool,
allow_candidate_generation: bool,
dependency_outputs: dict[str, str],
) -> NodeRunResult:
try:
@ -188,7 +188,7 @@ class TeamGraphScheduler:
return await self.runner.run(
envelope,
provider_bundle=node_provider_bundle,
learning_candidate_enabled=learning_candidate_enabled,
allow_candidate_generation=allow_candidate_generation,
)
except asyncio.CancelledError:
raise

View File

@ -21,7 +21,7 @@ class LocalAgentRunner:
envelope: DelegationEnvelope,
*,
provider_bundle: ProviderBundle | None = None,
learning_candidate_enabled: bool = False,
allow_candidate_generation: bool = False,
) -> NodeRunResult:
if provider_bundle is not None and (envelope.agent.model or envelope.agent.provider_name):
raise ValueError(
@ -37,6 +37,7 @@ class LocalAgentRunner:
source=f"team:{envelope.agent.name}",
title=envelope.agent.role or envelope.agent.name,
execution_context=self._execution_context(envelope),
skill_selection_context=self._skill_selection_context(envelope),
model=envelope.agent.model,
provider_name=envelope.agent.provider_name,
provider_bundle=provider_bundle,
@ -44,7 +45,7 @@ class LocalAgentRunner:
task_mode=bool(envelope.parent_task_id),
pinned_skill_names=envelope.inherited_pinned_skills,
pinned_skill_contexts=envelope.inherited_pinned_skill_contexts,
learning_candidate_enabled=learning_candidate_enabled,
allow_candidate_generation=allow_candidate_generation,
)
success = result.finish_reason == "stop"
return NodeRunResult(
@ -86,7 +87,48 @@ class LocalAgentRunner:
sections.append("Pinned inherited skills:\n" + "\n".join(f"- {item}" for item in envelope.inherited_pinned_skills))
if envelope.inherited_pinned_skill_contexts:
sections.append(
"Ephemeral pinned skill drafts:\n"
"Ephemeral pinned guidance:\n"
+ "\n".join(f"- {item.name} ({item.version})" for item in envelope.inherited_pinned_skill_contexts)
)
return "\n\n".join(sections)
@staticmethod
def _skill_selection_context(envelope: DelegationEnvelope) -> str:
sections: list[str] = []
if envelope.parent_task_id:
sections.append(f"Parent task ID:\n{envelope.parent_task_id}")
sections.append(f"Node task:\n{envelope.task}")
sections.append("Execution phase:\nteam_node")
if envelope.agent.role:
sections.append(f"Agent role:\n{envelope.agent.role}")
skill_query = envelope.agent.metadata.get("skill_query")
if skill_query:
sections.append(f"Skill query:\n{skill_query}")
required_capabilities = envelope.agent.metadata.get("required_capabilities")
if required_capabilities:
if isinstance(required_capabilities, list):
rendered = "\n".join(f"- {item}" for item in required_capabilities)
else:
rendered = str(required_capabilities)
sections.append(f"Required capabilities:\n{rendered}")
if envelope.constraints:
sections.append("Constraints:\n" + "\n".join(f"- {item}" for item in envelope.constraints))
if envelope.expected_output:
sections.append(f"Expected output:\n{envelope.expected_output}")
if envelope.inherited_pinned_skills:
sections.append(
"Pinned inherited skills (must be injected separately; use as strong context):\n"
+ "\n".join(f"- {item}" for item in envelope.inherited_pinned_skills)
)
if envelope.dependency_outputs:
rendered = "\n\n".join(
f"Dependency {node_id} output:\n{output[:800]}"
for node_id, output in envelope.dependency_outputs.items()
)
sections.append("Dependency outputs:\n" + rendered)
sections.append(
"Skill selection instruction:\n"
"Select published skills for this delegated node. "
"If no published skill matches, return [] and let the node continue without skills."
)
return "\n\n".join(sections)