feat: add agent visibility APIs and harden runtime verification
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.
This commit is contained in:
@@ -1,10 +1,25 @@
|
||||
from app.agents.schemas.event import AgentEvent
|
||||
from app.agents.schemas.task import AgentTask, TaskResult, TaskLifecycleStatus, VerificationStatus
|
||||
from app.agents.schemas.message import AgentMessage
|
||||
from app.agents.schemas.task import (
|
||||
AgentTask,
|
||||
CollaborationBudget,
|
||||
InterruptRecord,
|
||||
RecoveryRecord,
|
||||
TaskLifecycleStatus,
|
||||
TaskResult,
|
||||
TaskResultStatus,
|
||||
VerificationStatus,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AgentEvent",
|
||||
"AgentMessage",
|
||||
"AgentTask",
|
||||
"CollaborationBudget",
|
||||
"InterruptRecord",
|
||||
"RecoveryRecord",
|
||||
"TaskLifecycleStatus",
|
||||
"TaskResult",
|
||||
"TaskResultStatus",
|
||||
"VerificationStatus",
|
||||
]
|
||||
|
||||
@@ -11,6 +11,18 @@ AgentEventType = Literal[
|
||||
"agent.tool.result",
|
||||
"agent.verify.started",
|
||||
"agent.verify.completed",
|
||||
"agent.created",
|
||||
"agent.spawn.blocked",
|
||||
"agent.message.sent",
|
||||
"agent.message.received",
|
||||
"agent.interrupt.requested",
|
||||
"agent.interrupt.completed",
|
||||
"agent.recovery.started",
|
||||
"agent.recovery.completed",
|
||||
"agent.task.interrupted",
|
||||
"agent.task.recovered",
|
||||
"agent.task.reassigned",
|
||||
"agent.collaboration.budget.updated",
|
||||
"agent.error",
|
||||
]
|
||||
AgentEventSeverity = Literal["info", "warning", "error"]
|
||||
@@ -24,5 +36,11 @@ class AgentEvent(BaseModel):
|
||||
agent_id: str | None = None
|
||||
sub_commander_id: str | None = None
|
||||
task_id: str | None = None
|
||||
parent_task_id: str | None = None
|
||||
child_task_id: str | None = None
|
||||
thread_id: str | None = None
|
||||
message_id: str | None = None
|
||||
interrupt_id: str | None = None
|
||||
recovery_id: str | None = None
|
||||
payload: dict[str, Any] = Field(default_factory=dict)
|
||||
severity: AgentEventSeverity = "info"
|
||||
|
||||
29
backend/app/agents/schemas/message.py
Normal file
29
backend/app/agents/schemas/message.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
AgentMessageType = Literal[
|
||||
"task_request",
|
||||
"task_update",
|
||||
"handoff",
|
||||
"verification_request",
|
||||
"verification_feedback",
|
||||
"interrupt_notice",
|
||||
]
|
||||
|
||||
|
||||
class AgentMessage(BaseModel):
|
||||
message_id: str
|
||||
thread_id: str
|
||||
from_agent_id: str
|
||||
to_agent_id: str
|
||||
task_id: str | None = None
|
||||
reply_to_message_id: str | None = None
|
||||
message_type: AgentMessageType = "task_update"
|
||||
content_summary: str
|
||||
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
payload: dict[str, Any] = Field(default_factory=dict)
|
||||
@@ -8,6 +8,41 @@ from pydantic import BaseModel, Field
|
||||
|
||||
TaskLifecycleStatus = Literal["pending", "in_progress", "completed", "failed", "blocked"]
|
||||
VerificationStatus = Literal["passed", "failed", "skipped"]
|
||||
TaskResultStatus = Literal["completed", "failed", "blocked", "passed", "skipped"]
|
||||
InterruptStatus = Literal["requested", "acknowledged", "resolved"]
|
||||
BudgetMode = Literal["direct", "collaboration"]
|
||||
|
||||
|
||||
class InterruptRecord(BaseModel):
|
||||
interrupt_id: str
|
||||
reason: str
|
||||
status: InterruptStatus = "requested"
|
||||
requested_by: str | None = None
|
||||
source_event_id: str | None = None
|
||||
requested_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
payload: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class RecoveryRecord(BaseModel):
|
||||
recovery_id: str
|
||||
source_interrupt_id: str | None = None
|
||||
strategy: str | None = None
|
||||
resumed_from_task_id: str | None = None
|
||||
resumed_from_thread_id: str | None = None
|
||||
recovered_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
payload: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class CollaborationBudget(BaseModel):
|
||||
mode: BudgetMode = "direct"
|
||||
max_parallel_tasks: int | None = None
|
||||
remaining_parallel_tasks: int | None = None
|
||||
max_tool_calls: int | None = None
|
||||
remaining_tool_calls: int | None = None
|
||||
max_iterations: int | None = None
|
||||
remaining_iterations: int | None = None
|
||||
escalation_threshold: int | None = None
|
||||
metadata: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AgentTask(BaseModel):
|
||||
@@ -17,8 +52,16 @@ class AgentTask(BaseModel):
|
||||
owner_agent_id: str | None = None
|
||||
role: str | None = None
|
||||
goal: str | None = None
|
||||
parent_task_id: str | None = None
|
||||
child_task_ids: list[str] = Field(default_factory=list)
|
||||
thread_id: str | None = None
|
||||
message_id: str | None = None
|
||||
message_index: int | None = None
|
||||
expected_evidence: list[dict[str, Any]] = Field(default_factory=list)
|
||||
evidence: list[dict[str, Any]] = Field(default_factory=list)
|
||||
interrupt_records: list[InterruptRecord | dict[str, Any]] = Field(default_factory=list)
|
||||
recovery_records: list[RecoveryRecord | dict[str, Any]] = Field(default_factory=list)
|
||||
collaboration_budget: CollaborationBudget | dict[str, Any] | None = None
|
||||
result_summary: str | None = None
|
||||
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
@@ -26,7 +69,17 @@ class AgentTask(BaseModel):
|
||||
|
||||
class TaskResult(BaseModel):
|
||||
task_id: str
|
||||
status: VerificationStatus
|
||||
status: TaskResultStatus
|
||||
summary: str | None = None
|
||||
evidence: list[dict[str, Any]] = Field(default_factory=list)
|
||||
owner_agent_id: str | None = None
|
||||
parent_task_id: str | None = None
|
||||
child_task_ids: list[str] = Field(default_factory=list)
|
||||
thread_id: str | None = None
|
||||
message_id: str | None = None
|
||||
message_index: int | None = None
|
||||
interrupt_records: list[InterruptRecord | dict[str, Any]] = Field(default_factory=list)
|
||||
recovery_records: list[RecoveryRecord | dict[str, Any]] = Field(default_factory=list)
|
||||
budget_snapshot: CollaborationBudget | dict[str, Any] | None = None
|
||||
next_action: str | None = None
|
||||
output_data: dict[str, Any] | None = None
|
||||
|
||||
Reference in New Issue
Block a user