Skip to content
Open
Show file tree
Hide file tree
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
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ docker pull ghcr.io/stakpak/agent:latest
```

## Usage
You can [use your own Anthropic or OpenAI API keys](#option-b-running-without-a-stakpak-api-key), [custom OpenAI compatible endpoint](#option-b-running-without-a-stakpak-api-key), or [a Stakpak API key](#option-a-running-with-a-stakpak-api-key).
You can [use your own Anthropic or OpenAI API keys](#option-b-running-without-a-stakpak-api-key), [custom OpenAI compatible endpoint](#option-b-running-without-a-stakpak-api-key), [MiniMax API keys](#option-b-running-without-a-stakpak-api-key), or [a Stakpak API key](#option-a-running-with-a-stakpak-api-key).
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add it to the [use your own Anthropic or OpenAI API keys] instead of making a seperate entry


### Option A: Running with a Stakpak API Key (no card required)

Expand Down Expand Up @@ -207,6 +207,9 @@ stakpak auth login --provider openai --api-key $OPENAI_API_KEY

# Gemini
stakpak auth login --provider gemini --api-key $GEMINI_API_KEY

# MiniMax
stakpak auth login --provider minimax --api-key $MINIMAX_API_KEY
```

#### Manual configuration
Expand All @@ -222,7 +225,7 @@ provider = "local"
model = "anthropic/claude-sonnet-4-5"

# Built-in providers - credentials can also be set via environment variables
# (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY)
# (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, MINIMAX_API_KEY)
[profiles.byok.providers.anthropic]
type = "anthropic"
api_key = "sk-ant-..."
Expand All @@ -235,6 +238,10 @@ api_key = "sk-..."
type = "gemini"
api_key = "..."

[profiles.byok.providers.minimax]
type = "minimax"
api_key = "..."

