feat(multi-llm): Phase 1 - Foundation adaptor architecture

Implement base adaptor pattern for multi-LLM support (Issue #179)

**Architecture:**
- Created adaptors/ package with base SkillAdaptor class
- Implemented factory pattern with get_adaptor() registry
- Refactored Claude-specific code into ClaudeAdaptor

**Changes:**
- New: src/skill_seekers/cli/adaptors/base.py (SkillAdaptor + SkillMetadata)
- New: src/skill_seekers/cli/adaptors/__init__.py (registry + factory)
- New: src/skill_seekers/cli/adaptors/claude.py (refactored upload + enhance logic)
- Modified: package_skill.py (added --target flag, uses adaptor.package())
- Modified: upload_skill.py (added --target flag, uses adaptor.upload())
- Modified: enhance_skill.py (added --target flag, uses adaptor.enhance())

**Tests:**
- New: tests/test_adaptors/test_base.py (10 tests passing)
- All existing tests still pass (backward compatible)

**Backward Compatibility:**
- Default --target=claude maintains existing behavior
- All CLI tools work exactly as before without --target flag
- No breaking changes

**Next:** Phase 2 - Implement Gemini, OpenAI, Markdown adaptors
This commit is contained in:
yusyus
2025-12-28 20:17:31 +03:00
parent 74bae4b49f
commit d0bc042a43
8 changed files with 1211 additions and 158 deletions

View File

@@ -1,12 +1,18 @@
#!/usr/bin/env python3
"""
SKILL.md Enhancement Script
Uses Claude API to improve SKILL.md by analyzing reference documentation.
Uses platform AI APIs to improve SKILL.md by analyzing reference documentation.
Usage:
skill-seekers enhance output/steam-inventory/
# Claude (default)
skill-seekers enhance output/react/
skill-seekers enhance output/godot/ --api-key YOUR_API_KEY
skill-seekers enhance output/react/ --api-key sk-ant-...
# Gemini
skill-seekers enhance output/react/ --target gemini --api-key AIzaSy...
# OpenAI
skill-seekers enhance output/react/ --target openai --api-key sk-proj-...
"""
import os
@@ -195,18 +201,26 @@ Return ONLY the complete SKILL.md content, starting with the frontmatter (---).
def main():
parser = argparse.ArgumentParser(
description='Enhance SKILL.md using Claude API',
description='Enhance SKILL.md using platform AI APIs',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Using ANTHROPIC_API_KEY environment variable
# Claude (default)
export ANTHROPIC_API_KEY=sk-ant-...
skill-seekers enhance output/steam-inventory/
skill-seekers enhance output/react/
# Providing API key directly
# Gemini
export GOOGLE_API_KEY=AIzaSy...
skill-seekers enhance output/react/ --target gemini
# OpenAI
export OPENAI_API_KEY=sk-proj-...
skill-seekers enhance output/react/ --target openai
# With explicit API key
skill-seekers enhance output/react/ --api-key sk-ant-...
# Show what would be done (dry run)
# Dry run
skill-seekers enhance output/godot/ --dry-run
"""
)
@@ -214,7 +228,11 @@ Examples:
parser.add_argument('skill_dir', type=str,
help='Path to skill directory (e.g., output/steam-inventory/)')
parser.add_argument('--api-key', type=str,
help='Anthropic API key (or set ANTHROPIC_API_KEY env var)')
help='Platform API key (or set environment variable)')
parser.add_argument('--target',
choices=['claude', 'gemini', 'openai'],
default='claude',
help='Target LLM platform (default: claude)')
parser.add_argument('--dry-run', action='store_true',
help='Show what would be done without calling API')
@@ -249,18 +267,57 @@ Examples:
print(f" skill-seekers enhance {skill_dir}")
return
# Create enhancer and run
# Check if platform supports enhancement
try:
enhancer = SkillEnhancer(skill_dir, api_key=args.api_key)
success = enhancer.run()
from skill_seekers.cli.adaptors import get_adaptor
adaptor = get_adaptor(args.target)
if not adaptor.supports_enhancement():
print(f"❌ Error: {adaptor.PLATFORM_NAME} does not support AI enhancement")
print(f"\nSupported platforms for enhancement:")
print(" - Claude AI (Anthropic)")
print(" - Google Gemini")
print(" - OpenAI ChatGPT")
sys.exit(1)
# Get API key
api_key = args.api_key
if not api_key:
api_key = os.environ.get(adaptor.get_env_var_name(), '').strip()
if not api_key:
print(f"❌ Error: {adaptor.get_env_var_name()} not set")
print(f"\nSet your API key for {adaptor.PLATFORM_NAME}:")
print(f" export {adaptor.get_env_var_name()}=...")
print("Or provide it directly:")
print(f" skill-seekers enhance {skill_dir} --target {args.target} --api-key ...")
sys.exit(1)
# Run enhancement using adaptor
print(f"\n{'='*60}")
print(f"ENHANCING SKILL: {skill_dir}")
print(f"Platform: {adaptor.PLATFORM_NAME}")
print(f"{'='*60}\n")
success = adaptor.enhance(Path(skill_dir), api_key)
if success:
print(f"\n✅ Enhancement complete!")
print(f"\nNext steps:")
print(f" 1. Review: {Path(skill_dir) / 'SKILL.md'}")
print(f" 2. If you don't like it, restore backup: {Path(skill_dir) / 'SKILL.md.backup'}")
print(f" 3. Package your skill:")
print(f" skill-seekers package {skill_dir}/ --target {args.target}")
sys.exit(0 if success else 1)
except ImportError as e:
print(f"❌ Error: {e}")
print("\nAdaptor system not available. Reinstall skill-seekers.")
sys.exit(1)
except ValueError as e:
print(f"❌ Error: {e}")
print("\nSet your API key:")
print(" export ANTHROPIC_API_KEY=sk-ant-...")
print("Or provide it directly:")
print(f" skill-seekers enhance {skill_dir} --api-key sk-ant-...")
sys.exit(1)
except Exception as e:
print(f"❌ Unexpected error: {e}")