feat(beaver): 完成Task Team功能v1实现,重构后端架构支持统一内核
新增内部Task系统,包括验证、反馈门控机制,实现自动质量验证 (通过率>=0.75)和用户反馈闭环(satisfied/revise/abandon)。 实现Agent Team v1协调器,支持sequence/parallel/dag执行策略, sub-agent复用主AgentLoop,每个run使用独立memory snapshot。 建立Skill学习pipeline,包含draft/审核/发布/回滚完整生命周期, 通过Task验证通过且用户满意才生成学习候选。 重构目录结构,移除third_party依赖,建立统一engine内核, 所有agent共享运行时基础组件。 更新ContextBuilder清理provider消息字段,增强SkillContext版本管理, 集成TaskExecutionPlanner和TaskSkillResolver实现技能解析机制。
This commit is contained in:
@ -1,10 +1,90 @@
|
||||
"""Application service for coordinated team runs."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from beaver.coordinator import ExecutionGraph, ExecutionNode, LocalAgentRunner, TeamGraphScheduler, TeamRunResult
|
||||
from beaver.engine import AgentLoop
|
||||
from beaver.engine.providers import ProviderBundle
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from beaver.engine.context import SkillContext
|
||||
|
||||
|
||||
class TeamService:
|
||||
"""Placeholder service for multi-agent execution."""
|
||||
"""Internal service for Beaver-native multi-agent execution."""
|
||||
|
||||
def __init__(self, loop: AgentLoop) -> None:
|
||||
self.loop = loop
|
||||
self.runner = LocalAgentRunner(loop)
|
||||
self.scheduler = TeamGraphScheduler(self.runner)
|
||||
|
||||
async def run_team(
|
||||
self,
|
||||
graph: ExecutionGraph,
|
||||
*,
|
||||
parent_task_id: str | None,
|
||||
parent_session_id: str,
|
||||
parent_run_id: str | None = None,
|
||||
provider_bundle: ProviderBundle | None = None,
|
||||
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,
|
||||
) -> TeamRunResult:
|
||||
"""Run a team graph inside the parent task context."""
|
||||
|
||||
self._validate_parent_task(parent_task_id, parent_session_id)
|
||||
result = await self.scheduler.run(
|
||||
graph,
|
||||
parent_task_id=parent_task_id,
|
||||
parent_session_id=parent_session_id,
|
||||
parent_run_id=parent_run_id,
|
||||
provider_bundle=provider_bundle,
|
||||
provider_bundle_factory=provider_bundle_factory,
|
||||
inherited_pinned_skills=inherited_pinned_skills,
|
||||
inherited_pinned_skill_contexts=inherited_pinned_skill_contexts,
|
||||
learning_candidate_enabled=learning_candidate_enabled,
|
||||
)
|
||||
self._attach_runs_to_parent_task(result)
|
||||
return result
|
||||
|
||||
def run(self, task: str) -> str:
|
||||
"""Return a placeholder summary until real backends are migrated."""
|
||||
return f"team run placeholder: {task}"
|
||||
"""Compatibility shim for old callers that only expected a string."""
|
||||
|
||||
return f"team service requires run_team() for coordinated execution: {task}"
|
||||
|
||||
def _validate_parent_task(self, parent_task_id: str | None, parent_session_id: str) -> None:
|
||||
if not parent_task_id:
|
||||
return
|
||||
loaded = self.loop.boot()
|
||||
task_service = getattr(loaded, "task_service", None)
|
||||
if task_service is None:
|
||||
raise RuntimeError("TeamService requires task_service when parent_task_id is provided")
|
||||
task = task_service.get_task(parent_task_id)
|
||||
if task is None:
|
||||
raise ValueError(f"Unknown parent_task_id: {parent_task_id}")
|
||||
if task.session_id != parent_session_id:
|
||||
raise ValueError(
|
||||
f"parent_task_id {parent_task_id!r} belongs to session {task.session_id!r}, "
|
||||
f"not {parent_session_id!r}"
|
||||
)
|
||||
|
||||
def _attach_runs_to_parent_task(self, result: TeamRunResult) -> None:
|
||||
if not result.task_id or not result.run_ids:
|
||||
return
|
||||
loaded = self.loop.boot()
|
||||
task_service = getattr(loaded, "task_service", None)
|
||||
if task_service is None or task_service.get_task(result.task_id) is None:
|
||||
return
|
||||
run_store = getattr(loaded, "run_memory_store", None)
|
||||
for run_id in result.run_ids:
|
||||
skill_names: list[str] = []
|
||||
if run_store is not None:
|
||||
for record in run_store.list_runs():
|
||||
if record.run_id == run_id:
|
||||
skill_names = [receipt.skill_name for receipt in record.activated_skills]
|
||||
break
|
||||
task_service.append_run(result.task_id, run_id, skill_names=skill_names)
|
||||
|
||||
Reference in New Issue
Block a user