[settings]
```

Expand Down
5 changes: 3 additions & 2 deletions cli/src/commands/auth/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::config::AppConfig;
use crate::config::{ProfileConfig, ProviderType};
use crate::onboarding::config_templates::{
generate_anthropic_profile, generate_gemini_profile, generate_github_copilot_profile,
generate_openai_profile,
generate_minimax_profile, generate_openai_profile,
};
use crate::onboarding::menu::{prompt_password, select_option_no_header};
use crate::onboarding::navigation::NavResult;
Expand Down Expand Up @@ -397,6 +397,7 @@ async fn handle_non_interactive_api_setup(
"anthropic" => generate_anthropic_profile(),
"openai" => generate_openai_profile(),
"gemini" => generate_gemini_profile(),
"minimax" => generate_minimax_profile(),
"github-copilot" => {
return Err("GitHub Copilot does not support API key authentication.\n\
It requires OAuth via your GitHub account.\n\n\
Expand All @@ -409,7 +410,7 @@ async fn handle_non_interactive_api_setup(
}
_ => {
return Err(format!(
"Unsupported provider '{}'. Supported: anthropic, openai, gemini, stakpak, amazon-bedrock, github-copilot\n\
"Unsupported provider '{}'. Supported: anthropic, openai, gemini, minimax, stakpak, amazon-bedrock, github-copilot\n\
For bedrock, use: stakpak auth login --provider amazon-bedrock --region <region>\n\
For github-copilot, run without --api-key to use the device flow.",
provider_id
Expand Down
4 changes: 3 additions & 1 deletion cli/src/config/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ impl AppConfig {
"anthropic" => "ANTHROPIC_API_KEY",
"openai" => "OPENAI_API_KEY",
"gemini" => "GEMINI_API_KEY",
"minimax" => "MINIMAX_API_KEY",
_ => return None,
};

Expand Down Expand Up @@ -835,14 +836,15 @@ impl AppConfig {
}

let config_provider = Some("Local".to_string());
let builtin_providers = ["anthropic", "openai", "gemini"];
let builtin_providers = ["anthropic", "openai", "gemini", "minimax"];

for provider_name in builtin_providers {
if let Some(auth) = self.resolve_provider_auth(provider_name) {
let base_name = match provider_name {
"anthropic" => "Anthropic",
"openai" => "OpenAI",
"gemini" => "Gemini",
"minimax" => "MiniMax",
_ => provider_name,
};

Expand Down
9 changes: 9 additions & 0 deletions cli/src/config/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,15 @@ impl ProfileConfig {
}
}
}
ProviderConfig::MiniMax { api_endpoint, .. } => {
if let Some(ep) = api_endpoint {
let clean = Self::clean_api_endpoint(Some(ep.clone()));
if clean.as_ref() != Some(ep) {
*api_endpoint = clean;
cleaned = true;
}
}
}
}
}

Expand Down
47 changes: 47 additions & 0 deletions cli/src/onboarding/config_templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,24 @@ pub fn generate_anthropic_profile() -> ProfileConfig {
profile
}

/// Generate MiniMax profile configuration (credentials stored separately in config.toml auth field)
pub fn generate_minimax_profile() -> ProfileConfig {
let mut profile = ProfileConfig {
provider: Some(ProviderType::Local),
model: Some("minimax/MiniMax-M2.7".to_string()),
..ProfileConfig::default()
};
profile.providers.insert(
"minimax".to_string(),
ProviderConfig::MiniMax {
api_key: None,
api_endpoint: None,
auth: None,
},
);
profile
}

/// Generate custom provider profile configuration
///
/// This creates a profile with a custom OpenAI-compatible provider (e.g., LiteLLM, Ollama).
Expand Down Expand Up @@ -181,6 +199,7 @@ pub enum BuiltinProvider {
OpenAI,
Gemini,
Anthropic,
MiniMax,
}

impl BuiltinProvider {
Expand All @@ -189,6 +208,7 @@ impl BuiltinProvider {
BuiltinProvider::OpenAI => "OpenAI",
BuiltinProvider::Gemini => "Gemini",
BuiltinProvider::Anthropic => "Anthropic",
BuiltinProvider::MiniMax => "MiniMax",
}
}

Expand All @@ -197,6 +217,7 @@ impl BuiltinProvider {
BuiltinProvider::OpenAI => "gpt-4.1",
BuiltinProvider::Gemini => "gemini-2.5-pro",
BuiltinProvider::Anthropic => DEFAULT_MODEL,
BuiltinProvider::MiniMax => "minimax/MiniMax-M2.7",
}
}
}
Expand Down Expand Up @@ -259,6 +280,16 @@ pub fn generate_multi_provider_profile(
},
);
}
BuiltinProvider::MiniMax => {
profile.providers.insert(
"minimax".to_string(),
ProviderConfig::MiniMax {
api_key: Some(setup.api_key),
api_endpoint: None,
auth: None,
},
);
}
}
}

Expand Down Expand Up @@ -395,6 +426,22 @@ pub fn config_to_toml_preview(profile: &ProfileConfig, profile_name: &str) -> St
toml.push_str(&format!("# auth: {} (set)\n", a.auth_type_display()));
}
}
ProviderConfig::MiniMax {
api_key,
api_endpoint,
..
} => {
toml.push_str("type = \"minimax\"\n");
if let Some(key) = api_key {
toml.push_str(&format!(
"api_key = \"{}\"\n",
if key.is_empty() { "" } else { "***" }
));
}
if let Some(endpoint) = api_endpoint {
toml.push_str(&format!("api_endpoint = \"{}\"\n", endpoint));
}
}
}
}

Expand Down
11 changes: 9 additions & 2 deletions libs/ai/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use super::{ClientConfig, Inference, InferenceConfig};
use crate::error::Result;
use crate::provider::Provider;
use crate::providers::{
anthropic::AnthropicProvider, gemini::GeminiProvider, openai::OpenAIProvider,
stakpak::StakpakProvider,
anthropic::AnthropicProvider, gemini::GeminiProvider, minimax::MiniMaxProvider,
openai::OpenAIProvider, stakpak::StakpakProvider,
};
use crate::registry::ProviderRegistry;

Expand Down Expand Up @@ -72,6 +72,13 @@ impl ClientBuilder {
registry = registry.register("stakpak", provider);
}

// Register MiniMax if configured
if let Some(config) = inference_config.minimax_config
&& let Ok(provider) = MiniMaxProvider::new(config)
{
registry = registry.register("minimax", provider);
}

// Register Bedrock if configured
#[cfg(feature = "bedrock")]
if let Some(config) = inference_config.bedrock_config {
Expand Down
47 changes: 45 additions & 2 deletions libs/ai/src/client/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Client configuration

use crate::providers::{
anthropic::AnthropicConfig, gemini::GeminiConfig, openai::OpenAIConfig,
stakpak::StakpakProviderConfig,
anthropic::AnthropicConfig, gemini::GeminiConfig, minimax::MiniMaxConfig,
openai::OpenAIConfig, stakpak::StakpakProviderConfig,
};

#[cfg(feature = "bedrock")]
Expand Down Expand Up @@ -67,6 +67,7 @@ pub struct InferenceConfig {
pub(crate) anthropic_config: Option<AnthropicConfig>,
pub(crate) gemini_config: Option<GeminiConfig>,
pub(crate) stakpak_config: Option<StakpakProviderConfig>,
pub(crate) minimax_config: Option<MiniMaxConfig>,
#[cfg(feature = "bedrock")]
pub(crate) bedrock_config: Option<BedrockConfig>,
pub(crate) client_config: ClientConfig,
Expand Down Expand Up @@ -257,6 +258,48 @@ impl InferenceConfig {
self
}

/// Configure MiniMax provider with API key and optional base URL
///
/// MiniMax provides OpenAI-compatible API access to MiniMax-M2.7
/// and MiniMax-M2.5 series models.
///
/// # Example
///
/// ```rust,no_run
/// # use stakai::InferenceConfig;
/// let config = InferenceConfig::new()
/// .minimax("your-api-key", None);
///
/// // With custom base URL
/// let config = InferenceConfig::new()
/// .minimax("your-api-key", Some("https://custom.minimax.io/v1".to_string()));
/// ```
pub fn minimax(mut self, api_key: impl Into<String>, base_url: Option<String>) -> Self {
let mut config = MiniMaxConfig::new(api_key);
if let Some(url) = base_url {
config = config.with_base_url(url);
}
self.minimax_config = Some(config);
self
}

