Files
beaver_project/app-instance/backend/beaver/memory/runs/models.py
steven_li 8a12c30141 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实现技能解析机制。
2026-05-08 17:14:14 +08:00

143 lines
4.5 KiB
Python

"""Run-level receipts and skill effect records."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
from beaver.skills.specs import SkillActivationReceipt
@dataclass(slots=True)
class RunOutcome:
success: bool
finish_reason: str
feedback_score: float | None = None
notes: str = ""
def to_dict(self) -> dict[str, Any]:
return {
"success": self.success,
"finish_reason": self.finish_reason,
"feedback_score": self.feedback_score,
"notes": self.notes,
}
@classmethod
def from_dict(cls, payload: dict[str, Any]) -> "RunOutcome":
return cls(
success=bool(payload.get("success")),
finish_reason=str(payload.get("finish_reason") or ""),
feedback_score=_coerce_optional_float(payload.get("feedback_score")),
notes=str(payload.get("notes") or ""),
)
@dataclass(slots=True)
class RunRecord:
run_id: str
session_id: str
task_text: str
started_at: str
ended_at: str
success: bool
finish_reason: str
feedback: dict[str, Any] = field(default_factory=dict)
activated_skills: list[SkillActivationReceipt] = field(default_factory=list)
task_id: str | None = None
attempt_index: int | None = None
validation_result: dict[str, Any] | None = None
def to_dict(self) -> dict[str, Any]:
return {
"run_id": self.run_id,
"session_id": self.session_id,
"task_id": self.task_id,
"attempt_index": self.attempt_index,
"task_text": self.task_text,
"started_at": self.started_at,
"ended_at": self.ended_at,
"success": self.success,
"finish_reason": self.finish_reason,
"feedback": dict(self.feedback),
"activated_skills": [receipt.to_dict() for receipt in self.activated_skills],
"validation_result": self.validation_result,
}
@classmethod
def from_dict(cls, payload: dict[str, Any]) -> "RunRecord":
return cls(
run_id=str(payload["run_id"]),
session_id=str(payload["session_id"]),
task_id=_coerce_optional_str(payload.get("task_id")),
attempt_index=_coerce_optional_int(payload.get("attempt_index")),
task_text=str(payload.get("task_text") or ""),
started_at=str(payload.get("started_at") or ""),
ended_at=str(payload.get("ended_at") or ""),
success=bool(payload.get("success")),
finish_reason=str(payload.get("finish_reason") or ""),
feedback=dict(payload.get("feedback") or {}),
activated_skills=[
SkillActivationReceipt.from_dict(item)
for item in payload.get("activated_skills") or []
if isinstance(item, dict)
],
validation_result=(
dict(payload["validation_result"])
if isinstance(payload.get("validation_result"), dict)
else None
),
)
@dataclass(slots=True)
class SkillEffectRecord:
run_id: str
skill_name: str
skill_version: str
success: bool
feedback_score: float | None
notes: str
created_at: str
def to_dict(self) -> dict[str, Any]:
return {
"run_id": self.run_id,
"skill_name": self.skill_name,
"skill_version": self.skill_version,
"success": self.success,
"feedback_score": self.feedback_score,
"notes": self.notes,
"created_at": self.created_at,
}
@classmethod
def from_dict(cls, payload: dict[str, Any]) -> "SkillEffectRecord":
return cls(
run_id=str(payload["run_id"]),
skill_name=str(payload["skill_name"]),
skill_version=str(payload["skill_version"]),
success=bool(payload.get("success")),
feedback_score=_coerce_optional_float(payload.get("feedback_score")),
notes=str(payload.get("notes") or ""),
created_at=str(payload.get("created_at") or ""),
)
def _coerce_optional_float(value: Any) -> float | None:
if value in (None, ""):
return None
return float(value)
def _coerce_optional_int(value: Any) -> int | None:
if value in (None, ""):
return None
return int(value)
def _coerce_optional_str(value: Any) -> str | None:
if value in (None, ""):
return None
return str(value)