"""最小审计模型与待确认持久化记录。""" from datetime import datetime from sqlalchemy import DateTime, ForeignKey, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.ids import new_audit_id from app.core.time import utc_now from app.db.base import Base class AuditEvent(Base): __tablename__ = "audit_events" id: Mapped[str] = mapped_column(String(80), primary_key=True, default=new_audit_id) pivot: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True) character_id: Mapped[str | None] = mapped_column( String(80), ForeignKey("characters.id"), index=True ) run_id: Mapped[str | None] = mapped_column(String(80), ForeignKey("runs.id"), index=True) action: Mapped[str] = mapped_column(String(120), nullable=False) actor: Mapped[str] = mapped_column(String(80), nullable=False, default="system") risk_level: Mapped[str] = mapped_column(String(20), nullable=False, default="L1") decision: Mapped[str] = mapped_column(String(40), nullable=False, default="allow") reason: Mapped[str | None] = mapped_column(Text) input_summary: Mapped[str | None] = mapped_column(Text) output_summary: Mapped[str | None] = mapped_column(Text) trace_id: Mapped[str | None] = mapped_column(String(80), index=True) resource_type: Mapped[str | None] = mapped_column(String(80)) resource_id: Mapped[str | None] = mapped_column(String(120)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) class PendingConfirmationRecord(Base): """待确认工具调用的持久化记录(多 worker 共享确认状态)。 对应 ``modules/safety/confirmation.py`` 的 ``PendingConfirmation`` 值对象。 ``status`` 流转:pending → consumed / timed_out。 """ __tablename__ = "pending_confirmations" id: Mapped[str] = mapped_column(String(80), primary_key=True) tool: Mapped[str] = mapped_column(String(120), nullable=False) input_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}") risk_level: Mapped[str] = mapped_column(String(40), nullable=False, default="L2") reason: Mapped[str] = mapped_column(Text, nullable=False, default="") run_id: Mapped[str | None] = mapped_column(String(80), index=True) character_id: Mapped[str | None] = mapped_column(String(80), index=True) trace_id: Mapped[str | None] = mapped_column(String(80)) status: Mapped[str] = mapped_column(String(40), nullable=False, default="pending", index=True) # M5 请命改造:超时=拒绝执行(HJ-1302);brief_json 为请命六要素说明 expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) brief_json: Mapped[str] = mapped_column(Text, nullable=False, default="{}", server_default="{}") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))