feat(phase6-9): Complete modular architecture and Agent Teams
Phase 6.4 - Modular Architecture: - Add lewooogo-brain adapters for LLM providers - Add lewooogo-data dual memory (Redis + PostgreSQL) - Implement consensus engine for multi-agent decisions - Add incident memory service for historical context Phase 9 - Agent Teams (Claude Agent SDK): - Add base agent class with Claude Sonnet 4 integration - Implement action planner, blast radius, and security agents - Add agent API endpoints and proposal workflow - Integrate ADR-009 OpenClaw Agent Teams architecture DevOps & CI/CD: - Add GitHub Actions CI/CD workflows (ci.yaml, cd.yaml) - Add pre-commit hooks and secrets baseline - Add docker-compose for local development - Update Kubernetes network policies Frontend Improvements: - Add auto-healing error boundary component - Update i18n messages for agent features - Enhance dual-state incident card with execution feedback Documentation: - Add 7 ADRs covering MCP, design system, architecture decisions - Update ARCHITECTURE_MEMORY.md with modular design - Add GLOBAL_RULES.md and SOUL.md for project identity Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
281
scripts/test_agent_sdk.py
Normal file
281
scripts/test_agent_sdk.py
Normal file
@@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Phase 9 Agent SDK POC Verification Script
|
||||
==========================================
|
||||
|
||||
驗證 claude-agent-sdk 是否能在 AWOOOI 專案中正常運作。
|
||||
|
||||
Usage:
|
||||
python scripts/test_agent_sdk.py
|
||||
|
||||
Environment Variables:
|
||||
ANTHROPIC_API_KEY - 如果設置,將測試基本 API 調用
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
|
||||
def test_import() -> bool:
|
||||
"""Test basic import of claude-agent-sdk."""
|
||||
print("=" * 60)
|
||||
print("Phase 9 Agent SDK POC Verification")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
try:
|
||||
import claude_agent_sdk
|
||||
|
||||
version = getattr(claude_agent_sdk, "__version__", "N/A")
|
||||
print(f"[PASS] claude_agent_sdk imported successfully")
|
||||
print(f" Version: {version}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f"[FAIL] Failed to import claude_agent_sdk: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_core_exports() -> bool:
|
||||
"""Test that core exports are available."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Testing core exports...")
|
||||
print("-" * 60)
|
||||
|
||||
required_exports = [
|
||||
"query",
|
||||
"ClaudeAgentOptions",
|
||||
"ClaudeSDKClient",
|
||||
"Message",
|
||||
"UserMessage",
|
||||
"AssistantMessage",
|
||||
"SystemMessage",
|
||||
]
|
||||
|
||||
all_passed = True
|
||||
for export in required_exports:
|
||||
try:
|
||||
from claude_agent_sdk import query # noqa: F401
|
||||
|
||||
module = __import__("claude_agent_sdk", fromlist=[export])
|
||||
getattr(module, export)
|
||||
print(f" [PASS] {export}")
|
||||
except (ImportError, AttributeError) as e:
|
||||
print(f" [FAIL] {export}: {e}")
|
||||
all_passed = False
|
||||
|
||||
return all_passed
|
||||
|
||||
|
||||
def test_types() -> bool:
|
||||
"""Test type definitions are available."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Testing type definitions...")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
from claude_agent_sdk import (
|
||||
AssistantMessage,
|
||||
ClaudeAgentOptions,
|
||||
Message,
|
||||
PermissionMode,
|
||||
StreamEvent,
|
||||
TextBlock,
|
||||
ThinkingConfig,
|
||||
ToolUseBlock,
|
||||
UserMessage,
|
||||
)
|
||||
|
||||
print(f" [PASS] ClaudeAgentOptions: {ClaudeAgentOptions}")
|
||||
print(f" [PASS] Message: {Message}")
|
||||
print(f" [PASS] UserMessage: {UserMessage}")
|
||||
print(f" [PASS] AssistantMessage: {AssistantMessage}")
|
||||
print(f" [PASS] TextBlock: {TextBlock}")
|
||||
print(f" [PASS] ToolUseBlock: {ToolUseBlock}")
|
||||
print(f" [PASS] StreamEvent: {StreamEvent}")
|
||||
print(f" [PASS] ThinkingConfig: {ThinkingConfig}")
|
||||
print(f" [PASS] PermissionMode: {PermissionMode}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f" [FAIL] Type import failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_mcp_integration() -> bool:
|
||||
"""Test MCP server configuration types."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Testing MCP integration types...")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
from claude_agent_sdk import (
|
||||
McpServerConfig,
|
||||
McpServerInfo,
|
||||
McpServerStatus,
|
||||
McpStatusResponse,
|
||||
McpToolInfo,
|
||||
)
|
||||
|
||||
print(f" [PASS] McpServerConfig: {McpServerConfig}")
|
||||
print(f" [PASS] McpServerInfo: {McpServerInfo}")
|
||||
print(f" [PASS] McpServerStatus: {McpServerStatus}")
|
||||
print(f" [PASS] McpStatusResponse: {McpStatusResponse}")
|
||||
print(f" [PASS] McpToolInfo: {McpToolInfo}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f" [FAIL] MCP type import failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_hook_types() -> bool:
|
||||
"""Test hook-related types for agent customization."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Testing hook types...")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
from claude_agent_sdk import (
|
||||
HookCallback,
|
||||
HookContext,
|
||||
HookInput,
|
||||
PermissionRequestHookInput,
|
||||
PostToolUseHookInput,
|
||||
PreToolUseHookInput,
|
||||
StopHookInput,
|
||||
)
|
||||
|
||||
print(f" [PASS] HookCallback: {HookCallback}")
|
||||
print(f" [PASS] HookContext: {HookContext}")
|
||||
print(f" [PASS] HookInput: {HookInput}")
|
||||
print(f" [PASS] PreToolUseHookInput: {PreToolUseHookInput}")
|
||||
print(f" [PASS] PostToolUseHookInput: {PostToolUseHookInput}")
|
||||
print(f" [PASS] PermissionRequestHookInput: {PermissionRequestHookInput}")
|
||||
print(f" [PASS] StopHookInput: {StopHookInput}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f" [FAIL] Hook type import failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_session_management() -> bool:
|
||||
"""Test session management functions."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Testing session management functions...")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
from claude_agent_sdk import (
|
||||
get_session_info,
|
||||
get_session_messages,
|
||||
list_sessions,
|
||||
rename_session,
|
||||
tag_session,
|
||||
)
|
||||
|
||||
print(f" [PASS] list_sessions: {list_sessions}")
|
||||
print(f" [PASS] get_session_info: {get_session_info}")
|
||||
print(f" [PASS] get_session_messages: {get_session_messages}")
|
||||
print(f" [PASS] rename_session: {rename_session}")
|
||||
print(f" [PASS] tag_session: {tag_session}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f" [FAIL] Session management import failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_api_key_available() -> bool:
|
||||
"""Check if ANTHROPIC_API_KEY is available."""
|
||||
print()
|
||||
print("-" * 60)
|
||||
print("Checking environment variables...")
|
||||
print("-" * 60)
|
||||
|
||||
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
||||
if api_key:
|
||||
# Don't print the actual key
|
||||
masked = api_key[:8] + "..." + api_key[-4:] if len(api_key) > 12 else "***"
|
||||
print(f" [INFO] ANTHROPIC_API_KEY is set (masked: {masked})")
|
||||
return True
|
||||
else:
|
||||
print(" [INFO] ANTHROPIC_API_KEY not set - skipping API call test")
|
||||
return False
|
||||
|
||||
|
||||
def list_required_env_vars() -> None:
|
||||
"""List all required environment variables for full functionality."""
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("Required Environment Variables for Full Functionality")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
env_vars = [
|
||||
("ANTHROPIC_API_KEY", "Required for API calls", True),
|
||||
("CLAUDE_API_KEY", "Alternative API key (optional)", False),
|
||||
("CLAUDE_CONFIG_DIR", "Custom config directory (optional)", False),
|
||||
]
|
||||
|
||||
print("| Variable | Description | Required |")
|
||||
print("|-------------------|----------------------------------|----------|")
|
||||
for var, desc, required in env_vars:
|
||||
status = "Yes" if required else "No"
|
||||
is_set = "[SET]" if os.environ.get(var) else "[NOT SET]"
|
||||
print(f"| {var:<17} | {desc:<32} | {status:<8} | {is_set}")
|
||||
print()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Run all tests and return exit code."""
|
||||
results: dict[str, bool] = {}
|
||||
|
||||
# Run tests
|
||||
results["import"] = test_import()
|
||||
results["core_exports"] = test_core_exports()
|
||||
results["types"] = test_types()
|
||||
results["mcp_integration"] = test_mcp_integration()
|
||||
results["hooks"] = test_hook_types()
|
||||
results["session_management"] = test_session_management()
|
||||
|
||||
# Check API key
|
||||
has_api_key = test_api_key_available()
|
||||
|
||||
# List required env vars
|
||||
list_required_env_vars()
|
||||
|
||||
# Summary
|
||||
print("=" * 60)
|
||||
print("Summary")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
passed = sum(1 for v in results.values() if v)
|
||||
total = len(results)
|
||||
|
||||
for test_name, passed_test in results.items():
|
||||
status = "[PASS]" if passed_test else "[FAIL]"
|
||||
print(f" {status} {test_name}")
|
||||
|
||||
print()
|
||||
print(f"Results: {passed}/{total} tests passed")
|
||||
print()
|
||||
|
||||
if passed == total:
|
||||
print("[SUCCESS] claude-agent-sdk is ready for Phase 9 integration!")
|
||||
print()
|
||||
print("Next steps:")
|
||||
print(" 1. Add 'claude-agent-sdk>=0.1.50' to apps/api/pyproject.toml")
|
||||
print(" 2. Set ANTHROPIC_API_KEY in environment")
|
||||
print(" 3. Create agent definitions in apps/api/src/agents/")
|
||||
return 0
|
||||
else:
|
||||
print("[WARNING] Some tests failed. Please review the output above.")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user