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:
OG T
2026-03-23 09:32:07 +08:00
parent d050dd1ecc
commit 80d0ef4a8f
17 changed files with 1007 additions and 7 deletions

View 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必須透過介面抽象

View File

@@ -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 |

View 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/)

View 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)

View 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"]

View 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__",
]

View File

@@ -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",
]

View File

@@ -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",
]

View File

@@ -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: 是否成功
"""
...

View File

@@ -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:
"""取得預設安全護欄配置"""
...

View File

@@ -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",
]

View 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)

View 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"]

View 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__",
]

View File

@@ -0,0 +1,15 @@
"""
leWOOOgo Data Interfaces - ABC 定義
====================================
所有 Provider 必須實作這些抽象介面
介面列表:
- IMemoryProvider: 記憶體提供者介面
"""
from lewooogo_data.interfaces.memory_provider import IMemoryProvider
__all__ = [
"IMemoryProvider",
]

View File

@@ -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: 是否成功
"""
...

View File

@@ -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",
]