Phase 6.4g (API 突觸對接):
- lewooogo-brain dependency binding in apps/api/pyproject.toml
- POST /api/v1/incidents/{id}/propose route (proposals.py)
- Guardrails integration (8/8 tests passed)
Phase 6.5a (視覺皮層建置):
- DualStateIncidentCard.tsx with Nothing.tech visual compliance
- Ping radar animation for alert state
- Tier-based decision layer UI (AI 執行中 / 等待親核)
Phase 6.5b (神經網路串接):
- Main warroom page integration (page.tsx)
- IncidentResponse → DualState mapper function
- Empty state: "系統穩定。0 活躍異常。"
Tests:
- test_guardrails.py (8/8)
- test_incident_engine.py (6/6)
- test_skill_loader.py (6/6)
- Frontend build: 0 errors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
161 lines
4.5 KiB
Python
161 lines
4.5 KiB
Python
"""
|
||
SkillLoader 單元測試
|
||
====================
|
||
|
||
Phase 6.4f 驗證點 1:
|
||
確認 SkillLoader 能從 .agents/skills/ 讀取 Markdown 內容
|
||
"""
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
# 添加 src 到 Python Path
|
||
src_path = Path(__file__).parent.parent / "src"
|
||
sys.path.insert(0, str(src_path))
|
||
|
||
# 設定專案根目錄 (向上尋找 .agents/skills)
|
||
project_root = Path(__file__).parent.parent.parent.parent
|
||
|
||
|
||
def test_skill_loader_find_skills_dir():
|
||
"""測試:能找到 skills 目錄"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
assert loader._skills_path.exists(), f"Skills dir not found: {loader._skills_path}"
|
||
print(f"✅ Skills 目錄找到: {loader._skills_path}")
|
||
|
||
|
||
def test_skill_loader_load_devops_skill():
|
||
"""測試:載入 04-awoooi-devops-commander.md"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
# 用完整 ID 載入
|
||
content = loader.load("04-awoooi-devops-commander")
|
||
assert content is not None, "Failed to load skill by full ID"
|
||
assert "DevOps" in content or "devops" in content.lower(), "Content doesn't contain DevOps"
|
||
print(f"✅ 完整 ID 載入成功,內容長度: {len(content)} 字元")
|
||
|
||
# 用短 ID 載入
|
||
content_short = loader.load("04")
|
||
assert content_short is not None, "Failed to load skill by short ID"
|
||
assert content_short == content, "Short ID should return same content"
|
||
print("✅ 短 ID 載入成功")
|
||
|
||
|
||
def test_skill_loader_load_skill_object():
|
||
"""測試:載入 Skill 物件並解析 metadata"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
skill = loader.load_skill("04-awoooi-devops-commander")
|
||
assert skill is not None, "Failed to load Skill object"
|
||
assert skill.skill_id == "04-awoooi-devops-commander"
|
||
assert skill.name != ""
|
||
assert skill.content != ""
|
||
print(f"✅ Skill 物件載入成功:")
|
||
print(f" - ID: {skill.skill_id}")
|
||
print(f" - Name: {skill.name}")
|
||
print(f" - Description: {skill.description[:50]}...")
|
||
|
||
|
||
def test_skill_loader_load_all():
|
||
"""測試:載入所有 Skills"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
skills = loader.load_all()
|
||
assert len(skills) >= 6, f"Expected at least 6 skills, got {len(skills)}"
|
||
print(f"✅ 載入 {len(skills)} 個 Skills:")
|
||
for skill in skills:
|
||
print(f" - {skill.skill_id}: {skill.name}")
|
||
|
||
|
||
def test_skill_to_context():
|
||
"""測試:Skill 轉換為 LLM Context"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
skill = loader.load_skill("04")
|
||
assert skill is not None
|
||
|
||
context = skill.to_context()
|
||
assert "## Skill:" in context
|
||
assert skill.name in context
|
||
print(f"✅ Context 生成成功,長度: {len(context)} 字元")
|
||
|
||
|
||
def test_skill_loader_list_skills():
|
||
"""測試:列出所有可用 Skills"""
|
||
from lewooogo_brain.skills.loader import SkillLoader
|
||
|
||
loader = SkillLoader(
|
||
skills_dir=".agents/skills",
|
||
project_root=project_root,
|
||
)
|
||
|
||
skill_list = loader.list_skills()
|
||
assert len(skill_list) >= 6
|
||
|
||
print("✅ Skill 清單:")
|
||
for s in skill_list:
|
||
print(f" - {s['skill_id']}: {s['name']}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
print("=" * 60)
|
||
print("🧪 SkillLoader 單元測試")
|
||
print("=" * 60)
|
||
|
||
tests = [
|
||
test_skill_loader_find_skills_dir,
|
||
test_skill_loader_load_devops_skill,
|
||
test_skill_loader_load_skill_object,
|
||
test_skill_loader_load_all,
|
||
test_skill_to_context,
|
||
test_skill_loader_list_skills,
|
||
]
|
||
|
||
passed = 0
|
||
failed = 0
|
||
|
||
for test in tests:
|
||
print(f"\n🔬 {test.__name__}")
|
||
try:
|
||
test()
|
||
passed += 1
|
||
except AssertionError as e:
|
||
print(f"❌ FAILED: {e}")
|
||
failed += 1
|
||
except Exception as e:
|
||
print(f"❌ ERROR: {e}")
|
||
failed += 1
|
||
|
||
print("\n" + "=" * 60)
|
||
print(f"📊 結果: {passed} 通過, {failed} 失敗")
|
||
print("=" * 60)
|
||
|
||
if failed > 0:
|
||
sys.exit(1)
|