feat(packages): Phase 6.4a-c leWOOOgo modular architecture
New packages: - packages/lewooogo-brain: AI reasoning & decision engine - IProposalEngine interface (ABC) - IIncidentProcessor interface (ABC) - Pydantic models: Proposal, Guardrails, Incident, Signal - packages/lewooogo-data: Memory provider abstraction - IMemoryProvider interface (ABC) - IDualMemoryProvider for Working + Episodic memory - Generic type support for flexible data models Documentation: - ADR-008: Python modular packages architecture decision - ARCHITECTURE_MEMORY.md: Module map index for AI developers - LOGBOOK.md: Updated milestones and Phase 6.4 status Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
94
docs/ARCHITECTURE_MEMORY.md
Normal file
94
docs/ARCHITECTURE_MEMORY.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# AWOOOI 架構記憶地圖 (Architecture Memory)
|
||||
|
||||
> AI 模組地圖索引 - 每次新增積木後必須登記
|
||||
|
||||
**最後更新**: 2026-03-23
|
||||
**維護者**: Claude Code + C-Suite
|
||||
|
||||
---
|
||||
|
||||
## 📦 Python 積木 (packages/)
|
||||
|
||||
| 積木名稱 | 職責 | 對外介面 | ADR |
|
||||
|----------|------|----------|-----|
|
||||
| **lewooogo-brain** | AI 推論與決策邏輯 | `IProposalEngine`, `IIncidentProcessor` | ADR-008 |
|
||||
| **lewooogo-data** | 資料抽象與持久化 | `IMemoryProvider`, `IDualMemoryProvider` | ADR-008 |
|
||||
|
||||
### lewooogo-brain 模組結構
|
||||
|
||||
```
|
||||
packages/lewooogo-brain/
|
||||
├── src/lewooogo_brain/
|
||||
│ ├── interfaces/ # ABC 定義
|
||||
│ │ ├── proposal_engine.py → IProposalEngine
|
||||
│ │ └── incident_processor.py → IIncidentProcessor
|
||||
│ ├── engines/ # 推論引擎實作
|
||||
│ │ ├── proposal_engine.py # 🔲 待實作
|
||||
│ │ └── incident_engine.py # 🔲 待搬遷
|
||||
│ └── skills/ # Skill 動態載入
|
||||
│ └── loader.py # 🔲 待實作
|
||||
```
|
||||
|
||||
### lewooogo-data 模組結構
|
||||
|
||||
```
|
||||
packages/lewooogo-data/
|
||||
├── src/lewooogo_data/
|
||||
│ ├── interfaces/ # ABC 定義
|
||||
│ │ └── memory_provider.py → IMemoryProvider, IDualMemoryProvider
|
||||
│ └── providers/ # 具體實作
|
||||
│ ├── redis_memory.py # 🔲 待實作
|
||||
│ ├── pg_memory.py # 🔲 待實作
|
||||
│ └── dual_memory.py # 🔲 待實作
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 TypeScript 積木 (packages/)
|
||||
|
||||
| 積木名稱 | 職責 | 對外介面 | ADR |
|
||||
|----------|------|----------|-----|
|
||||
| **lewooogo-core** | 前端 Plugin 系統 | `LeWOOOgoPlugin`, `AgentProvider`, `DataAdapter` | ADR-003 |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 模組依賴關係
|
||||
|
||||
```
|
||||
apps/api (FastAPI BFF)
|
||||
├── lewooogo-brain (AI 積木)
|
||||
│ └── lewooogo-data (資料積木)
|
||||
└── lewooogo-data (直接引用)
|
||||
|
||||
apps/web (Next.js)
|
||||
└── lewooogo-core (TS 積木)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 介面契約索引
|
||||
|
||||
### Python 介面
|
||||
|
||||
| 介面 | 位置 | 職責 |
|
||||
|------|------|------|
|
||||
| `IProposalEngine` | `lewooogo_brain.interfaces` | 決策提案生成 |
|
||||
| `IIncidentProcessor` | `lewooogo_brain.interfaces` | 事件聚合處理 |
|
||||
| `IMemoryProvider` | `lewooogo_data.interfaces` | 單層記憶體存取 |
|
||||
| `IDualMemoryProvider` | `lewooogo_data.interfaces` | 雙層記憶體 (Working + Episodic) |
|
||||
|
||||
### HTTP API 契約
|
||||
|
||||
| 端點 | 位置 | 職責 |
|
||||
|------|------|------|
|
||||
| `POST /api/v1/incidents/{id}/propose` | `apps/api/src/api/v1/incidents.py` | 生成決策提案 |
|
||||
| `GET /api/v1/incidents/{id}` | `apps/api/src/api/v1/incidents.py` | 取得事件詳情 |
|
||||
|
||||
---
|
||||
|
||||
## 🚨 AI 開發者注意事項
|
||||
|
||||
1. **新增積木前**: 先讀取此檔案確認命名不衝突
|
||||
2. **新增積木後**: 必須在此檔案登記職責與對外介面
|
||||
3. **修改介面前**: 先讀取 `docs/adr/` 確認架構決策
|
||||
4. **跨模組引用**: 禁止直接 import,必須透過介面抽象
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
| 項目 | 狀態 |
|
||||
|------|------|
|
||||
| **當前 Phase** | **Phase 6.3 完成** - Incident Engine v1 (告警聚合核心) |
|
||||
| **Day** | Day 4 |
|
||||
| **下一步** | Phase 6.4 Decision Proposal API |
|
||||
| **重大變更** | 🧠 **認知覺醒計畫 6.0-6.3 竣工**: Event Bus + 海馬迴 + 聚合引擎全線貫通 |
|
||||
| **當前 Phase** | **Phase 6.4 實作中** - 模組化架構重整 + Decision Proposal |
|
||||
| **Day** | Day 5 |
|
||||
| **下一步** | Phase 6.4d MemoryProvider 實作 |
|
||||
| **重大變更** | 🚨 **生產事故修復**: Worker CrashLoopBackOff (7h) + 簽核卡片 Race Condition |
|
||||
|
||||
### 🧠 認知覺醒計畫 Phase 6 施工順序 (C-Suite 2026-03-22 決議)
|
||||
### 🧠 認知覺醒計畫 Phase 6 施工順序 (C-Suite 2026-03-23 統帥方案)
|
||||
|
||||
| 步驟 | 項目 | 部署位置 | 工時 | 狀態 |
|
||||
|------|------|---------|------|------|
|
||||
@@ -23,8 +23,16 @@
|
||||
| 6.2.1 | Working Memory (Redis Hash) | .188 Redis | 1d | ✅ 完成 |
|
||||
| 6.2.2 | Episodic Memory (PostgreSQL) | .188 PostgreSQL | 1d | ✅ 完成 |
|
||||
| 6.3 | Incident Engine v1 | .188 API | 3d | ✅ 完成 |
|
||||
| 6.4 | Decision Proposal API | .188 API | 1d | 🔲 待辦 |
|
||||
| 6.5 | Sensor Agent (各主機) | .110/.112/.120 | 2d | 🔲 待辦 |
|
||||
| **6.4a** | **lewooogo-brain 骨架** | `packages/` | 1h | ✅ 完成 |
|
||||
| **6.4b** | **lewooogo-data 骨架** | `packages/` | 1h | ✅ 完成 |
|
||||
| **6.4c** | **Interface 定義 (ABC)** | `packages/` | 2h | ✅ 完成 |
|
||||
| **6.4d** | **MemoryProvider 實作** | `packages/` | 4h | 🔲 待辦 |
|
||||
| **6.4e** | **Engine 搬遷** | `packages/` | 4h | 🔲 待辦 |
|
||||
| **6.4f** | **SkillLoader** | `packages/` | 2h | 🔲 待辦 |
|
||||
| **6.4g** | **apps/api 引用更新** | `apps/api` | 2h | 🔲 待辦 |
|
||||
| **6.4h** | **Decision Proposal API** | .188 API | 4h | 🔲 待辦 |
|
||||
| 6.5 | Runner 整合 + 5+1 狀態機 | .188 API | 4h | 🔲 待辦 |
|
||||
| 6.6 | Sensor Agent (各主機) | .110/.112/.120 | 2d | 🔲 待辦 |
|
||||
|
||||
---
|
||||
|
||||
@@ -32,6 +40,11 @@
|
||||
|
||||
| 時間 | 事件 | 負責人 |
|
||||
|------|------|--------|
|
||||
| 2026-03-23 09:30 | **🔧 NetworkPolicy 修復**: `allow-required-egress` podSelector 改為 `system=awoooi` (原本只允許 API pod) | Claude Code |
|
||||
| 2026-03-23 09:20 | **🚨 生產修復 #2**: Worker CrashLoopBackOff 92次 + `init_redis` → `init_redis_pool` 函數名修正 + 7h 無告警根因 | Claude Code |
|
||||
| 2026-03-23 09:15 | **🚨 生產修復 #1**: 簽核卡片閃爍消失 + Polling Race Condition + approval.store.ts 暫停/恢復機制 | Claude Code |
|
||||
| 2026-03-23 09:10 | **📚 Skills 更新**: 05-awoooi-sre-qa.md + 新增 CrashLoopBackOff 診斷 + Race Condition 偵測 + Telegram 健康檢查 | Claude Code |
|
||||
| 2026-03-23 10:30 | **🧱 C-Suite 模組化架構評審**: 統帥質疑積木化原則淡化 + 後端缺 lewooogo-brain/data 積木 + 方案 B 漸進式拆分 (Interface→Memory→Brain→Skill) + 2.5d 工時評估 + 施工順序重排 | C-Suite + Claude Code |
|
||||
| 2026-03-23 01:10 | **🚀 Signal Worker 啟用**: `replicas: 0→1` + Redis Streams Consumer 正式上線 + Incident Engine 處理鏈完整 | CTO + Claude Code |
|
||||
| 2026-03-23 01:05 | **🎯 實彈告警發射成功**: 4 發告警注入 Redis Streams (HarborOOMKilled/HighCPU/DBTimeout/RedisMemory) + message_id 確認 | CTO + Claude Code |
|
||||
| 2026-03-23 00:55 | **📊 GlobalPulse 脈搏恢復**: SignOz v3 表修正 + RPS 5.4/Error 25%/P99 3s 真實數據顯示 | CTO + Claude Code |
|
||||
|
||||
146
docs/adr/ADR-008-python-modular-packages.md
Normal file
146
docs/adr/ADR-008-python-modular-packages.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# ADR-008: Python 模組化獨立積木架構
|
||||
|
||||
**狀態**: 已批准
|
||||
**日期**: 2026-03-23
|
||||
**決策者**: CEO (統帥) + C-Suite
|
||||
**執行者**: CTO + Claude Code
|
||||
|
||||
## 背景
|
||||
|
||||
AWOOOI 2.0 的後端 Python 代碼 (`apps/api/src/services/`) 出現以下問題:
|
||||
|
||||
1. **模組化原則淡化**: 所有邏輯直接寫在 `services/` 目錄,未建立獨立積木
|
||||
2. **跨模組非法引用**: `proposal_service.py` 直接 import `redis_client`, `db.base`
|
||||
3. **前後端積木不對稱**: 前端有 `packages/lewooogo-core` (TS),後端無對應 Python 積木
|
||||
4. **Skill Registry 缺失**: 6 個 Skill MD 檔案無動態載入機制
|
||||
|
||||
## 決策
|
||||
|
||||
**採用統帥方案 (方案 A): 在 `packages/` 下建立獨立 Python 積木**
|
||||
|
||||
### 放棄的方案
|
||||
|
||||
- **方案 B (漸進式)**: 在 `apps/api/src/` 內建立 `brain/`、`memory/` 模組
|
||||
- **理由**: 無法達成真正的物理隔離,違反 leWOOOgo 積木化原則
|
||||
|
||||
### 採用的技術
|
||||
|
||||
```toml
|
||||
# apps/api/pyproject.toml
|
||||
dependencies = [
|
||||
"lewooogo-brain @ file:../../packages/lewooogo-brain",
|
||||
"lewooogo-data @ file:../../packages/lewooogo-data",
|
||||
]
|
||||
```
|
||||
|
||||
使用 `pip install -e .` (Editable Install) 達成本地聯動開發。
|
||||
|
||||
## 積木職責定義
|
||||
|
||||
### lewooogo-brain (AI 邏輯積木)
|
||||
|
||||
| 模組 | 職責 |
|
||||
|------|------|
|
||||
| `interfaces/` | ABC 定義 (IProposalEngine, IIncidentProcessor) |
|
||||
| `engines/` | 推論引擎 (IncidentEngine, ProposalEngine) |
|
||||
| `skills/` | Skill 動態載入器 |
|
||||
|
||||
### lewooogo-data (資料抽象積木)
|
||||
|
||||
| 模組 | 職責 |
|
||||
|------|------|
|
||||
| `interfaces/` | ABC 定義 (IMemoryProvider) |
|
||||
| `providers/` | 具體實作 (RedisMemory, PgMemory) |
|
||||
|
||||
## 目錄結構
|
||||
|
||||
```
|
||||
packages/
|
||||
├── lewooogo-core/ # TS 前端積木 (已有)
|
||||
├── lewooogo-brain/ # Python AI 積木 (新建)
|
||||
│ ├── pyproject.toml
|
||||
│ └── src/lewooogo_brain/
|
||||
│ ├── __init__.py
|
||||
│ ├── interfaces/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── proposal_engine.py
|
||||
│ │ └── incident_processor.py
|
||||
│ ├── engines/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── incident_engine.py
|
||||
│ │ └── proposal_engine.py
|
||||
│ └── skills/
|
||||
│ ├── __init__.py
|
||||
│ └── loader.py
|
||||
└── lewooogo-data/ # Python 資料積木 (新建)
|
||||
├── pyproject.toml
|
||||
└── src/lewooogo_data/
|
||||
├── __init__.py
|
||||
├── interfaces/
|
||||
│ ├── __init__.py
|
||||
│ └── memory_provider.py
|
||||
└── providers/
|
||||
├── __init__.py
|
||||
├── redis_memory.py
|
||||
└── pg_memory.py
|
||||
```
|
||||
|
||||
## 引用方式
|
||||
|
||||
```python
|
||||
# apps/api/src/api/v1/incidents.py
|
||||
from lewooogo_brain.engines import ProposalEngine
|
||||
from lewooogo_data.providers import RedisMemory
|
||||
|
||||
engine = ProposalEngine(memory=RedisMemory())
|
||||
proposal = await engine.generate(incident_id)
|
||||
```
|
||||
|
||||
## 依賴配置
|
||||
|
||||
### lewooogo-brain
|
||||
|
||||
```toml
|
||||
dependencies = [
|
||||
"pydantic>=2.5.0",
|
||||
"structlog>=24.1.0",
|
||||
"opentelemetry-api>=1.20.0",
|
||||
"lewooogo-data", # 依賴資料積木
|
||||
]
|
||||
```
|
||||
|
||||
### lewooogo-data
|
||||
|
||||
```toml
|
||||
dependencies = [
|
||||
"pydantic>=2.5.0",
|
||||
"redis>=5.0.0",
|
||||
"sqlalchemy[asyncio]>=2.0.0",
|
||||
"structlog>=24.1.0",
|
||||
]
|
||||
```
|
||||
|
||||
## 後果
|
||||
|
||||
### 優點
|
||||
|
||||
1. **完全物理隔離**: Brain 和 Data 積木可獨立測試、獨立部署
|
||||
2. **可複用性**: 其他專案可直接引用這些積木
|
||||
3. **符合 leWOOOgo 原則**: 高內聚、低耦合
|
||||
4. **介面先行**: 強制定義 ABC,再實作具體類別
|
||||
|
||||
### 缺點
|
||||
|
||||
1. **初期工時增加**: 約 3-4 天建立積木骨架
|
||||
2. **依賴管理複雜度**: 需維護多個 pyproject.toml
|
||||
3. **學習曲線**: 團隊需適應新的引用方式
|
||||
|
||||
## 相關決策
|
||||
|
||||
- ADR-003: leWOOOgo 模組架構 (前端 TS 版)
|
||||
- ADR-005: BFF 閘道架構
|
||||
|
||||
## 參考資料
|
||||
|
||||
- [Python Packaging User Guide](https://packaging.python.org/)
|
||||
- [PEP 621 – Storing project metadata in pyproject.toml](https://peps.python.org/pep-0621/)
|
||||
41
packages/lewooogo-brain/README.md
Normal file
41
packages/lewooogo-brain/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# leWOOOgo Brain
|
||||
|
||||
> AI Reasoning & Decision Engine for AWOOOI 2.0
|
||||
|
||||
## Overview
|
||||
|
||||
leWOOOgo Brain 是 AWOOOI 智能運維平台的 AI 推論核心積木,負責:
|
||||
|
||||
- **決策提案**: 分析 Incident 生成修復建議
|
||||
- **事件處理**: 聚合告警、分析爆炸半徑
|
||||
- **Skill 載入**: 動態載入專業技能模組
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# 在 apps/api 中使用
|
||||
pip install -e ../../packages/lewooogo-brain
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from lewooogo_brain.interfaces import IProposalEngine
|
||||
from lewooogo_brain.engines import ProposalEngine
|
||||
|
||||
# 使用決策引擎
|
||||
engine = ProposalEngine(memory=memory_provider)
|
||||
proposal, message = await engine.generate(incident_id)
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Description |
|
||||
|--------|-------------|
|
||||
| `interfaces/` | ABC 定義 |
|
||||
| `engines/` | 推論引擎 |
|
||||
| `skills/` | Skill 載入器 |
|
||||
|
||||
## ADR Reference
|
||||
|
||||
- [ADR-008: Python 模組化獨立積木架構](../../docs/adr/ADR-008-python-modular-packages.md)
|
||||
58
packages/lewooogo-brain/pyproject.toml
Normal file
58
packages/lewooogo-brain/pyproject.toml
Normal file
@@ -0,0 +1,58 @@
|
||||
[project]
|
||||
name = "lewooogo-brain"
|
||||
version = "0.1.0"
|
||||
description = "leWOOOgo Brain - AI Reasoning & Decision Engine for AWOOOI"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "AWOOOI Team", email = "team@awoooi.dev"},
|
||||
]
|
||||
keywords = ["awoooi", "lewooogo", "aiops", "decision-engine"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"pydantic>=2.5.0",
|
||||
"structlog>=24.1.0",
|
||||
"opentelemetry-api>=1.20.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=7.4.0",
|
||||
"pytest-asyncio>=0.23.0",
|
||||
"pytest-cov>=4.1.0",
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.8.0",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/lewooogo_brain"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 88
|
||||
select = ["E", "W", "F", "I", "B", "C4", "UP"]
|
||||
ignore = ["E501"]
|
||||
|
||||
[tool.ruff.isort]
|
||||
known-first-party = ["lewooogo_brain"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.11"
|
||||
strict = true
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
testpaths = ["tests"]
|
||||
25
packages/lewooogo-brain/src/lewooogo_brain/__init__.py
Normal file
25
packages/lewooogo-brain/src/lewooogo_brain/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
leWOOOgo Brain - AI Reasoning & Decision Engine
|
||||
================================================
|
||||
|
||||
AWOOOI 2.0 的 AI 推論核心積木
|
||||
|
||||
模組結構:
|
||||
- interfaces/ ABC 定義 (IProposalEngine, IIncidentProcessor)
|
||||
- engines/ 推論引擎 (IncidentEngine, ProposalEngine)
|
||||
- skills/ Skill 動態載入器
|
||||
|
||||
使用方式:
|
||||
from lewooogo_brain.engines import ProposalEngine
|
||||
from lewooogo_brain.interfaces import IProposalEngine
|
||||
|
||||
統帥鐵律:
|
||||
- 所有引擎必須實作對應的 Interface (ABC)
|
||||
- 禁止直接引用外部模組,必須透過依賴注入
|
||||
- 所有決策必須可稽核 (AIDecisionChain)
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = [
|
||||
"__version__",
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
leWOOOgo Brain Engines - 推論引擎
|
||||
==================================
|
||||
|
||||
具體實作 IProposalEngine 和 IIncidentProcessor
|
||||
|
||||
引擎列表:
|
||||
- ProposalEngine: 決策提案引擎
|
||||
- IncidentEngine: 事件處理引擎
|
||||
"""
|
||||
|
||||
# TODO: Phase 6.4e 搬遷後啟用
|
||||
# from lewooogo_brain.engines.proposal_engine import ProposalEngine
|
||||
# from lewooogo_brain.engines.incident_engine import IncidentEngine
|
||||
|
||||
__all__: list[str] = [
|
||||
# "ProposalEngine",
|
||||
# "IncidentEngine",
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
leWOOOgo Brain Interfaces - ABC 定義
|
||||
=====================================
|
||||
|
||||
所有引擎必須實作這些抽象介面
|
||||
|
||||
介面列表:
|
||||
- IProposalEngine: 決策提案引擎介面
|
||||
- IIncidentProcessor: 事件處理器介面
|
||||
"""
|
||||
|
||||
from lewooogo_brain.interfaces.proposal_engine import IProposalEngine
|
||||
from lewooogo_brain.interfaces.incident_processor import IIncidentProcessor
|
||||
|
||||
__all__ = [
|
||||
"IProposalEngine",
|
||||
"IIncidentProcessor",
|
||||
]
|
||||
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
IIncidentProcessor - 事件處理器介面
|
||||
===================================
|
||||
|
||||
定義 Incident 處理的標準介面
|
||||
|
||||
統帥鐵律:
|
||||
- 禁止告警風暴 (相關告警必須聚合)
|
||||
- 禁止 O(N) 掃描 (所有查詢必須 O(1))
|
||||
- 禁止 Race Condition (所有寫入必須原子操作)
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
from pydantic import BaseModel, Field
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
class IncidentStatus(str, Enum):
|
||||
"""事件狀態"""
|
||||
INVESTIGATING = "investigating"
|
||||
MITIGATING = "mitigating"
|
||||
RESOLVED = "resolved"
|
||||
CLOSED = "closed"
|
||||
|
||||
|
||||
class Severity(str, Enum):
|
||||
"""嚴重等級"""
|
||||
P0 = "P0" # Critical
|
||||
P1 = "P1" # High
|
||||
P2 = "P2" # Warning
|
||||
P3 = "P3" # Info
|
||||
|
||||
|
||||
class Signal(BaseModel):
|
||||
"""告警信號"""
|
||||
alert_name: str
|
||||
severity: Severity
|
||||
source: str
|
||||
fired_at: datetime
|
||||
labels: dict[str, str] = {}
|
||||
annotations: dict[str, str] = {}
|
||||
fingerprint: str | None = None
|
||||
|
||||
|
||||
class Incident(BaseModel):
|
||||
"""事件資料結構"""
|
||||
incident_id: str
|
||||
status: IncidentStatus = IncidentStatus.INVESTIGATING
|
||||
severity: Severity = Severity.P2
|
||||
signals: list[Signal] = []
|
||||
affected_services: list[str] = []
|
||||
proposal_ids: list[UUID] = []
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
updated_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
resolved_at: datetime | None = None
|
||||
closed_at: datetime | None = None
|
||||
|
||||
|
||||
class IIncidentProcessor(ABC):
|
||||
"""
|
||||
事件處理器介面
|
||||
|
||||
職責:
|
||||
1. 聚合相關告警到同一 Incident
|
||||
2. 分析爆炸半徑 (透過 GraphRAG)
|
||||
3. 雙層持久化 (Working + Episodic Memory)
|
||||
|
||||
使用方式:
|
||||
class MyIncidentProcessor(IIncidentProcessor):
|
||||
async def process_signal(self, signal_data: dict) -> Incident | None:
|
||||
# 實作邏輯
|
||||
pass
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def process_signal(
|
||||
self,
|
||||
signal_data: dict[str, Any],
|
||||
) -> Incident | None:
|
||||
"""
|
||||
處理告警信號
|
||||
|
||||
Args:
|
||||
signal_data: 告警資料 (來自 Redis Streams)
|
||||
|
||||
Returns:
|
||||
Incident | None: 處理後的事件 (可能是新建或聚合)
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def get_incident(
|
||||
self,
|
||||
incident_id: str,
|
||||
) -> Incident | None:
|
||||
"""
|
||||
取得事件
|
||||
|
||||
Args:
|
||||
incident_id: 事件 ID
|
||||
|
||||
Returns:
|
||||
Incident | None
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def update_status(
|
||||
self,
|
||||
incident_id: str,
|
||||
status: IncidentStatus,
|
||||
) -> bool:
|
||||
"""
|
||||
更新事件狀態
|
||||
|
||||
Args:
|
||||
incident_id: 事件 ID
|
||||
status: 新狀態
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
...
|
||||
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
IProposalEngine - 決策提案引擎介面
|
||||
==================================
|
||||
|
||||
定義 Proposal 生成的標準介面
|
||||
|
||||
統帥鐵律:
|
||||
- 所有 Proposal 必須包含 Guardrails
|
||||
- 禁止跳過 TrustEngine 評估
|
||||
- 所有決策必須可稽核
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Protocol
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Proposal(BaseModel):
|
||||
"""決策提案資料結構"""
|
||||
proposal_id: str
|
||||
incident_id: str
|
||||
action: str
|
||||
description: str
|
||||
risk_level: str
|
||||
guardrails: dict[str, Any]
|
||||
metadata: dict[str, Any] = {}
|
||||
|
||||
|
||||
class Guardrails(BaseModel):
|
||||
"""安全護欄配置"""
|
||||
require_dry_run: bool = True
|
||||
allowed_namespace: list[str] = ["awoooi-prod"]
|
||||
forbidden_commands: list[str] = ["rm -rf", "drop table", "kubectl delete ns"]
|
||||
max_retries: int = 1
|
||||
timeout_sec: int = 60
|
||||
audit_log: str = "mandatory"
|
||||
rollback_window_sec: int = 300
|
||||
|
||||
|
||||
class IMemoryProvider(Protocol):
|
||||
"""記憶體提供者協定 (來自 lewooogo_data)"""
|
||||
async def load_incident(self, incident_id: str) -> Any | None: ...
|
||||
async def save_incident(self, incident: Any) -> None: ...
|
||||
|
||||
|
||||
class IProposalEngine(ABC):
|
||||
"""
|
||||
決策提案引擎介面
|
||||
|
||||
職責:
|
||||
1. 分析 Incident 生成修復建議
|
||||
2. 評估風險等級
|
||||
3. 建立 ApprovalRequest
|
||||
4. 更新 Incident 狀態
|
||||
|
||||
使用方式:
|
||||
class MyProposalEngine(IProposalEngine):
|
||||
async def generate(self, incident_id: str) -> tuple[Proposal | None, str]:
|
||||
# 實作邏輯
|
||||
pass
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def generate(
|
||||
self,
|
||||
incident_id: str,
|
||||
) -> tuple[Proposal | None, str]:
|
||||
"""
|
||||
生成決策提案
|
||||
|
||||
Args:
|
||||
incident_id: 事件 ID
|
||||
|
||||
Returns:
|
||||
(Proposal, message) 或 (None, error_message)
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def generate_with_skill(
|
||||
self,
|
||||
incident_id: str,
|
||||
skill_id: str,
|
||||
) -> tuple[Proposal | None, str]:
|
||||
"""
|
||||
使用指定 Skill 生成決策提案
|
||||
|
||||
Args:
|
||||
incident_id: 事件 ID
|
||||
skill_id: Skill 識別碼 (e.g., "04-awoooi-devops-commander")
|
||||
|
||||
Returns:
|
||||
(Proposal, message) 或 (None, error_message)
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def get_default_guardrails(self) -> Guardrails:
|
||||
"""取得預設安全護欄配置"""
|
||||
...
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
leWOOOgo Brain Skills - Skill 動態載入
|
||||
=======================================
|
||||
|
||||
動態載入 .agents/skills/*.md 並注入到推論引擎
|
||||
|
||||
模組列表:
|
||||
- SkillLoader: Skill 載入器
|
||||
- SkillRegistry: Skill → Incident 類型對映
|
||||
"""
|
||||
|
||||
# TODO: Phase 6.4f 實作後啟用
|
||||
# from lewooogo_brain.skills.loader import SkillLoader
|
||||
# from lewooogo_brain.skills.registry import SkillRegistry
|
||||
|
||||
__all__: list[str] = [
|
||||
# "SkillLoader",
|
||||
# "SkillRegistry",
|
||||
]
|
||||
48
packages/lewooogo-data/README.md
Normal file
48
packages/lewooogo-data/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# leWOOOgo Data
|
||||
|
||||
> Memory Provider Abstraction Layer for AWOOOI 2.0
|
||||
|
||||
## Overview
|
||||
|
||||
leWOOOgo Data 是 AWOOOI 智能運維平台的資料抽象層積木,負責:
|
||||
|
||||
- **Working Memory**: Redis 快取 (7 天 TTL)
|
||||
- **Episodic Memory**: PostgreSQL/SQLite 永久保存
|
||||
- **Dual Memory**: 雙層同步寫入
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# 在 apps/api 中使用
|
||||
pip install -e ../../packages/lewooogo-data
|
||||
|
||||
# 如需 PostgreSQL 支援
|
||||
pip install -e "../../packages/lewooogo-data[pg]"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from lewooogo_data.interfaces import IMemoryProvider
|
||||
from lewooogo_data.providers import RedisMemory, PgMemory, DualMemory
|
||||
|
||||
# 使用雙層記憶體
|
||||
memory = DualMemory(
|
||||
working=RedisMemory(redis_url="redis://localhost:6379"),
|
||||
episodic=PgMemory(database_url="postgresql://...")
|
||||
)
|
||||
|
||||
# 載入 Incident
|
||||
incident = await memory.load(f"incident:{incident_id}")
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Description |
|
||||
|--------|-------------|
|
||||
| `interfaces/` | ABC 定義 |
|
||||
| `providers/` | 具體實作 |
|
||||
|
||||
## ADR Reference
|
||||
|
||||
- [ADR-008: Python 模組化獨立積木架構](../../docs/adr/ADR-008-python-modular-packages.md)
|
||||
63
packages/lewooogo-data/pyproject.toml
Normal file
63
packages/lewooogo-data/pyproject.toml
Normal file
@@ -0,0 +1,63 @@
|
||||
[project]
|
||||
name = "lewooogo-data"
|
||||
version = "0.1.0"
|
||||
description = "leWOOOgo Data - Memory Provider Abstraction Layer for AWOOOI"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "AWOOOI Team", email = "team@awoooi.dev"},
|
||||
]
|
||||
keywords = ["awoooi", "lewooogo", "data", "memory-provider", "redis", "postgresql"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"pydantic>=2.5.0",
|
||||
"structlog>=24.1.0",
|
||||
"redis>=5.0.0",
|
||||
"sqlalchemy[asyncio]>=2.0.0",
|
||||
"aiosqlite>=0.19.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=7.4.0",
|
||||
"pytest-asyncio>=0.23.0",
|
||||
"pytest-cov>=4.1.0",
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.8.0",
|
||||
]
|
||||
pg = [
|
||||
"asyncpg>=0.29.0",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/lewooogo_data"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
line-length = 88
|
||||
select = ["E", "W", "F", "I", "B", "C4", "UP"]
|
||||
ignore = ["E501"]
|
||||
|
||||
[tool.ruff.isort]
|
||||
known-first-party = ["lewooogo_data"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.11"
|
||||
strict = true
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
testpaths = ["tests"]
|
||||
24
packages/lewooogo-data/src/lewooogo_data/__init__.py
Normal file
24
packages/lewooogo-data/src/lewooogo_data/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
leWOOOgo Data - Memory Provider Abstraction Layer
|
||||
==================================================
|
||||
|
||||
AWOOOI 2.0 的資料抽象層積木
|
||||
|
||||
模組結構:
|
||||
- interfaces/ ABC 定義 (IMemoryProvider)
|
||||
- providers/ 具體實作 (RedisMemory, PgMemory)
|
||||
|
||||
使用方式:
|
||||
from lewooogo_data.providers import RedisMemory
|
||||
from lewooogo_data.interfaces import IMemoryProvider
|
||||
|
||||
統帥鐵律:
|
||||
- 所有 Provider 必須實作 IMemoryProvider
|
||||
- Working Memory (Redis): TTL 7 天
|
||||
- Episodic Memory (PG/SQLite): 永久保存
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = [
|
||||
"__version__",
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
leWOOOgo Data Interfaces - ABC 定義
|
||||
====================================
|
||||
|
||||
所有 Provider 必須實作這些抽象介面
|
||||
|
||||
介面列表:
|
||||
- IMemoryProvider: 記憶體提供者介面
|
||||
"""
|
||||
|
||||
from lewooogo_data.interfaces.memory_provider import IMemoryProvider
|
||||
|
||||
__all__ = [
|
||||
"IMemoryProvider",
|
||||
]
|
||||
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
IMemoryProvider - 記憶體提供者介面
|
||||
===================================
|
||||
|
||||
定義資料存取的標準介面
|
||||
|
||||
記憶層級:
|
||||
- Working Memory (Redis): 7 天 TTL,快速存取
|
||||
- Episodic Memory (PG/SQLite): 永久保存,可查詢
|
||||
|
||||
統帥鐵律:
|
||||
- 禁止直接存取底層資料庫
|
||||
- 所有存取必須透過 Provider 抽象
|
||||
- 雙層寫入:Working + Episodic 同步
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, TypeVar, Generic
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
class IMemoryProvider(ABC, Generic[T]):
|
||||
"""
|
||||
記憶體提供者介面
|
||||
|
||||
職責:
|
||||
1. 提供統一的資料存取抽象
|
||||
2. 隱藏底層實作細節 (Redis/PG/SQLite)
|
||||
3. 支援 TTL 與永久保存
|
||||
|
||||
使用方式:
|
||||
class RedisMemory(IMemoryProvider[Incident]):
|
||||
async def load(self, key: str) -> Incident | None:
|
||||
# 實作 Redis 存取
|
||||
pass
|
||||
|
||||
class PgMemory(IMemoryProvider[Incident]):
|
||||
async def load(self, key: str) -> Incident | None:
|
||||
# 實作 PostgreSQL 存取
|
||||
pass
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def load(self, key: str) -> T | None:
|
||||
"""
|
||||
載入資料
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
|
||||
Returns:
|
||||
T | None: 資料物件或 None
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def save(self, key: str, data: T, ttl_seconds: int | None = None) -> bool:
|
||||
"""
|
||||
儲存資料
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
data: 資料物件
|
||||
ttl_seconds: 過期時間 (秒),None 表示永久
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def delete(self, key: str) -> bool:
|
||||
"""
|
||||
刪除資料
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def exists(self, key: str) -> bool:
|
||||
"""
|
||||
檢查資料是否存在
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
|
||||
Returns:
|
||||
bool: 是否存在
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def update(self, key: str, updates: dict[str, Any]) -> bool:
|
||||
"""
|
||||
部分更新資料
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
updates: 要更新的欄位
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
class IDualMemoryProvider(ABC, Generic[T]):
|
||||
"""
|
||||
雙層記憶體提供者介面
|
||||
|
||||
統帥鐵律:Working + Episodic 同步寫入
|
||||
|
||||
使用方式:
|
||||
class DualMemory(IDualMemoryProvider[Incident]):
|
||||
def __init__(self):
|
||||
self.working = RedisMemory()
|
||||
self.episodic = PgMemory()
|
||||
|
||||
async def save(self, key: str, data: Incident) -> bool:
|
||||
# 同時寫入 Redis + PG
|
||||
pass
|
||||
"""
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def working(self) -> IMemoryProvider[T]:
|
||||
"""Working Memory Provider (Redis)"""
|
||||
...
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def episodic(self) -> IMemoryProvider[T]:
|
||||
"""Episodic Memory Provider (PG/SQLite)"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def load(self, key: str) -> T | None:
|
||||
"""
|
||||
載入資料 (Working 優先,Episodic 備援)
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
|
||||
Returns:
|
||||
T | None: 資料物件或 None
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
async def save(self, key: str, data: T) -> bool:
|
||||
"""
|
||||
雙層儲存 (Working + Episodic 同步)
|
||||
|
||||
Args:
|
||||
key: 資料鍵值
|
||||
data: 資料物件
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
...
|
||||
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
leWOOOgo Data Providers - 具體實作
|
||||
===================================
|
||||
|
||||
IMemoryProvider 的具體實作
|
||||
|
||||
Provider 列表:
|
||||
- RedisMemory: Working Memory (7 天 TTL)
|
||||
- PgMemory: Episodic Memory (永久)
|
||||
- DualMemory: 雙層記憶體 (Working + Episodic)
|
||||
"""
|
||||
|
||||
# TODO: Phase 6.4d 實作後啟用
|
||||
# from lewooogo_data.providers.redis_memory import RedisMemory
|
||||
# from lewooogo_data.providers.pg_memory import PgMemory
|
||||
# from lewooogo_data.providers.dual_memory import DualMemory
|
||||
|
||||
__all__: list[str] = [
|
||||
# "RedisMemory",
|
||||
# "PgMemory",
|
||||
# "DualMemory",
|
||||
]
|
||||
Reference in New Issue
Block a user