Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

822 lines
31 KiB
Python

"""Wizard configuration metadata."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Literal
from config.config import (
ANTHROPIC_REASONING_MODEL,
AZURE_OPENAI_REASONING_MODEL,
BEDROCK_REASONING_MODEL,
DEEPSEEK_REASONING_MODEL,
DEFAULT_OLLAMA_HOST,
DEFAULT_OLLAMA_MODEL,
GEMINI_REASONING_MODEL,
GROQ_REASONING_MODEL,
MINIMAX_REASONING_MODEL,
NVIDIA_REASONING_MODEL,
OPENAI_REASONING_MODEL,
OPENROUTER_REASONING_MODEL,
)
from config.llm_auth.provider_catalog import require_provider_spec
from config.local_env import PROJECT_ROOT as PROJECT_ROOT
from config.local_env import get_project_env_path
from integrations.llm_cli.base import LLMCLIAdapter
PROJECT_ENV_PATH = get_project_env_path()
CredentialKind = Literal["api_key", "host", "cli", "none"]
@dataclass(frozen=True)
class ModelOption:
"""A selectable default model."""
value: str
label: str
@dataclass(frozen=True)
class ProviderOption:
"""Wizard metadata for a supported LLM provider."""
value: str
label: str
group: str
api_key_env: str
model_env: str
default_model: str
models: tuple[ModelOption, ...]
#: If set, ``sync_provider_env`` also writes this key (same value) for legacy .env files.
legacy_model_env: str | None = None
#: Env var that holds the *toolcall* model for this provider. ``None`` for
#: providers that don't expose a separate toolcall model (e.g. CLI-backed
#: providers like ``codex``/``claude-code``, or Ollama).
toolcall_model_env: str | None = None
#: Env var that holds the *classification* model for this provider. When
#: unset, ``sync_provider_env`` falls back to replacing ``_REASONING_MODEL``
#: with ``_CLASSIFICATION_MODEL`` in ``model_env``.
classification_model_env: str | None = None
endpoint_env: str = ""
api_version_env: str = ""
#: Human-readable name for the credential requested during onboarding. Most
#: providers want an API key; Ollama wants a host URL. Used as the wizard
#: prompt label, e.g. ``{label} {credential_label} ({api_key_env})``.
credential_label: str = "API key"
#: Whether the credential should be prompted as a secret (hidden input).
#: API keys are secrets; a local Ollama host URL is not.
credential_secret: bool = True
#: Optional hint shown as the default value in the prompt (e.g. the
#: default Ollama host URL). Empty string means no default.
credential_default: str = ""
#: ``cli`` providers use ``adapter_factory`` and vendor auth (no API key in .env).
credential_kind: CredentialKind = "api_key"
adapter_factory: Callable[[], LLMCLIAdapter] | None = None
#: Whether the CLI should accept model IDs outside the curated quick-pick list.
#: Use this for providers whose model catalogs are large, account-gated, or
#: updated independently of OpenSRE releases.
allow_custom_models: bool = False
def __post_init__(self) -> None:
spec = require_provider_spec(self.value)
kind_map = {"api_key": "api_key", "cli": "cli", "none": "ambient", "host": "local"}
catalog_kind = kind_map[self.credential_kind]
mismatches = {
"api_key_env": (self.api_key_env, spec.api_key_env),
"model_env": (self.model_env, spec.model_env),
"legacy_model_env": (self.legacy_model_env, spec.legacy_model_env),
"toolcall_model_env": (self.toolcall_model_env, spec.toolcall_model_env),
"classification_model_env": (
self.classification_model_env,
spec.classification_model_env,
),
"endpoint_env": (self.endpoint_env, spec.endpoint_env),
"api_version_env": (self.api_version_env, spec.api_version_env),
"credential_kind": (catalog_kind, spec.credential_kind),
"allow_custom_models": (self.allow_custom_models, spec.allow_custom_models),
}
drift = {name: values for name, values in mismatches.items() if values[0] != values[1]}
if drift:
details = ", ".join(
f"{name}: {actual!r} != {expected!r}" for name, (actual, expected) in drift.items()
)
raise ValueError(
f"ProviderOption {self.value!r} drifts from provider catalog: {details}"
)
# Source: https://docs.anthropic.com/en/docs/about-claude/models/overview
ANTHROPIC_MODELS = (
ModelOption(value=ANTHROPIC_REASONING_MODEL, label="Claude Opus 4.7"),
ModelOption(value="claude-fable-5", label="Claude Fable 5 — most capable"),
ModelOption(value="claude-sonnet-4-6", label="Claude Sonnet 4.6"),
ModelOption(value="claude-haiku-4-5", label="Claude Haiku 4.5"),
)
# Source: https://platform.openai.com/docs/models
# Codex model IDs are intentionally omitted here: OpenSRE's direct OpenAI
# provider uses Chat Completions, while Codex models require a different API path.
OPENAI_MODELS = (
ModelOption(value=OPENAI_REASONING_MODEL, label="GPT-5.4 mini"),
ModelOption(value="gpt-5.6-sol", label="GPT-5.6 Sol — flagship"),
ModelOption(value="gpt-5.6-terra", label="GPT-5.6 Terra — balanced"),
ModelOption(value="gpt-5.6-luna", label="GPT-5.6 Luna — cost-efficient"),
ModelOption(value="gpt-5.5", label="GPT-5.5"),
ModelOption(value="gpt-5.4", label="GPT-5.4"),
ModelOption(value="gpt-5.4-nano", label="GPT-5.4 nano"),
)
# Source: https://openrouter.ai/api/v1/models
OPENROUTER_MODELS = (
ModelOption(value=OPENROUTER_REASONING_MODEL, label="OpenRouter Auto (smart routing)"),
ModelOption(value="openai/gpt-5.6-sol", label="GPT-5.6 Sol (via OpenRouter)"),
ModelOption(value="openai/gpt-5.6-terra", label="GPT-5.6 Terra (via OpenRouter)"),
ModelOption(value="openai/gpt-5.6-luna", label="GPT-5.6 Luna (via OpenRouter)"),
ModelOption(value="openai/gpt-5.5", label="GPT-5.5 (via OpenRouter)"),
ModelOption(value="anthropic/claude-opus-4.7", label="Claude Opus 4.7 (via OpenRouter)"),
ModelOption(value="anthropic/claude-sonnet-4.6", label="Claude Sonnet 4.6 (via OpenRouter)"),
ModelOption(value="anthropic/claude-haiku-4.5", label="Claude Haiku 4.5 (via OpenRouter)"),
ModelOption(
value="google/gemini-3.1-pro-preview", label="Gemini 3.1 Pro (preview, via OpenRouter)"
),
ModelOption(
value="google/gemini-3-flash-preview", label="Gemini 3 Flash (preview, via OpenRouter)"
),
ModelOption(
value="google/gemini-3.1-flash-lite-preview",
label="Gemini 3.1 Flash-Lite (preview, via OpenRouter)",
),
ModelOption(
value="google/gemini-3.1-flash-image-preview",
label="Gemini 3.1 Flash Image (preview, via OpenRouter)",
),
ModelOption(
value="google/gemini-3-pro-image-preview",
label="Gemini 3 Pro Image (preview, via OpenRouter)",
),
ModelOption(value="meta-llama/llama-4-maverick", label="Llama 4 Maverick (via OpenRouter)"),
ModelOption(value="meta-llama/llama-4-scout", label="Llama 4 Scout (via OpenRouter)"),
ModelOption(value="mistralai/mistral-large-2512", label="Mistral Large 3 (via OpenRouter)"),
ModelOption(value="x-ai/grok-4", label="Grok 4 (via OpenRouter)"),
ModelOption(value="x-ai/grok-4-fast", label="Grok 4 Fast (via OpenRouter)"),
ModelOption(value="moonshotai/kimi-k2.5", label="Kimi K2.5 (via OpenRouter)"),
ModelOption(value="z-ai/glm-4.7", label="GLM 4.7 (via OpenRouter)"),
ModelOption(value="minimax/minimax-m2", label="MiniMax M2 (via OpenRouter)"),
ModelOption(value="deepseek/deepseek-v3.2", label="DeepSeek V3.2 (via OpenRouter)"),
ModelOption(value="qwen/qwen-3.6-plus-preview", label="Qwen 3.6 Plus (via OpenRouter)"),
)
DEEPSEEK_MODELS = (
ModelOption(value=DEEPSEEK_REASONING_MODEL, label="DeepSeek V4 Pro"),
ModelOption(value="deepseek-v4-flash", label="DeepSeek V4 Flash"),
)
GEMINI_MODELS = (
ModelOption(value=GEMINI_REASONING_MODEL, label="Gemini 3.1 Pro (preview)"),
ModelOption(value="gemini-3-flash-preview", label="Gemini 3 Flash (preview)"),
ModelOption(value="gemini-3.1-flash-lite-preview", label="Gemini 3.1 Flash-Lite (preview)"),
ModelOption(value="gemini-3.1-flash-image-preview", label="Gemini 3.1 Flash Image (preview)"),
ModelOption(value="gemini-3-pro-image-preview", label="Gemini 3 Pro Image (preview)"),
)
NVIDIA_MODELS = (
ModelOption(
value=NVIDIA_REASONING_MODEL,
label="Nemotron 3 Super 120B (5x higher throughput for agentic AI)",
),
ModelOption(value="nvidia/nemotron-3-nano-30b-a3b", label="Nemotron 3 Nano 30B"),
)
MINIMAX_MODELS = (
ModelOption(value=MINIMAX_REASONING_MODEL, label="MiniMax M3"),
ModelOption(value="MiniMax-M2.7-highspeed", label="MiniMax M2.7 highspeed"),
)
GROQ_MODELS = (
ModelOption(value=GROQ_REASONING_MODEL, label="Llama 3.3 70B Versatile"),
ModelOption(value="llama-3.1-8b-instant", label="Llama 3.1 8B Instant"),
ModelOption(value="openai/gpt-oss-120b", label="GPT-OSS 120B"),
ModelOption(value="openai/gpt-oss-20b", label="GPT-OSS 20B"),
ModelOption(value="qwen/qwen3-32b", label="Qwen3 32B"),
ModelOption(value="meta-llama/llama-4-scout-17b-16e-instruct", label="Llama 4 Scout 17B"),
)
# Azure OpenAI model values are deployment names in your resource.
# Source: https://learn.microsoft.com/en-us/azure/ai-foundry/model-inference/concepts/models
AZURE_OPENAI_MODELS = (
ModelOption(value=AZURE_OPENAI_REASONING_MODEL, label="gpt-5.4-mini deployment"),
ModelOption(value="gpt-5.6-sol", label="gpt-5.6-sol deployment"),
ModelOption(value="gpt-5.6-terra", label="gpt-5.6-terra deployment"),
ModelOption(value="gpt-5.6-luna", label="gpt-5.6-luna deployment"),
ModelOption(value="gpt-5.5", label="gpt-5.5 deployment"),
ModelOption(value="gpt-5.4", label="gpt-5.4 deployment"),
ModelOption(value="gpt-5.4-nano", label="gpt-5.4-nano deployment"),
ModelOption(value="gpt-5-mini", label="gpt-5-mini deployment"),
ModelOption(value="gpt-5", label="gpt-5 deployment"),
ModelOption(value="gpt-4.1", label="gpt-4.1 deployment"),
ModelOption(value="gpt-4.1-mini", label="gpt-4.1-mini deployment"),
ModelOption(value="o3-mini", label="o3-mini deployment"),
)
BEDROCK_MODELS = (
ModelOption(
value=BEDROCK_REASONING_MODEL,
label="Claude Sonnet 4.6 (US cross-region) — default",
),
ModelOption(
value="us.anthropic.claude-opus-4-7",
label="Claude Opus 4.7 (US cross-region) — most capable",
),
ModelOption(
value="us.anthropic.claude-opus-4-6-v1",
label="Claude Opus 4.6 (US cross-region)",
),
ModelOption(
value="us.anthropic.claude-opus-4-5-20251101-v1:0",
label="Claude Opus 4.5 (US cross-region)",
),
ModelOption(
value="us.anthropic.claude-opus-4-1-20250805-v1:0",
label="Claude Opus 4.1 (US cross-region)",
),
ModelOption(
value="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
label="Claude Sonnet 4.5 (US cross-region)",
),
ModelOption(
value="us.anthropic.claude-sonnet-4-20250514-v1:0",
label="Claude Sonnet 4 (US cross-region)",
),
ModelOption(
value="us.anthropic.claude-haiku-4-5-20251001-v1:0",
label="Claude Haiku 4.5 (US cross-region) — fast, cost-efficient",
),
ModelOption(
value="us.meta.llama4-maverick-17b-instruct-v1:0",
label="Llama 4 Maverick 17B (US cross-region)",
),
ModelOption(
value="us.amazon.nova-pro-v1:0",
label="Amazon Nova Pro (US cross-region)",
),
ModelOption(
value="mistral.mistral-large-3-675b-instruct",
label="Mistral Large 3 675B Instruct (on-demand)",
),
)
OLLAMA_MODELS = (
ModelOption(value="llama3.2", label="Llama 3.2 (3B) — recommended"),
ModelOption(value="llama3.1:8b", label="Llama 3.1 (8B)"),
ModelOption(value="mistral", label="Mistral 7B"),
ModelOption(value="qwen2.5:7b", label="Qwen 2.5 (7B)"),
)
# Source: https://platform.claude.com/docs/en/about-claude/models/overview (verified 2026-05-21).
# Empty value means "no --model" so Claude Code uses its configured default.
CLAUDE_CODE_MODELS = (
ModelOption(
value="",
label="CLI default (no --model; use Claude Code configured model)",
),
ModelOption(value="claude-fable-5", label="Claude Fable 5 — most capable"),
ModelOption(value="claude-opus-4-7", label="Claude Opus 4.7"),
ModelOption(value="claude-sonnet-4-6", label="Claude Sonnet 4.6 — balanced"),
ModelOption(value="claude-haiku-4-5", label="Claude Haiku 4.5 — fast, cost-efficient"),
)
# Source: https://developers.openai.com/codex/cli/features (verified 2026-05-21).
# Empty value means "no -m" so the Codex CLI uses its configured default/current model.
CODEX_MODELS = (
ModelOption(
value="",
label="CLI default (no -m; use Codex configured model)",
),
ModelOption(value="gpt-5.6-sol", label="gpt-5.6-sol — newest frontier coding"),
ModelOption(value="gpt-5.6-terra", label="gpt-5.6-terra — balanced"),
ModelOption(value="gpt-5.6-luna", label="gpt-5.6-luna — fast, cost-efficient"),
ModelOption(value="gpt-5.5", label="gpt-5.5 — frontier coding"),
ModelOption(value="gpt-5.4", label="gpt-5.4 — fallback default"),
ModelOption(value="gpt-5.4-mini", label="gpt-5.4-mini — fast, cost-efficient"),
ModelOption(value="gpt-5.3-codex", label="gpt-5.3-codex — coding-optimized"),
ModelOption(
value="gpt-5.3-codex-spark",
label="gpt-5.3-codex-spark — research preview (ChatGPT Pro)",
),
)
# Source: google-gemini/gemini-cli, packages/core/src/config/models.ts (verified 2026-05-21).
# Empty value means "no --model" so Gemini CLI uses its configured/default model.
GEMINI_CLI_MODELS = (
ModelOption(
value="",
label="CLI default (no --model; use Gemini CLI configured model)",
),
ModelOption(
value="gemini-3.1-pro-preview",
label="gemini-3.1-pro-preview — newest frontier (preview)",
),
ModelOption(
value="gemini-3-flash-preview",
label="gemini-3-flash-preview — fast (preview)",
),
ModelOption(
value="gemini-3.1-flash-lite-preview",
label="gemini-3.1-flash-lite-preview — fastest (preview)",
),
ModelOption(
value="gemini-2.5-pro",
label="gemini-2.5-pro — stable, strongest reasoning",
),
ModelOption(
value="gemini-2.5-flash",
label="gemini-2.5-flash — stable, balanced",
),
ModelOption(
value="gemini-2.5-flash-lite",
label="gemini-2.5-flash-lite — stable, fastest",
),
)
# Source: ``agy`` ``/models`` (verified 2026-05-26 against agy 1.0.2).
# Empty value means "no --model" so agy uses its currently configured model.
# Note: agy 1.0.2 does not yet expose ``--model`` in headless ``-p`` mode
# (verified locally), so the adapter ignores any value via ``del model`` in
# ``build()``. Catalog is forward-compat: once Google ships ``--model`` in
# headless, the wizard selection plus ``model_env_key="ANTIGRAVITY_CLI_MODEL"``
# will route through to ``argv`` in a one-line change to ``antigravity_cli.py``.
# Effort variants (Low/Medium/High/Thinking) shown in ``/models`` belong on
# opensre's existing ``reasoning_effort`` knob, not here.
ANTIGRAVITY_CLI_MODELS = (
ModelOption(
value="",
label="CLI default (no --model; use agy's currently configured model)",
),
ModelOption(value="gemini-3.5-flash", label="gemini-3.5-flash — fast"),
ModelOption(value="gemini-3.1-pro", label="gemini-3.1-pro — strongest Google reasoning"),
ModelOption(value="claude-sonnet-4.6", label="claude-sonnet-4.6 — Anthropic balanced"),
ModelOption(value="claude-opus-4.6", label="claude-opus-4.6 — Anthropic most capable"),
ModelOption(value="gpt-oss-120b", label="gpt-oss-120b — open-source"),
)
# Source: https://opencode.ai/docs/zen (verified 2026-05-21).
# OpenCode routes models through OpenCode Zen using the ``opencode/`` prefix.
# Curated subset of the full ~40-model catalog; the wizard's custom-ID escape
# hatch covers anything not pre-listed here.
OPENCODE_MODELS = (
ModelOption(
value="",
label="CLI default (no -m; use OpenCode configured model)",
),
ModelOption(value="opencode/gpt-5.5", label="GPT-5.5 (OpenCode Zen) — frontier"),
ModelOption(value="opencode/gpt-5.4", label="GPT-5.4 (OpenCode Zen)"),
ModelOption(value="opencode/gpt-5.4-mini", label="GPT-5.4 mini (OpenCode Zen) — fast"),
ModelOption(
value="opencode/gpt-5.3-codex",
label="GPT-5.3 Codex (OpenCode Zen) — coding-optimized",
),
ModelOption(
value="opencode/gpt-5.3-codex-spark",
label="GPT-5.3 Codex Spark (OpenCode Zen) — research preview",
),
ModelOption(
value="opencode/claude-opus-4-7",
label="Claude Opus 4.7 (OpenCode Zen) — most capable",
),
ModelOption(
value="opencode/claude-sonnet-4-6",
label="Claude Sonnet 4.6 (OpenCode Zen) — balanced",
),
ModelOption(
value="opencode/claude-haiku-4-5",
label="Claude Haiku 4.5 (OpenCode Zen) — fast",
),
ModelOption(value="opencode/gemini-3.1-pro", label="Gemini 3.1 Pro (OpenCode Zen)"),
ModelOption(value="opencode/gemini-3-flash", label="Gemini 3 Flash (OpenCode Zen)"),
ModelOption(value="opencode/kimi-k2.6", label="Kimi K2.6 (OpenCode Zen)"),
ModelOption(value="opencode/minimax-m2.7", label="MiniMax M2.7 (OpenCode Zen)"),
ModelOption(value="opencode/qwen3.6-plus", label="Qwen3.6 Plus (OpenCode Zen)"),
ModelOption(value="opencode/glm-5.1", label="GLM 5.1 (OpenCode Zen)"),
ModelOption(
value="opencode/minimax-m2.5-free",
label="MiniMax M2.5 (OpenCode Zen) — free tier",
),
ModelOption(
value="opencode/deepseek-v4-flash-free",
label="DeepSeek V4 Flash (OpenCode Zen) — free tier",
),
)
CURSOR_MODELS = (
ModelOption(
value="",
label="CLI default (no --model; use Cursor configured model)",
),
ModelOption(value="auto", label="auto"),
ModelOption(value="gpt-5", label="gpt-5"),
ModelOption(value="sonnet-4", label="sonnet-4"),
ModelOption(value="sonnet-4-thinking", label="sonnet-4-thinking"),
)
def _codex_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.codex import CodexAdapter
return CodexAdapter()
def _cursor_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.cursor import CursorAdapter
return CursorAdapter()
def _claude_code_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.claude_code import ClaudeCodeAdapter
return ClaudeCodeAdapter()
def _gemini_cli_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.gemini_cli import GeminiCLIAdapter
return GeminiCLIAdapter()
def _antigravity_cli_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.antigravity_cli import AntigravityCLIAdapter
return AntigravityCLIAdapter()
def _opencode_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.opencode import OpenCodeAdapter
return OpenCodeAdapter()
def _kimi_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.kimi import KimiAdapter
return KimiAdapter()
def _copilot_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.copilot import CopilotAdapter
return CopilotAdapter()
def _grok_cli_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.grok_cli import GrokCLIAdapter
return GrokCLIAdapter()
_GROK_CLI_DEFAULT_MODEL_OPTION = ModelOption(
value="",
label="CLI default (no -m; use Grok Build configured model)",
)
# Static fallback used when ``grok models`` is unavailable at wizard time.
GROK_CLI_MODELS = (
_GROK_CLI_DEFAULT_MODEL_OPTION,
ModelOption(value="grok-build", label="grok-build"),
ModelOption(value="grok-composer-2.5-fast", label="grok-composer-2.5-fast"),
)
def _pi_adapter_factory() -> LLMCLIAdapter:
from integrations.llm_cli.pi_cli import PiAdapter
return PiAdapter()
# Pi is BYOK/multi-provider; models use the ``provider/model`` form. These are a
# convenience shortlist — ``allow_custom_models=True`` lets users type any model
# (and PI_MODEL overrides at runtime). Run ``pi --list-models`` for the full set.
PI_MODELS = (
ModelOption(value="", label="CLI default (no --model; use Pi configured model)"),
ModelOption(value="google/gemini-2.5-flash-lite", label="google/gemini-2.5-flash-lite"),
ModelOption(value="google/gemini-2.5-flash", label="google/gemini-2.5-flash"),
ModelOption(value="anthropic/claude-haiku-4-5", label="anthropic/claude-haiku-4-5"),
ModelOption(value="openai/gpt-4o-mini", label="openai/gpt-4o-mini"),
)
KIMI_MODELS = (
ModelOption(
value="",
label="CLI default (no -m; use Kimi configured model)",
),
ModelOption(value="kimi-k2-thinking-turbo", label="kimi-k2-thinking-turbo"),
ModelOption(value="kimi-k2.5", label="kimi-k2.5"),
ModelOption(value="kimi-k2.6", label="kimi-k2.6"),
)
# Empty value means "no --model" so Copilot CLI uses its configured default model.
# We do not hardcode model identifiers here: the Copilot CLI's accepted --model
# values are not stable across releases and live behind GitHub-side gating, so
# baking them in risks "model not found" errors after the user has finished the
# wizard. Users override via COPILOT_MODEL when they know what their plan exposes.
COPILOT_MODELS = (
ModelOption(
value="",
label="CLI default (no --model; use Copilot CLI configured model)",
),
)
SUPPORTED_PROVIDERS = (
ProviderOption(
value="anthropic",
label="Anthropic API key",
group="Hosted providers",
api_key_env="ANTHROPIC_API_KEY",
model_env="ANTHROPIC_REASONING_MODEL",
default_model=ANTHROPIC_REASONING_MODEL,
models=ANTHROPIC_MODELS,
legacy_model_env="ANTHROPIC_MODEL",
toolcall_model_env="ANTHROPIC_TOOLCALL_MODEL",
classification_model_env="ANTHROPIC_CLASSIFICATION_MODEL",
),
ProviderOption(
value="claude-code",
label="Anthropic Claude Code CLI",
group="Hosted providers",
api_key_env="",
model_env="CLAUDE_CODE_MODEL",
default_model="",
models=CLAUDE_CODE_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_claude_code_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="openai",
label="OpenAI API key",
group="Hosted providers",
api_key_env="OPENAI_API_KEY",
model_env="OPENAI_REASONING_MODEL",
default_model=OPENAI_REASONING_MODEL,
models=OPENAI_MODELS,
legacy_model_env="OPENAI_MODEL",
toolcall_model_env="OPENAI_TOOLCALL_MODEL",
classification_model_env="OPENAI_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="codex",
label="OpenAI Codex CLI",
group="Hosted providers",
api_key_env="",
model_env="CODEX_MODEL",
default_model="",
models=CODEX_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_codex_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="openrouter",
label="OpenRouter",
group="Hosted providers",
api_key_env="OPENROUTER_API_KEY",
model_env="OPENROUTER_REASONING_MODEL",
default_model=OPENROUTER_REASONING_MODEL,
models=OPENROUTER_MODELS,
legacy_model_env="OPENROUTER_MODEL",
toolcall_model_env="OPENROUTER_TOOLCALL_MODEL",
classification_model_env="OPENROUTER_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="deepseek",
label="DeepSeek",
group="Hosted providers",
api_key_env="DEEPSEEK_API_KEY",
model_env="DEEPSEEK_REASONING_MODEL",
default_model=DEEPSEEK_REASONING_MODEL,
models=DEEPSEEK_MODELS,
legacy_model_env="DEEPSEEK_MODEL",
toolcall_model_env="DEEPSEEK_TOOLCALL_MODEL",
classification_model_env="DEEPSEEK_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="gemini",
label="Google Gemini API key",
group="Hosted providers",
api_key_env="GEMINI_API_KEY",
model_env="GEMINI_REASONING_MODEL",
default_model=GEMINI_REASONING_MODEL,
models=GEMINI_MODELS,
legacy_model_env="GEMINI_MODEL",
toolcall_model_env="GEMINI_TOOLCALL_MODEL",
classification_model_env="GEMINI_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="gemini-cli",
label="Google Gemini CLI",
group="Hosted providers",
api_key_env="",
model_env="GEMINI_CLI_MODEL",
default_model="",
models=GEMINI_CLI_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_gemini_cli_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="antigravity-cli",
label="Google Antigravity CLI",
group="Hosted providers",
api_key_env="",
model_env="ANTIGRAVITY_CLI_MODEL",
default_model="",
models=ANTIGRAVITY_CLI_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_antigravity_cli_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="nvidia",
label="NVIDIA NIM",
group="Hosted providers",
api_key_env="NVIDIA_API_KEY",
model_env="NVIDIA_REASONING_MODEL",
default_model=NVIDIA_REASONING_MODEL,
models=NVIDIA_MODELS,
legacy_model_env="NVIDIA_MODEL",
toolcall_model_env="NVIDIA_TOOLCALL_MODEL",
classification_model_env="NVIDIA_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="minimax",
label="MiniMax",
group="Hosted providers",
api_key_env="MINIMAX_API_KEY",
model_env="MINIMAX_REASONING_MODEL",
default_model=MINIMAX_REASONING_MODEL,
models=MINIMAX_MODELS,
legacy_model_env="MINIMAX_MODEL",
toolcall_model_env="MINIMAX_TOOLCALL_MODEL",
classification_model_env="MINIMAX_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="bedrock",
label="Amazon Bedrock (IAM auth)",
group="Hosted providers",
# Intentionally empty: Bedrock authenticates via the IAM credential
# chain (env, ~/.aws/credentials, instance profile) — no API key to
# prompt for. Empty string is safe: every downstream check uses
# ``bool(provider.api_key_env)`` or ``.get()`` (never subscript).
api_key_env="",
model_env="BEDROCK_REASONING_MODEL",
default_model=BEDROCK_REASONING_MODEL,
models=BEDROCK_MODELS,
toolcall_model_env="BEDROCK_TOOLCALL_MODEL",
classification_model_env="BEDROCK_CLASSIFICATION_MODEL",
credential_label="AWS region (uses IAM credentials)",
credential_secret=False,
# credential_kind="none" causes flow.py to skip the credential prompt
# entirely. Region is picked up from AWS_DEFAULT_REGION / ~/.aws/config.
credential_kind="none",
allow_custom_models=True,
),
ProviderOption(
value="groq",
label="Groq API key",
group="Hosted providers",
api_key_env="GROQ_API_KEY",
model_env="GROQ_REASONING_MODEL",
default_model=GROQ_REASONING_MODEL,
models=GROQ_MODELS,
legacy_model_env="GROQ_MODEL",
toolcall_model_env="GROQ_TOOLCALL_MODEL",
classification_model_env="GROQ_CLASSIFICATION_MODEL",
allow_custom_models=True,
),
ProviderOption(
value="azure-openai",
label="Azure OpenAI",
group="Hosted providers",
api_key_env="AZURE_OPENAI_API_KEY",
model_env="AZURE_OPENAI_REASONING_MODEL",
default_model=AZURE_OPENAI_REASONING_MODEL,
models=AZURE_OPENAI_MODELS,
legacy_model_env="AZURE_OPENAI_MODEL",
toolcall_model_env="AZURE_OPENAI_TOOLCALL_MODEL",
classification_model_env="AZURE_OPENAI_CLASSIFICATION_MODEL",
endpoint_env="AZURE_OPENAI_BASE_URL",
api_version_env="AZURE_OPENAI_API_VERSION",
credential_default="https://your-resource.openai.azure.com",
allow_custom_models=True,
),
ProviderOption(
value="grok-cli",
label="xAI Grok Build CLI",
group="Hosted providers",
api_key_env="",
model_env="GROK_CLI_MODEL",
default_model="",
models=GROK_CLI_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_grok_cli_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="cursor",
label="Cursor Agent CLI",
group="Local CLI providers",
api_key_env="",
model_env="CURSOR_MODEL",
default_model="auto",
models=CURSOR_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_cursor_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="opencode",
label="OpenCode CLI",
group="Local CLI providers",
api_key_env="",
model_env="OPENCODE_MODEL",
default_model="",
models=OPENCODE_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_opencode_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="kimi",
label="Kimi Code CLI",
group="Local CLI providers",
api_key_env="",
model_env="KIMI_MODEL",
default_model="",
models=KIMI_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_kimi_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="copilot",
label="GitHub Copilot CLI",
group="Local CLI providers",
api_key_env="",
model_env="COPILOT_MODEL",
default_model="",
models=COPILOT_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_copilot_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="pi",
label="Pi CLI (pi.dev, BYOK multi-provider)",
group="Local CLI providers",
api_key_env="",
model_env="PI_MODEL",
default_model="",
models=PI_MODELS,
credential_kind="cli",
credential_secret=False,
adapter_factory=_pi_adapter_factory,
allow_custom_models=True,
),
ProviderOption(
value="ollama",
label="Ollama (local)",
group="Local providers",
api_key_env="OLLAMA_HOST",
model_env="OLLAMA_MODEL",
default_model=DEFAULT_OLLAMA_MODEL,
models=OLLAMA_MODELS,
credential_label="host URL",
credential_secret=False,
credential_default=DEFAULT_OLLAMA_HOST,
credential_kind="host",
allow_custom_models=True,
),
)
PROVIDER_BY_VALUE = {provider.value: provider for provider in SUPPORTED_PROVIDERS}