fix: add Incident/Playbook/HealLog to autoheal_models.py (was never committed)
All checks were successful
CD Pipeline / deploy (push) Successful in 1m16s

ADR-013 AIOps classes Incident, Playbook, HealLog existed locally but were
missing from git. manager.py imports them → ImportError on every scheduler
restart. Also fixes transitive MetaData conflict with ai_models.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ogt
2026-04-20 04:50:28 +08:00
parent f2b20c1892
commit aef8982cbb

View File

@@ -15,13 +15,14 @@ class AgentContext(Base):
session_id = Column(String(64), nullable=False, index=True)
agent_name = Column(String(50), nullable=False, index=True)
context_key = Column(String(100), nullable=False)
context_val = Column(Text) # JSON 字串
context_val = Column(Text) # JSON string
created_at = Column(DateTime, default=datetime.now)
ttl_minutes = Column(Integer, default=60)
__table_args__ = (
Index('idx_agent_context_session_key', 'session_id', 'agent_name', 'context_key'),
Index('idx_agent_context_session_ttl', 'session_id', 'created_at'),
{'extend_existing': True},
)
@@ -45,6 +46,7 @@ class ActionPlan(Base):
__table_args__ = (
Index('idx_action_plan_sku_status', 'sku', 'status'),
Index('idx_action_plan_created', 'created_at'),
{'extend_existing': True},
)
@@ -53,6 +55,7 @@ class ActionOutcome(Base):
行動結果追蹤(閉環學習核心)。
"""
__tablename__ = 'action_outcomes'
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
plan_id = Column(Integer, ForeignKey('action_plans.id'), nullable=False)
@@ -68,8 +71,8 @@ class ActionOutcome(Base):
class AgentStrategyWeights(Base):
"""
Agent 策略權重OpenClaw 學習累積)。
索引:strategy_key 以便快速更新與查詢。
Agent strategy weights (OpenClaw learning accumulation).
Index: strategy_key for fast updates/query.
"""
__tablename__ = 'agent_strategy_weights'
@@ -82,4 +85,111 @@ class AgentStrategyWeights(Base):
__table_args__ = (
Index('idx_strategy_key', 'strategy_key'),
{'extend_existing': True},
)
class Incident(Base):
"""
Incident tracking for AIOps auto-healing.
"""
__tablename__ = 'incidents'
id = Column(Integer, primary_key=True, autoincrement=True)
task_name = Column(String(100), nullable=False)
error_type = Column(String(50), nullable=False)
error_message = Column(Text, nullable=False)
traceback_str = Column(Text)
severity = Column(String(20), default='medium')
status = Column(String(20), default='open') # open/healing/closed/escalated
retry_count = Column(Integer, default=0)
matched_playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=True)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now)
# Relationship
playbook = relationship("Playbook", backref="incidents")
class Playbook(Base):
"""
Playbook definitions for auto-healing actions.
"""
__tablename__ = 'playbooks'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False)
description = Column(Text)
error_type = Column(String(50), nullable=False)
match_pattern = Column(Text) # JSON array of patterns
action_type = Column(String(50), nullable=False) # DOCKER_RESTART/SSH_CMD/ALERT_ONLY/WAIT_RETRY
action_params = Column(Text) # JSON params
max_retries = Column(Integer, default=3)
cooldown_min = Column(Integer, default=30)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now)
def get_match_patterns(self):
"""Parse match_pattern JSON to list"""
if self.match_pattern:
try:
import json
return json.loads(self.match_pattern)
except:
return []
return []
def get_action_params(self):
"""Parse action_params JSON to dict"""
if self.action_params:
try:
import json
return json.loads(self.action_params)
except:
return {}
return {}
class HealLog(Base):
"""
Healing execution logs.
"""
__tablename__ = 'heal_logs'
id = Column(Integer, primary_key=True, autoincrement=True)
incident_id = Column(Integer, ForeignKey('incidents.id'), nullable=False)
playbook_id = Column(Integer, ForeignKey('playbooks.id'), nullable=False)
action_type = Column(String(50), nullable=False)
action_detail = Column(Text)
result = Column(String(20), default='unknown') # success/failed/skipped
result_output = Column(Text)
duration_ms = Column(Float)
created_at = Column(DateTime, default=datetime.now)
# Relationships
incident = relationship("Incident", backref="heal_logs")
playbook = relationship("Playbook", backref="heal_logs")
# Seed playbooks for common issues
SEED_PLAYBOOKS = [
{
'name': 'Database Connection Recovery',
'error_type': 'database',
'match_pattern': '["connection", "timeout", "unreachable"]',
'action_type': 'WAIT_RETRY',
'action_params': '{"wait_minutes": 5}',
'max_retries': 3,
'cooldown_min': 15
},
{
'name': 'Disk Space Alert',
'error_type': 'disk_space',
'match_pattern': '["disk", "space", "full", "no space"]',
'action_type': 'ALERT_ONLY',
'action_params': '{"message": "Disk space critical - manual intervention required"}',
'max_retries': 1,
'cooldown_min': 60
}
]