Clawith/backend/app/models/audit.py

82 lines
4.0 KiB
Python

"""Audit log, approval request, chat message, and enterprise info models."""
import uuid
from datetime import datetime
from sqlalchemy import DateTime, Enum, ForeignKey, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import JSON, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
class AuditLog(Base):
"""Audit trail for all operations."""
__tablename__ = "audit_logs"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"))
agent_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("agents.id"))
action: Mapped[str] = mapped_column(String(100), nullable=False)
details: Mapped[dict] = mapped_column(JSON, default={})
ip_address: Mapped[str | None] = mapped_column(String(50))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)
class ApprovalRequest(Base):
"""Approval request for L3 autonomy operations."""
__tablename__ = "approval_requests"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
agent_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("agents.id"), nullable=False)
action_type: Mapped[str] = mapped_column(String(100), nullable=False)
details: Mapped[dict] = mapped_column(JSON, default={})
status: Mapped[str] = mapped_column(
Enum("pending", "approved", "rejected", name="approval_status_enum"),
default="pending",
nullable=False,
)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
resolved_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"))
class ChatMessage(Base):
"""Web chat message between user and agent."""
__tablename__ = "chat_messages"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
agent_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("agents.id"), nullable=False, index=True)
user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
role: Mapped[str] = mapped_column(
Enum("user", "assistant", "system", "tool_call", name="chat_role_enum"),
nullable=False,
)
content: Mapped[str] = mapped_column(Text, nullable=False)
conversation_id: Mapped[str] = mapped_column(String(200), default="web", nullable=False)
# Participant identity (unified User/Agent identity)
participant_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("participants.id"), nullable=True)
# Model thinking process
thinking: Mapped[str | None] = mapped_column(Text, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)
class EnterpriseInfo(Base):
"""Centralized enterprise information with versioning for sync."""
__tablename__ = "enterprise_info"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
info_type: Mapped[str] = mapped_column(String(50), nullable=False, unique=True) # org_structure, company_profile, etc.
content: Mapped[dict] = mapped_column(JSON, nullable=False)
version: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
visible_roles: Mapped[list] = mapped_column(JSON, default=[]) # Which agent roles can see this
updated_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)