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
6 changes: 6 additions & 0 deletions backend/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ type Config struct {
QwenServerURL string `env:"QWEN_SERVER_URL" envDefault:"https://dashscope-us.aliyuncs.com/compatible-mode/v1"`
QwenProvider string `env:"QWEN_PROVIDER"`

// === LLM Provider: MiniMax ===
MiniMaxAPIKey string `env:"MINIMAX_API_KEY"`
MiniMaxServerURL string `env:"MINIMAX_SERVER_URL" envDefault:"https://api.minimax.io/v1"`
MiniMaxProvider string `env:"MINIMAX_PROVIDER"`

// === Search Engine: DuckDuckGo ===
DuckDuckGoEnabled bool `env:"DUCKDUCKGO_ENABLED" envDefault:"true"`
DuckDuckGoRegion string `env:"DUCKDUCKGO_REGION"`
Expand Down Expand Up @@ -322,6 +327,7 @@ func (c *Config) GetSecretPatterns() []patterns.Pattern {
{c.GLMAPIKey, "GLM Key"},
{c.KimiAPIKey, "Kimi Key"},
{c.QwenAPIKey, "Qwen Key"},
{c.MiniMaxAPIKey, "MiniMax Key"},
{c.GoogleAPIKey, "Google API Key"},
{c.GoogleCXKey, "Google CX Key"},
{c.OAuthGoogleClientID, "Google Client ID"},
Expand Down
130 changes: 130 additions & 0 deletions backend/pkg/providers/minimax/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
simple:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 8192
price:
input: 0.60
output: 2.40

simple_json:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 4096
json: true
price:
input: 0.60
output: 2.40

primary_agent:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 16384
price:
input: 0.60
output: 2.40

assistant:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 16384
price:
input: 0.60
output: 2.40

generator:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 32768
price:
input: 0.60
output: 2.40

refiner:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 20480
price:
input: 0.60
output: 2.40

adviser:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 8192
price:
input: 0.60
output: 2.40

reflector:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 4096
price:
input: 0.60
output: 2.40

searcher:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 4096
price:
input: 0.60
output: 2.40

enricher:
model: MiniMax-M3
temperature: 0.7
top_p: 0.8
n: 1
max_tokens: 4096
price:
input: 0.60
output: 2.40

coder:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 20480
price:
input: 0.60
output: 2.40

installer:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 16384
price:
input: 0.60
output: 2.40

pentester:
model: MiniMax-M3
temperature: 0.5
top_p: 0.5
n: 1
max_tokens: 16384
price:
input: 0.60
output: 2.40
194 changes: 194 additions & 0 deletions backend/pkg/providers/minimax/minimax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package minimax

import (
"context"
"embed"
"fmt"

"pentagi/pkg/config"
"pentagi/pkg/providers/pconfig"
"pentagi/pkg/providers/provider"
"pentagi/pkg/system"
"pentagi/pkg/templates"

"github.com/vxcontrol/langchaingo/llms"
"github.com/vxcontrol/langchaingo/llms/openai"
"github.com/vxcontrol/langchaingo/llms/streaming"
)

//go:embed config.yml models.yml
var configFS embed.FS

// MiniMaxAgentModel is the fallback model used when no agent-specific configuration exists.
// MiniMax-M3 is the latest flagship model (512K context, up to 128K output, image input support)
// and serves as the default for all agent types.
const MiniMaxAgentModel = "MiniMax-M3"

// MiniMaxToolCallIDTemplate is the pattern template for tool call IDs used by MiniMax.
const MiniMaxToolCallIDTemplate = "call_{r:24:b}"

func BuildProviderConfig(configData []byte) (*pconfig.ProviderConfig, error) {
defaultOptions := []llms.CallOption{
llms.WithModel(MiniMaxAgentModel),
llms.WithN(1),
llms.WithMaxTokens(4000),
}

providerConfig, err := pconfig.LoadConfigData(configData, defaultOptions)
if err != nil {
return nil, err
}

return providerConfig, nil
}

func DefaultProviderConfig() (*pconfig.ProviderConfig, error) {
configData, err := configFS.ReadFile("config.yml")
if err != nil {
return nil, err
}

return BuildProviderConfig(configData)
}

func DefaultModels() (pconfig.ModelsConfig, error) {
configData, err := configFS.ReadFile("models.yml")
if err != nil {
return nil, err
}

return pconfig.LoadModelsConfigData(configData)
}

type minimaxProvider struct {
llm *openai.LLM
models pconfig.ModelsConfig
providerName provider.ProviderName
providerConfig *pconfig.ProviderConfig
providerPrefix string
}

func New(
cfg *config.Config,
providerName provider.ProviderName,
providerConfig *pconfig.ProviderConfig,
) (provider.Provider, error) {
if cfg.MiniMaxAPIKey == "" {
return nil, fmt.Errorf("missing MINIMAX_API_KEY environment variable")
}

httpClient, err := system.GetHTTPClient(cfg)
if err != nil {
return nil, err
}

models, err := DefaultModels()
if err != nil {
return nil, err
}

client, err := openai.New(
openai.WithToken(cfg.MiniMaxAPIKey),
openai.WithModel(MiniMaxAgentModel),
openai.WithBaseURL(cfg.MiniMaxServerURL),
openai.WithHTTPClient(httpClient),
)
if err != nil {
return nil, err
}

return &minimaxProvider{
llm: client,
models: models,
providerName: providerName,
providerConfig: providerConfig,
providerPrefix: cfg.MiniMaxProvider,
}, nil
}

func (p *minimaxProvider) Type() provider.ProviderType {
return provider.ProviderMiniMax
}

func (p *minimaxProvider) Name() provider.ProviderName {
return p.providerName
}

func (p *minimaxProvider) GetRawConfig() []byte {
return p.providerConfig.GetRawConfig()
}

func (p *minimaxProvider) GetProviderConfig() *pconfig.ProviderConfig {
return p.providerConfig
}

func (p *minimaxProvider) GetPriceInfo(opt pconfig.ProviderOptionsType) *pconfig.PriceInfo {
return p.providerConfig.GetPriceInfoForType(opt)
}

func (p *minimaxProvider) GetModels() pconfig.ModelsConfig {
return p.models
}

func (p *minimaxProvider) Model(opt pconfig.ProviderOptionsType) string {
model := MiniMaxAgentModel
opts := llms.CallOptions{Model: &model}
for _, option := range p.providerConfig.GetOptionsForType(opt) {
option(&opts)
}

return opts.GetModel()
}

func (p *minimaxProvider) ModelWithPrefix(opt pconfig.ProviderOptionsType) string {
return provider.ApplyModelPrefix(p.Model(opt), p.providerPrefix)
}

func (p *minimaxProvider) Call(
ctx context.Context,
opt pconfig.ProviderOptionsType,
prompt string,
) (string, error) {
return provider.WrapGenerateFromSinglePrompt(
ctx, p, opt, p.llm, prompt,
p.providerConfig.GetOptionsForType(opt)...,
)
}

func (p *minimaxProvider) CallEx(
ctx context.Context,
opt pconfig.ProviderOptionsType,
chain []llms.MessageContent,
streamCb streaming.Callback,
) (*llms.ContentResponse, error) {
return provider.WrapGenerateContent(
ctx, p, opt, p.llm.GenerateContent, chain,
append([]llms.CallOption{
llms.WithStreamingFunc(streamCb),
}, p.providerConfig.GetOptionsForType(opt)...)...,
)
}

func (p *minimaxProvider) CallWithTools(
ctx context.Context,
opt pconfig.ProviderOptionsType,
chain []llms.MessageContent,
tools []llms.Tool,
streamCb streaming.Callback,
) (*llms.ContentResponse, error) {
return provider.WrapGenerateContent(
ctx, p, opt, p.llm.GenerateContent, chain,
append([]llms.CallOption{
llms.WithTools(tools),
llms.WithStreamingFunc(streamCb),
}, p.providerConfig.GetOptionsForType(opt)...)...,
)
}

func (p *minimaxProvider) GetUsage(info map[string]any) pconfig.CallUsage {
return pconfig.NewCallUsage(info)
}

func (p *minimaxProvider) GetToolCallIDTemplate(ctx context.Context, prompter templates.Prompter) (string, error) {
return provider.DetermineToolCallIDTemplate(ctx, p, pconfig.OptionsTypeSimple, prompter, MiniMaxToolCallIDTemplate)
}
Loading