pub use crate::tui::provider_selector::EXISTING_KEY_SENTINEL;
pub const PROVIDERS: &[ProviderInfo] = &[
ProviderInfo {
id: "anthropic",
name: "Anthropic Claude",
models: &[], key_label: "Setup Token",
help_lines: &[
"Claude Max / Code: run 'claude setup-token'",
"Or paste API key from console.anthropic.com",
],
},
ProviderInfo {
id: "openai",
name: "OpenAI",
models: &[],
key_label: "API Key",
help_lines: &["Get key from platform.openai.com"],
},
ProviderInfo {
id: "github",
name: "GitHub Copilot",
models: &[],
key_label: "OAuth",
help_lines: &["Sign in with GitHub to use your Copilot subscription"],
},
ProviderInfo {
id: "gemini",
name: "Google Gemini",
models: &[],
key_label: "API Key",
help_lines: &["Get key from aistudio.google.com"],
},
ProviderInfo {
id: "openrouter",
name: "OpenRouter",
models: &[],
key_label: "API Key",
help_lines: &["Get key from openrouter.ai/keys"],
},
ProviderInfo {
id: "minimax",
name: "Minimax",
models: &[], key_label: "API Key",
help_lines: &["Get key from platform.minimax.io"],
},
ProviderInfo {
id: "zhipu",
name: "z.ai GLM",
models: &[], key_label: "API Key",
help_lines: &["Get key from open.bigmodel.cn"],
},
ProviderInfo {
id: "claude-cli",
name: "Claude CLI",
models: &["sonnet", "opus", "haiku"],
key_label: "",
help_lines: &[
"Uses local 'claude' CLI subprocess — no API key needed",
"Requires: npm install -g @anthropic-ai/claude-code",
],
},
ProviderInfo {
id: "opencode-cli",
name: "OpenCode CLI",
models: &[],
key_label: "",
help_lines: &[
"Uses local 'opencode' CLI subprocess — free models, no API key needed",
"Requires: curl -fsSL https://opencode.ai/install | bash",
],
},
ProviderInfo {
id: "qwen-code-cli",
name: "Qwen CLI",
models: &["qwen3.6-plus", "qwen3.5-plus", "qwen3-coder-plus"],
key_label: "",
help_lines: &[
"Uses local 'qwen' CLI subprocess — 1k free req/day via Qwen OAuth",
"Requires: npm install -g @qwen-code/qwen-code OR brew install qwen-code",
],
},
ProviderInfo {
id: "qwen",
name: "Qwen",
models: &["qwen3.6-plus"],
key_label: "OAuth",
help_lines: &[
"Sign in with qwen.ai — OpenCrabs orchestrates tools and context natively",
"Free tier: 60 req/min, 1000 req/day",
],
},
ProviderInfo {
id: "", name: "Custom OpenAI-Compatible",
models: &[],
key_label: "API Key",
help_lines: &["Enter your own API endpoint"],
},
];
pub struct ProviderInfo {
pub id: &'static str,
pub name: &'static str,
pub models: &'static [&'static str],
pub key_label: &'static str,
pub help_lines: &'static [&'static str],
}
pub const CHANNEL_NAMES: &[(&str, &str)] = &[
("Telegram", "Bot token (via @BotFather)"),
("Discord", "Bot token (via Developer Portal)"),
("WhatsApp", "QR code pairing"),
("Slack", "Socket Mode (bot + app tokens)"),
("Trello", "API Key + Token from trello.com/power-ups/admin"),
];
pub const TEMPLATE_FILES: &[(&str, &str)] = &[
(
"SOUL.md",
include_str!("../../docs/reference/templates/SOUL.md"),
),
(
"IDENTITY.md",
include_str!("../../docs/reference/templates/IDENTITY.md"),
),
(
"USER.md",
include_str!("../../docs/reference/templates/USER.md"),
),
(
"AGENTS.md",
include_str!("../../docs/reference/templates/AGENTS.md"),
),
(
"TOOLS.md",
include_str!("../../docs/reference/templates/TOOLS.md"),
),
(
"MEMORY.md",
include_str!("../../docs/reference/templates/MEMORY.md"),
),
(
"CODE.md",
include_str!("../../docs/reference/templates/CODE.md"),
),
(
"SECURITY.md",
include_str!("../../docs/reference/templates/SECURITY.md"),
),
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OnboardingStep {
ModeSelect,
Workspace,
ProviderAuth,
Channels,
TelegramSetup,
DiscordSetup,
WhatsAppSetup,
SlackSetup,
TrelloSetup,
VoiceSetup,
ImageSetup,
Daemon,
HealthCheck,
BrainSetup,
Complete,
}
impl OnboardingStep {
pub fn number(&self) -> usize {
match self {
Self::ModeSelect => 1,
Self::Workspace => 2,
Self::ProviderAuth => 3,
Self::Channels => 4,
Self::TelegramSetup => 4, Self::DiscordSetup => 4, Self::WhatsAppSetup => 4, Self::SlackSetup => 4, Self::TrelloSetup => 4, Self::VoiceSetup => 5,
Self::ImageSetup => 6,
Self::Daemon => 7,
Self::HealthCheck => 8,
Self::BrainSetup => 9,
Self::Complete => 10,
}
}
pub fn total() -> usize {
9
}
pub fn title(&self) -> &'static str {
match self {
Self::ModeSelect => "Pick Your Vibe",
Self::Workspace => "Home Base",
Self::ProviderAuth => "Brain Fuel",
Self::Channels => "Chat Me Anywhere",
Self::TelegramSetup => "Telegram Bot",
Self::DiscordSetup => "Discord Bot",
Self::WhatsAppSetup => "WhatsApp",
Self::SlackSetup => "Slack Bot",
Self::TrelloSetup => "Trello",
Self::VoiceSetup => "Voice Superpowers",
Self::ImageSetup => "Image Handling",
Self::Daemon => "Always On",
Self::HealthCheck => "Vibe Check",
Self::BrainSetup => "Make It Yours",
Self::Complete => "Let's Go!",
}
}
pub fn subtitle(&self) -> &'static str {
match self {
Self::ModeSelect => "Quick and easy or full control — your call",
Self::Workspace => "Where my brain lives on disk",
Self::ProviderAuth => "Pick your AI model and drop your key",
Self::Channels => "Chat with me from your phone — Telegram, WhatsApp, whatever",
Self::TelegramSetup => "Hook up your Telegram bot token",
Self::DiscordSetup => "Hook up your Discord bot token",
Self::WhatsAppSetup => "Scan the QR code with your phone",
Self::SlackSetup => "Hook up your Slack bot and app tokens",
Self::TrelloSetup => "Hook up your Trello API Key and Token",
Self::VoiceSetup => "Talk to me, literally",
Self::ImageSetup => "Vision and image generation via Google Gemini",
Self::Daemon => "Keep me running in the background",
Self::HealthCheck => "Making sure everything's wired up right",
Self::BrainSetup => "Make me yours, drop some context so I actually get you",
Self::Complete => "You're all set — let's build something cool",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WizardMode {
QuickStart,
Advanced,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HealthStatus {
Pending,
Running,
Pass,
Fail(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AuthField {
Provider,
ApiKey,
Model,
CustomName,
CustomBaseUrl,
CustomApiKey,
CustomModel,
CustomContextWindow,
ZhipuEndpointType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiscordField {
BotToken,
ChannelID,
AllowedList,
RespondTo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SlackField {
BotToken,
AppToken,
ChannelID,
AllowedList,
RespondTo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TelegramField {
BotToken,
UserID,
RespondTo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WhatsAppField {
Connection,
PhoneAllowlist,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrelloField {
ApiKey,
ApiToken,
BoardId,
AllowedUsers,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChannelTestStatus {
Idle,
Testing,
Success,
Failed(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VoiceField {
SttModeSelect,
GroqApiKey,
LocalModelSelect,
TtsModeSelect,
TtsLocalVoiceSelect,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImageField {
VisionToggle,
GenerationToggle,
ApiKey,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GitHubDeviceFlowStatus {
Idle,
WaitingForUser,
Complete,
Failed(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum QwenDeviceFlowStatus {
#[default]
Idle,
WaitingForUser { verification_uri: String },
Complete,
Failed(String),
RotationStep { current: usize, total: usize },
RotationSignout { current: usize, total: usize },
RotationComplete,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BrainField {
AboutMe,
AboutAgent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WizardAction {
None,
Cancel,
Complete,
GenerateBrain,
FetchModels,
WhatsAppConnect,
TestTelegram,
TestDiscord,
TestSlack,
TestWhatsApp,
TestTrello,
DownloadWhisperModel,
DownloadPiperVoice,
GitHubDeviceFlow,
QwenDeviceFlow,
QwenRotationFlow,
QwenRotationNext,
QuickJumpDone,
}