feat(aiops): add mcp agent loop foundation
Some checks failed
CD Pipeline / tests (push) Successful in 1m59s
Code Review / ai-code-review (push) Successful in 28s
run-migration / migrate (push) Failing after 24s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / tests (push) Successful in 1m59s
Code Review / ai-code-review (push) Successful in 28s
run-migration / migrate (push) Failing after 24s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -19,6 +19,7 @@ from sqlalchemy import (
|
||||
BigInteger,
|
||||
Boolean,
|
||||
CheckConstraint,
|
||||
Date,
|
||||
DateTime,
|
||||
Float,
|
||||
Index,
|
||||
@@ -456,6 +457,90 @@ class AuditLog(Base):
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MCP Audit / Snapshots — 2026-05-01 ghost-loop + MCP governance
|
||||
# =============================================================================
|
||||
|
||||
class MCPAuditLog(Base):
|
||||
"""Durable audit trail for every MCP tool call."""
|
||||
|
||||
__tablename__ = "mcp_audit_log"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
session_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
||||
flywheel_node: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
||||
mcp_server: Mapped[str] = mapped_column(String(80), nullable=False)
|
||||
tool_name: Mapped[str] = mapped_column(String(120), nullable=False)
|
||||
input_params: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
|
||||
output_result: Mapped[dict | list | str | None] = mapped_column(JSONB, nullable=True)
|
||||
duration_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
success: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||||
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
incident_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
agent_role: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=taipei_now)
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_mcp_audit_session", "session_id"),
|
||||
Index("idx_mcp_audit_incident", "incident_id"),
|
||||
Index("idx_mcp_audit_node", "flywheel_node", "created_at"),
|
||||
Index("idx_mcp_audit_server_tool", "mcp_server", "tool_name", "created_at"),
|
||||
Index("idx_mcp_audit_agent_role", "agent_role", "created_at"),
|
||||
)
|
||||
|
||||
|
||||
class MCPDailyStats(Base):
|
||||
"""Daily aggregate for MCP provider/tool success rate and latency."""
|
||||
|
||||
__tablename__ = "mcp_daily_stats"
|
||||
|
||||
date: Mapped[datetime] = mapped_column(Date, primary_key=True)
|
||||
mcp_server: Mapped[str] = mapped_column(String(80), primary_key=True)
|
||||
tool_name: Mapped[str] = mapped_column(String(120), primary_key=True)
|
||||
call_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
success_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
avg_duration_ms: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
|
||||
|
||||
class K8sStateSnapshot(Base):
|
||||
"""Pre/post Kubernetes resource state snapshots for remediation verification."""
|
||||
|
||||
__tablename__ = "k8s_state_snapshots"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
incident_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
snapshot_type: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
namespace: Mapped[str | None] = mapped_column(String(63), nullable=True)
|
||||
resource_type: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
resource_name: Mapped[str | None] = mapped_column(String(253), nullable=True)
|
||||
state_json: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
|
||||
captured_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=taipei_now)
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_k8s_snapshot_incident", "incident_id"),
|
||||
Index("idx_k8s_snapshot_resource", "namespace", "resource_type", "resource_name"),
|
||||
Index("idx_k8s_snapshot_captured", "captured_at"),
|
||||
)
|
||||
|
||||
|
||||
class PrometheusSnapshot(Base):
|
||||
"""Prometheus query snapshots for detect/verify flywheel stages."""
|
||||
|
||||
__tablename__ = "prometheus_snapshots"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
incident_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
query: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
result_json: Mapped[dict | list | str | None] = mapped_column(JSONB, nullable=True)
|
||||
snapshot_type: Mapped[str | None] = mapped_column(String(40), nullable=True)
|
||||
captured_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=taipei_now)
|
||||
|
||||
__table_args__ = (
|
||||
Index("idx_prom_snapshot_incident", "incident_id"),
|
||||
Index("idx_prom_snapshot_type", "snapshot_type", "captured_at"),
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# AutoRepairExecution - Phase 10 操作記錄
|
||||
# 2026-04-08 Claude Code: 統帥指令「所有操作都必須被記錄,寫入資料庫」
|
||||
|
||||
Reference in New Issue
Block a user