Add Day 4 visibility endpoints and response models, strengthen collaboration/task verification behavior, and patch conversation schema startup migration for agent_state compatibility. Extend backend regression coverage for runtime schemas, verifier behavior, visibility APIs, router auth, and legacy conversation list loading.
94 lines
3.9 KiB
Python
94 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, cast
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from app.agents.schemas.task import AgentTask, TaskResult, TaskResultStatus, VerificationStatus
|
|
from app.agents.state import AgentState
|
|
|
|
|
|
class VerificationVerdict(BaseModel):
|
|
status: VerificationStatus
|
|
summary: str | None = None
|
|
evidence: list[dict[str, Any]] = Field(default_factory=list)
|
|
|
|
|
|
def normalize_task_result(
|
|
task_result: TaskResult | dict[str, Any],
|
|
*,
|
|
default_task_id: str | None = None,
|
|
) -> TaskResult:
|
|
payload = task_result.model_dump(mode="json") if isinstance(task_result, TaskResult) else dict(task_result or {})
|
|
normalized_status = payload.get("status")
|
|
if normalized_status not in {"completed", "failed", "blocked", "passed", "skipped"}:
|
|
normalized_status = "failed"
|
|
return TaskResult(
|
|
task_id=str(payload.get("task_id") or default_task_id or "unknown-task"),
|
|
status=cast(TaskResultStatus, normalized_status),
|
|
summary=payload.get("summary"),
|
|
evidence=list(payload.get("evidence") or []),
|
|
owner_agent_id=payload.get("owner_agent_id"),
|
|
parent_task_id=payload.get("parent_task_id"),
|
|
child_task_ids=list(payload.get("child_task_ids") or []),
|
|
thread_id=payload.get("thread_id"),
|
|
message_id=payload.get("message_id"),
|
|
message_index=payload.get("message_index") if isinstance(payload.get("message_index"), int) else None,
|
|
interrupt_records=list(payload.get("interrupt_records") or []),
|
|
recovery_records=list(payload.get("recovery_records") or []),
|
|
budget_snapshot=payload.get("budget_snapshot") if isinstance(payload.get("budget_snapshot"), dict) else None,
|
|
next_action=payload.get("next_action"),
|
|
output_data=payload.get("output_data") if isinstance(payload.get("output_data"), dict) else None,
|
|
)
|
|
|
|
|
|
def verify_task_result(
|
|
*,
|
|
task: AgentTask | dict[str, Any] | None = None,
|
|
result: TaskResult | dict[str, Any] | None = None,
|
|
summary: str | None = None,
|
|
evidence: list[dict[str, Any]] | None = None,
|
|
status: VerificationStatus | None = None,
|
|
) -> VerificationVerdict:
|
|
normalized_result = result.model_dump() if isinstance(result, TaskResult) else dict(result or {})
|
|
normalized_task = task.model_dump() if isinstance(task, AgentTask) else dict(task or {})
|
|
normalized_summary = summary or normalized_result.get("summary") or normalized_task.get("result_summary")
|
|
normalized_evidence = list(evidence or normalized_result.get("evidence") or normalized_task.get("evidence") or [])
|
|
|
|
if status is not None:
|
|
return VerificationVerdict(status=status, summary=normalized_summary, evidence=normalized_evidence)
|
|
|
|
normalized_status = normalized_result.get("status")
|
|
if normalized_status in {"passed", "failed", "skipped"}:
|
|
inferred_status = normalized_status
|
|
elif normalized_status == "completed":
|
|
inferred_status = "passed"
|
|
elif normalized_status == "blocked":
|
|
inferred_status = "skipped"
|
|
elif normalized_result.get("success") is True:
|
|
inferred_status = "passed"
|
|
elif normalized_result.get("success") is False:
|
|
inferred_status = "failed"
|
|
elif normalized_summary or normalized_evidence:
|
|
inferred_status = "skipped"
|
|
else:
|
|
inferred_status = "failed"
|
|
normalized_summary = "No verification input available."
|
|
|
|
return VerificationVerdict(
|
|
status=inferred_status,
|
|
summary=normalized_summary,
|
|
evidence=normalized_evidence,
|
|
)
|
|
|
|
|
|
def apply_verification_verdict(state: AgentState, verdict: VerificationVerdict) -> AgentState:
|
|
next_state = dict(state)
|
|
next_state["verification_status"] = verdict.status
|
|
next_state["verification_summary"] = verdict.summary
|
|
next_state["verification_evidence"] = list(verdict.evidence)
|
|
return AgentState(**next_state)
|
|
|
|
|
|
__all__ = ["VerificationVerdict", "apply_verification_verdict", "normalize_task_result", "verify_task_result"]
|