Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions src/fast_agent/cli/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Main CLI entry point for MCP Agent."""

from __future__ import annotations

import typer
from rich.table import Table

Expand Down Expand Up @@ -28,6 +30,102 @@
console = shared_console


def _get_available_providers() -> set[str]:
"""Detect which providers have API keys configured (env vars or config file).

Returns a set of provider names (lowercase) that have valid keys.
"""
from pathlib import Path

from fast_agent.cli.commands.check_config import find_config_files, get_secrets_summary
from fast_agent.llm.provider_key_manager import API_KEY_HINT_TEXT, ProviderKeyManager
from fast_agent.llm.provider_types import Provider

available: set[str] = set()

# Find config files from current directory
config_files = find_config_files(Path.cwd())
secrets_summary = get_secrets_summary(config_files.get("secrets"))

secrets = secrets_summary.get("secrets", {})
secrets_status = secrets_summary.get("status", "not_found")

for provider in Provider:
if provider == Provider.FAST_AGENT:
available.add(provider.value)
continue

provider_name = provider.value

# Check environment variable
env_key = ProviderKeyManager.get_env_var(provider_name)
if env_key:
available.add(provider_name)
continue

# Check secrets file
if secrets_status == "parsed":
config_key = ProviderKeyManager.get_config_file_key(provider_name, secrets)
if config_key and config_key != API_KEY_HINT_TEXT:
available.add(provider_name)
continue

return available


def _get_aliases_by_provider() -> dict[str, list[tuple[str, str]]]:
"""Group model aliases by their resolved provider.

Returns a dict mapping provider name to list of (alias, resolved_model) tuples.
"""
from fast_agent.llm.model_factory import ModelFactory

aliases_by_provider: dict[str, list[tuple[str, str]]] = {}

for alias, resolved in ModelFactory.MODEL_ALIASES.items():
try:
config = ModelFactory.parse_model_string(resolved)
provider_name = config.provider.value
except Exception:
provider_name = "unknown"

if provider_name not in aliases_by_provider:
aliases_by_provider[provider_name] = []
aliases_by_provider[provider_name].append((alias, config.model_name if 'config' in dir() else resolved))

# Re-parse to get proper model names
for alias, resolved in ModelFactory.MODEL_ALIASES.items():
try:
config = ModelFactory.parse_model_string(resolved)
provider_name = config.provider.value
# Update the entry with proper model name
for i, (a, _) in enumerate(aliases_by_provider.get(provider_name, [])):
if a == alias:
aliases_by_provider[provider_name][i] = (alias, config.model_name)
break
except Exception:
pass

return aliases_by_provider


# Curated list of commonly used aliases to show in welcome message
# Format: (alias, description/model hint)
FEATURED_ALIASES: list[tuple[str, str, str]] = [
# (alias, provider, description)
("sonnet", "anthropic", "Claude Sonnet 4.5"),
("haiku", "anthropic", "Claude Haiku 4.5"),
("opus", "anthropic", "Claude Opus 4.5"),
("gpt51", "openai", "GPT 5.1"),
("o3", "openai", "o3"),
("gemini25", "google", "Gemini 2.5 Flash"),
("gemini25pro", "google", "Gemini 2.5 Pro"),
("deepseek", "deepseek", "DeepSeek Chat"),
("kimi", "hf", "Kimi K2 (via Groq)"),
("qwen3", "hf", "Qwen3 (via Together)"),
]


def show_welcome() -> None:
"""Show a welcome message with available commands, using new styling."""
from importlib.metadata import version
Expand Down Expand Up @@ -73,6 +171,37 @@ def _print_section_header(title: str, color: str = "blue") -> None:

console.print(table)

# Show model aliases with availability indicators
_print_section_header("Model Aliases", color="blue")

available_providers = _get_available_providers()

# Build alias display table
alias_table = Table(show_header=True, box=None, padding=(0, 2, 0, 0))
alias_table.add_column("", style="dim", width=2) # Status indicator
alias_table.add_column("Alias", style="cyan", header_style="bold bright_white")
alias_table.add_column("Model", header_style="bold bright_white")
alias_table.add_column("Provider", style="dim", header_style="bold bright_white")

for alias, provider, description in FEATURED_ALIASES:
is_available = provider in available_providers
status = "[green]✓[/green]" if is_available else "[dim]✗[/dim]"
alias_style = "[bold cyan]" if is_available else "[dim]"
desc_style = "" if is_available else "[dim]"
provider_style = "[green]" if is_available else "[dim]"

alias_table.add_row(
status,
f"{alias_style}{alias}[/]",
f"{desc_style}{description}[/]",
f"{provider_style}{provider}[/]",
)

console.print(alias_table)
console.print(
"\n[dim]✓ = API key configured | Use[/dim] [cyan]fast-agent check[/cyan] [dim]for full status[/dim]"
)

console.print(
"\nVisit [cyan][link=https://fast-agent.ai]fast-agent.ai[/link][/cyan] for more information."
)
Expand Down
Loading