feat: add interactive provider installation guide
New command: smarttools providers install Features: - Lists all provider groups (Claude, Codex, Gemini, OpenCode, Ollama) - Shows cost, requirements, and included models for each - Marks already-installed providers - Offers to run installation command automatically - Shows post-install setup instructions Provider groups: - Anthropic Claude (paid): claude, claude-haiku, claude-opus, claude-sonnet - OpenAI Codex (paid): codex - Google Gemini (free tier): gemini, gemini-flash - OpenCode (free tier): opencode-deepseek, opencode-pickle, etc. - Ollama (free, local): custom models 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6abca22019
commit
b4c7491784
|
|
@ -338,11 +338,148 @@ echo "input" | {args.name}
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
PROVIDER_INSTALL_INFO = {
|
||||||
|
"claude": {
|
||||||
|
"group": "Anthropic Claude",
|
||||||
|
"install_cmd": "npm install -g @anthropic-ai/claude-code",
|
||||||
|
"requires": "Node.js and npm",
|
||||||
|
"setup": "Run 'claude' and follow login prompts",
|
||||||
|
"cost": "Pay-per-use (API key required)",
|
||||||
|
"variants": ["claude", "claude-haiku", "claude-opus", "claude-sonnet"],
|
||||||
|
},
|
||||||
|
"codex": {
|
||||||
|
"group": "OpenAI Codex",
|
||||||
|
"install_cmd": "pip install openai-codex",
|
||||||
|
"requires": "Python 3.8+",
|
||||||
|
"setup": "Set OPENAI_API_KEY environment variable",
|
||||||
|
"cost": "Pay-per-use (API key required)",
|
||||||
|
"variants": ["codex"],
|
||||||
|
},
|
||||||
|
"gemini": {
|
||||||
|
"group": "Google Gemini",
|
||||||
|
"install_cmd": "pip install google-generativeai",
|
||||||
|
"requires": "Python 3.8+",
|
||||||
|
"setup": "Set GOOGLE_API_KEY or run 'gemini auth'",
|
||||||
|
"cost": "Free tier available, pay-per-use for more",
|
||||||
|
"variants": ["gemini", "gemini-flash"],
|
||||||
|
},
|
||||||
|
"opencode": {
|
||||||
|
"group": "OpenCode",
|
||||||
|
"install_cmd": "curl -fsSL https://opencode.ai/install.sh | bash",
|
||||||
|
"requires": "curl, bash",
|
||||||
|
"setup": "Run 'opencode auth' to authenticate",
|
||||||
|
"cost": "Free tier (pickle), paid for other models",
|
||||||
|
"variants": ["opencode-deepseek", "opencode-pickle", "opencode-nano", "opencode-reasoner", "opencode-grok"],
|
||||||
|
},
|
||||||
|
"ollama": {
|
||||||
|
"group": "Ollama (Local)",
|
||||||
|
"install_cmd": "curl -fsSL https://ollama.ai/install.sh | bash",
|
||||||
|
"requires": "curl, bash, decent GPU recommended",
|
||||||
|
"setup": "Run 'ollama pull llama3' to download a model",
|
||||||
|
"cost": "FREE (runs locally)",
|
||||||
|
"variants": [],
|
||||||
|
"custom": True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def cmd_providers(args):
|
def cmd_providers(args):
|
||||||
"""Manage AI providers."""
|
"""Manage AI providers."""
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
if args.providers_cmd == "list":
|
if args.providers_cmd == "install":
|
||||||
|
print("=" * 60)
|
||||||
|
print("SmartTools Provider Installation Guide")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Check what's already installed
|
||||||
|
providers = load_providers()
|
||||||
|
installed_groups = set()
|
||||||
|
for p in providers:
|
||||||
|
if p.name.lower() == "mock":
|
||||||
|
continue
|
||||||
|
cmd_parts = p.command.split()[0]
|
||||||
|
cmd_expanded = cmd_parts.replace("$HOME", str(Path.home())).replace("~", str(Path.home()))
|
||||||
|
if shutil.which(cmd_expanded) or Path(cmd_expanded).exists():
|
||||||
|
# Find which group this belongs to
|
||||||
|
for group, info in PROVIDER_INSTALL_INFO.items():
|
||||||
|
if p.name in info.get("variants", []):
|
||||||
|
installed_groups.add(group)
|
||||||
|
|
||||||
|
# Show available provider groups
|
||||||
|
print("Available AI Provider Groups:\n")
|
||||||
|
options = []
|
||||||
|
for i, (key, info) in enumerate(PROVIDER_INSTALL_INFO.items(), 1):
|
||||||
|
status = "[INSTALLED]" if key in installed_groups else ""
|
||||||
|
print(f" {i}. {info['group']} {status}")
|
||||||
|
print(f" Cost: {info['cost']}")
|
||||||
|
print(f" Models: {', '.join(info['variants']) if info['variants'] else 'Custom'}")
|
||||||
|
print()
|
||||||
|
options.append(key)
|
||||||
|
|
||||||
|
print(" 0. Cancel")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = input("Select a provider to install (1-{}, or 0 to cancel): ".format(len(options)))
|
||||||
|
choice = int(choice)
|
||||||
|
except (ValueError, EOFError):
|
||||||
|
print("Cancelled.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if choice == 0 or choice > len(options):
|
||||||
|
print("Cancelled.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
selected = options[choice - 1]
|
||||||
|
info = PROVIDER_INSTALL_INFO[selected]
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("=" * 60)
|
||||||
|
print(f"Installing: {info['group']}")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
print(f"Requirements: {info['requires']}")
|
||||||
|
print(f"Install command: {info['install_cmd']}")
|
||||||
|
print(f"Post-install: {info['setup']}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
confirm = input("Run installation command? (y/N): ").strip().lower()
|
||||||
|
except EOFError:
|
||||||
|
confirm = "n"
|
||||||
|
|
||||||
|
if confirm == "y":
|
||||||
|
print()
|
||||||
|
print(f"Running: {info['install_cmd']}")
|
||||||
|
print("-" * 40)
|
||||||
|
result = subprocess.run(info['install_cmd'], shell=True)
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print()
|
||||||
|
print("Installation completed!")
|
||||||
|
print()
|
||||||
|
print(f"Next steps:")
|
||||||
|
print(f" 1. {info['setup']}")
|
||||||
|
print(f" 2. Test with: smarttools providers test {info['variants'][0] if info['variants'] else selected}")
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
print(f"Installation failed (exit code {result.returncode})")
|
||||||
|
print("Try running the command manually:")
|
||||||
|
print(f" {info['install_cmd']}")
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
print("To install manually, run:")
|
||||||
|
print(f" {info['install_cmd']}")
|
||||||
|
print()
|
||||||
|
print(f"Then: {info['setup']}")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
elif args.providers_cmd == "list":
|
||||||
providers = load_providers()
|
providers = load_providers()
|
||||||
print(f"Configured providers ({len(providers)}):\n")
|
print(f"Configured providers ({len(providers)}):\n")
|
||||||
for p in providers:
|
for p in providers:
|
||||||
|
|
@ -520,6 +657,10 @@ def main():
|
||||||
p_prov_check = providers_sub.add_parser("check", help="Check which providers are available")
|
p_prov_check = providers_sub.add_parser("check", help="Check which providers are available")
|
||||||
p_prov_check.set_defaults(func=cmd_providers)
|
p_prov_check.set_defaults(func=cmd_providers)
|
||||||
|
|
||||||
|
# providers install
|
||||||
|
p_prov_install = providers_sub.add_parser("install", help="Interactive guide to install AI providers")
|
||||||
|
p_prov_install.set_defaults(func=cmd_providers)
|
||||||
|
|
||||||
# providers add
|
# providers add
|
||||||
p_prov_add = providers_sub.add_parser("add", help="Add or update a provider")
|
p_prov_add = providers_sub.add_parser("add", help="Add or update a provider")
|
||||||
p_prov_add.add_argument("name", help="Provider name")
|
p_prov_add.add_argument("name", help="Provider name")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue