Reformatted multiline function calls, object definitions, and queries for improved code readability and consistency. Adjusted imports and constraints where necessary.
274 lines
9.3 KiB
Python
274 lines
9.3 KiB
Python
"""
|
|
Event schemas for the Syndarix EventBus (Redis Pub/Sub).
|
|
|
|
This module defines event types and payload schemas for real-time communication
|
|
between services, agents, and the frontend.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class EventType(str, Enum):
|
|
"""
|
|
Event types for the EventBus.
|
|
|
|
Naming convention: {domain}.{action}
|
|
"""
|
|
|
|
# Agent Events
|
|
AGENT_SPAWNED = "agent.spawned"
|
|
AGENT_STATUS_CHANGED = "agent.status_changed"
|
|
AGENT_MESSAGE = "agent.message"
|
|
AGENT_TERMINATED = "agent.terminated"
|
|
|
|
# Issue Events
|
|
ISSUE_CREATED = "issue.created"
|
|
ISSUE_UPDATED = "issue.updated"
|
|
ISSUE_ASSIGNED = "issue.assigned"
|
|
ISSUE_CLOSED = "issue.closed"
|
|
|
|
# Sprint Events
|
|
SPRINT_STARTED = "sprint.started"
|
|
SPRINT_COMPLETED = "sprint.completed"
|
|
|
|
# Approval Events
|
|
APPROVAL_REQUESTED = "approval.requested"
|
|
APPROVAL_GRANTED = "approval.granted"
|
|
APPROVAL_DENIED = "approval.denied"
|
|
|
|
# Project Events
|
|
PROJECT_CREATED = "project.created"
|
|
PROJECT_UPDATED = "project.updated"
|
|
PROJECT_ARCHIVED = "project.archived"
|
|
|
|
# Workflow Events
|
|
WORKFLOW_STARTED = "workflow.started"
|
|
WORKFLOW_STEP_COMPLETED = "workflow.step_completed"
|
|
WORKFLOW_COMPLETED = "workflow.completed"
|
|
WORKFLOW_FAILED = "workflow.failed"
|
|
|
|
|
|
ActorType = Literal["agent", "user", "system"]
|
|
|
|
|
|
class Event(BaseModel):
|
|
"""
|
|
Base event schema for the EventBus.
|
|
|
|
All events published to the EventBus must conform to this schema.
|
|
"""
|
|
|
|
id: str = Field(
|
|
...,
|
|
description="Unique event identifier (UUID string)",
|
|
examples=["550e8400-e29b-41d4-a716-446655440000"],
|
|
)
|
|
type: EventType = Field(
|
|
...,
|
|
description="Event type enum value",
|
|
examples=[EventType.AGENT_MESSAGE],
|
|
)
|
|
timestamp: datetime = Field(
|
|
...,
|
|
description="When the event occurred (UTC)",
|
|
examples=["2024-01-15T10:30:00Z"],
|
|
)
|
|
project_id: UUID = Field(
|
|
...,
|
|
description="Project this event belongs to",
|
|
examples=["550e8400-e29b-41d4-a716-446655440001"],
|
|
)
|
|
actor_id: UUID | None = Field(
|
|
default=None,
|
|
description="ID of the agent or user who triggered the event",
|
|
examples=["550e8400-e29b-41d4-a716-446655440002"],
|
|
)
|
|
actor_type: ActorType = Field(
|
|
...,
|
|
description="Type of actor: 'agent', 'user', or 'system'",
|
|
examples=["agent"],
|
|
)
|
|
payload: dict = Field(
|
|
default_factory=dict,
|
|
description="Event-specific payload data",
|
|
)
|
|
|
|
model_config = {
|
|
"json_schema_extra": {
|
|
"example": {
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"type": "agent.message",
|
|
"timestamp": "2024-01-15T10:30:00Z",
|
|
"project_id": "550e8400-e29b-41d4-a716-446655440001",
|
|
"actor_id": "550e8400-e29b-41d4-a716-446655440002",
|
|
"actor_type": "agent",
|
|
"payload": {"message": "Processing task...", "progress": 50},
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# Specific payload schemas for type safety
|
|
|
|
|
|
class AgentSpawnedPayload(BaseModel):
|
|
"""Payload for AGENT_SPAWNED events."""
|
|
|
|
agent_instance_id: UUID = Field(..., description="ID of the spawned agent instance")
|
|
agent_type_id: UUID = Field(..., description="ID of the agent type")
|
|
agent_name: str = Field(..., description="Human-readable name of the agent")
|
|
role: str = Field(..., description="Agent role (e.g., 'product_owner', 'engineer')")
|
|
|
|
|
|
class AgentStatusChangedPayload(BaseModel):
|
|
"""Payload for AGENT_STATUS_CHANGED events."""
|
|
|
|
agent_instance_id: UUID = Field(..., description="ID of the agent instance")
|
|
previous_status: str = Field(..., description="Previous status")
|
|
new_status: str = Field(..., description="New status")
|
|
reason: str | None = Field(default=None, description="Reason for status change")
|
|
|
|
|
|
class AgentMessagePayload(BaseModel):
|
|
"""Payload for AGENT_MESSAGE events."""
|
|
|
|
agent_instance_id: UUID = Field(..., description="ID of the agent instance")
|
|
message: str = Field(..., description="Message content")
|
|
message_type: str = Field(
|
|
default="info",
|
|
description="Message type: 'info', 'warning', 'error', 'debug'",
|
|
)
|
|
metadata: dict = Field(
|
|
default_factory=dict,
|
|
description="Additional metadata (e.g., token usage, model info)",
|
|
)
|
|
|
|
|
|
class AgentTerminatedPayload(BaseModel):
|
|
"""Payload for AGENT_TERMINATED events."""
|
|
|
|
agent_instance_id: UUID = Field(..., description="ID of the agent instance")
|
|
termination_reason: str = Field(..., description="Reason for termination")
|
|
final_status: str = Field(..., description="Final status at termination")
|
|
|
|
|
|
class IssueCreatedPayload(BaseModel):
|
|
"""Payload for ISSUE_CREATED events."""
|
|
|
|
issue_id: str = Field(..., description="Issue ID (from external tracker)")
|
|
title: str = Field(..., description="Issue title")
|
|
priority: str | None = Field(default=None, description="Issue priority")
|
|
labels: list[str] = Field(default_factory=list, description="Issue labels")
|
|
|
|
|
|
class IssueUpdatedPayload(BaseModel):
|
|
"""Payload for ISSUE_UPDATED events."""
|
|
|
|
issue_id: str = Field(..., description="Issue ID (from external tracker)")
|
|
changes: dict = Field(..., description="Dictionary of field changes")
|
|
|
|
|
|
class IssueAssignedPayload(BaseModel):
|
|
"""Payload for ISSUE_ASSIGNED events."""
|
|
|
|
issue_id: str = Field(..., description="Issue ID (from external tracker)")
|
|
assignee_id: UUID | None = Field(
|
|
default=None, description="Agent or user assigned to"
|
|
)
|
|
assignee_name: str | None = Field(default=None, description="Assignee name")
|
|
|
|
|
|
class IssueClosedPayload(BaseModel):
|
|
"""Payload for ISSUE_CLOSED events."""
|
|
|
|
issue_id: str = Field(..., description="Issue ID (from external tracker)")
|
|
resolution: str = Field(..., description="Resolution status")
|
|
|
|
|
|
class SprintStartedPayload(BaseModel):
|
|
"""Payload for SPRINT_STARTED events."""
|
|
|
|
sprint_id: UUID = Field(..., description="Sprint ID")
|
|
sprint_name: str = Field(..., description="Sprint name")
|
|
goal: str | None = Field(default=None, description="Sprint goal")
|
|
issue_count: int = Field(default=0, description="Number of issues in sprint")
|
|
|
|
|
|
class SprintCompletedPayload(BaseModel):
|
|
"""Payload for SPRINT_COMPLETED events."""
|
|
|
|
sprint_id: UUID = Field(..., description="Sprint ID")
|
|
sprint_name: str = Field(..., description="Sprint name")
|
|
completed_issues: int = Field(default=0, description="Number of completed issues")
|
|
incomplete_issues: int = Field(default=0, description="Number of incomplete issues")
|
|
|
|
|
|
class ApprovalRequestedPayload(BaseModel):
|
|
"""Payload for APPROVAL_REQUESTED events."""
|
|
|
|
approval_id: UUID = Field(..., description="Approval request ID")
|
|
approval_type: str = Field(..., description="Type of approval needed")
|
|
description: str = Field(..., description="Description of what needs approval")
|
|
requested_by: UUID | None = Field(
|
|
default=None, description="Agent/user requesting approval"
|
|
)
|
|
timeout_minutes: int | None = Field(
|
|
default=None, description="Minutes before auto-escalation"
|
|
)
|
|
|
|
|
|
class ApprovalGrantedPayload(BaseModel):
|
|
"""Payload for APPROVAL_GRANTED events."""
|
|
|
|
approval_id: UUID = Field(..., description="Approval request ID")
|
|
approved_by: UUID = Field(..., description="User who granted approval")
|
|
comments: str | None = Field(default=None, description="Approval comments")
|
|
|
|
|
|
class ApprovalDeniedPayload(BaseModel):
|
|
"""Payload for APPROVAL_DENIED events."""
|
|
|
|
approval_id: UUID = Field(..., description="Approval request ID")
|
|
denied_by: UUID = Field(..., description="User who denied approval")
|
|
reason: str = Field(..., description="Reason for denial")
|
|
|
|
|
|
class WorkflowStartedPayload(BaseModel):
|
|
"""Payload for WORKFLOW_STARTED events."""
|
|
|
|
workflow_id: UUID = Field(..., description="Workflow execution ID")
|
|
workflow_type: str = Field(..., description="Type of workflow")
|
|
total_steps: int = Field(default=0, description="Total number of steps")
|
|
|
|
|
|
class WorkflowStepCompletedPayload(BaseModel):
|
|
"""Payload for WORKFLOW_STEP_COMPLETED events."""
|
|
|
|
workflow_id: UUID = Field(..., description="Workflow execution ID")
|
|
step_name: str = Field(..., description="Name of completed step")
|
|
step_number: int = Field(..., description="Step number (1-indexed)")
|
|
total_steps: int = Field(..., description="Total number of steps")
|
|
result: dict = Field(default_factory=dict, description="Step result data")
|
|
|
|
|
|
class WorkflowCompletedPayload(BaseModel):
|
|
"""Payload for WORKFLOW_COMPLETED events."""
|
|
|
|
workflow_id: UUID = Field(..., description="Workflow execution ID")
|
|
duration_seconds: float = Field(..., description="Total execution duration")
|
|
result: dict = Field(default_factory=dict, description="Workflow result data")
|
|
|
|
|
|
class WorkflowFailedPayload(BaseModel):
|
|
"""Payload for WORKFLOW_FAILED events."""
|
|
|
|
workflow_id: UUID = Field(..., description="Workflow execution ID")
|
|
error_message: str = Field(..., description="Error message")
|
|
failed_step: str | None = Field(default=None, description="Step that failed")
|
|
recoverable: bool = Field(default=False, description="Whether error is recoverable")
|