Files
ewoooc/database/autoheal_models.py
ogt d5c0feab5e
All checks were successful
CD Pipeline / deploy (push) Successful in 1m35s
fix: Telegram bot 全功能修復 — 16個await按鈕/AI對話/模型遷移/DB schema
## Telegram Bot 功能修復
- 補全 16 個 await: 按鈕的 handler(日期選擇/目標設定/促銷追蹤等),
  新增 _handle_await_callback + _process_await_input 完整狀態機
- cmd: 按鈕加入  即時回饋 + try/except 防 BadRequest
- handle_callback 加頂層 try/except 錯誤兜底
- 補 momo:cmd:suggestion + momo:menu:main callback handler
- 修復 _enhanced_keyword_matching context NameError

## AI 模型遷移(hermes3@111 → qwen2.5@188)
- hermes_analyst_service: URL 192.168.0.111→188, hermes3→qwen2.5:7b-instruct
- code_review_pipeline: 改用 HERMES_URL/HERMES_MODEL 常數
- elephant_alpha_orchestrator / nemoton_dispatcher: registry/footprint 同步
- aider_heal_executor: OLLAMA_API_BASE fallback 改 188
- ai_routes: footprint display 字串改 qwen2.5:7b-instruct

## ElephantAlpha 404 修復
- elephant_service: openrouter→NVIDIA NIM, nvidia/llama-3.1-nemotron-ultra-253b-v1
- ai_provider: 模型 ID 同步更新

## TELEGRAM_CHAT_ID 環境變數修正
- cicd_routes + aider_heal_executor: 優先讀 TELEGRAM_CHAT_IDS[0],
  fallback TELEGRAM_CHAT_ID,修復通知靜默失敗

## AI 對話 logging 改善
- telegram_ai_integration: Hermes 降級改 WARNING,OpenClaw 失敗加 exc_info
- hermes_analyst_service: 連線失敗 log 加 host/model context

## DB Schema 修復
- migrations/019: action_plans 補齊全欄位,DROP NOT NULL action_type
- autoheal_models: ActionPlan ORM 同步為超集 schema

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 03:30:14 +08:00

208 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, ForeignKey, Index, Float
from sqlalchemy.orm import relationship
from database.models import Base
from datetime import datetime
class AgentContext(Base):
"""
共享上下文表(替代硬編碼鏈),支援多 Agent 存取與 TTL。
索引:(session_id, agent_name, context_key) 以加速跨 Agent 查詢。
"""
__tablename__ = 'agent_context'
id = Column(Integer, primary_key=True, autoincrement=True)
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 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},
)
class ActionPlan(Base):
"""
行動計畫表 — 統一 schema超集
Group A01-init.sql / CodeReview / OpenClaw:
action_type, description, priority, metadata_json
Group Bmigration 017 / watcher_agent / ai_orchestrator:
session_id, plan_type, sku, payload, created_by, approved_by, executed_at
migration 019 已在 DB 補齊所有欄位。
"""
__tablename__ = 'action_plans'
id = Column(Integer, primary_key=True, autoincrement=True)
# Group A columns
action_type = Column(String(100), nullable=True) # code_review_fix / openclaw_recommendation
description = Column(Text) # 人類可讀的行動說明
status = Column(String(50), default='pending') # pending/auto_pending/pending_review/executed
priority = Column(Integer, default=3) # 1=critical 2=high 3=medium 4=low
metadata_json = Column(Text) # JSON: pipeline_id/commit_sha/findings
created_at = Column(DateTime, default=datetime.now)
# Group B columns (ADR-012 / NemoTron)
session_id = Column(String(64), nullable=True)
plan_type = Column(String(50), nullable=True) # price_adjust / restock / campaign
sku = Column(String(100), nullable=True)
payload = Column(Text) # JSON 行動內容
created_by = Column(String(50)) # nemotron / openclaw
approved_by = Column(String(100), nullable=True) # Telegram user_id
executed_at = Column(DateTime, nullable=True)
__table_args__ = (
Index('idx_action_plans_type', 'action_type'),
Index('idx_action_plan_sku_status', 'sku', 'status'),
Index('idx_action_plan_created', 'created_at'),
{'extend_existing': True},
)
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)
metric_type = Column(String(50), nullable=True) # sales_7d / price_rank / conversion
before_val = Column(Float)
after_val = Column(Float)
measured_at = Column(DateTime)
verdict = Column(String(20)) # effective / neutral / backfired
created_at = Column(DateTime, default=datetime.now)
plan = relationship("ActionPlan", backref="outcomes")
class AgentStrategyWeights(Base):
"""
Agent strategy weights (OpenClaw learning accumulation).
Index: strategy_key for fast updates/query.
"""
__tablename__ = 'agent_strategy_weights'
id = Column(Integer, primary_key=True, autoincrement=True)
strategy_key = Column(String(100), unique=True, nullable=False) # e.g. price_cut_when_gap_gt_5pct
weight = Column(Float, default=1.0)
success_cnt = Column(Integer, default=0)
fail_cnt = Column(Integer, default=0)
updated_at = Column(DateTime, default=datetime.now)
__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
}
]