/// Configure MiniMax provider with full MiniMaxConfig
///
/// # Example
///
/// ```rust,no_run
/// # use stakai::{InferenceConfig, providers::minimax::MiniMaxConfig};
/// let minimax_config = MiniMaxConfig::new("your-api-key")
/// .with_base_url("https://custom.minimax.io/v1");
///
/// let config = InferenceConfig::new()
/// .minimax_config(minimax_config);
/// ```
pub fn minimax_config(mut self, config: MiniMaxConfig) -> Self {
self.minimax_config = Some(config);
self
}

/// Configure AWS Bedrock provider with a region
///
/// Uses the AWS credential chain for authentication (env vars, shared credentials,
Expand Down
4 changes: 4 additions & 0 deletions libs/ai/src/provider/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub enum ProviderKind {
Anthropic,
/// Google Gemini provider (future)
Google,
/// MiniMax provider
MiniMax,
}

impl ProviderKind {
Expand All @@ -21,6 +23,7 @@ impl ProviderKind {
Self::OpenAI => "openai",
Self::Anthropic => "anthropic",
Self::Google => "google",
Self::MiniMax => "minimax",
}
}
}
Expand All @@ -33,6 +36,7 @@ impl std::str::FromStr for ProviderKind {
"openai" => Ok(Self::OpenAI),
"anthropic" => Ok(Self::Anthropic),
"google" | "gemini" => Ok(Self::Google),
"minimax" => Ok(Self::MiniMax),
_ => Err(Error::UnknownProvider(s.to_string())),
}
}
Expand Down
Loading
Loading