Files
nofx/agent/model_provider_catalog.go
2026-04-25 16:18:45 +08:00

243 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package agent
import (
"fmt"
"strings"
)
type modelProviderSpec struct {
ID string
DisplayName string
DefaultModel string
CredentialLabelZH string
CredentialLabelEN string
SupportsCustomAPIURL bool
SupportsCustomModel bool
UsesWalletCredential bool
Recommended bool
RecommendedModelHints []string
}
func supportedModelProviders() []modelProviderSpec {
return []modelProviderSpec{
{ID: "deepseek", DisplayName: "DeepSeek", DefaultModel: "deepseek-chat", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "qwen", DisplayName: "Qwen", DefaultModel: "qwen3-max", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "openai", DisplayName: "OpenAI", DefaultModel: "gpt-5.1", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "claude", DisplayName: "Claude", DefaultModel: "claude-opus-4-6", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "gemini", DisplayName: "Google Gemini", DefaultModel: "gemini-3-pro-preview", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "grok", DisplayName: "Grok (xAI)", DefaultModel: "grok-3-latest", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "kimi", DisplayName: "Kimi (Moonshot)", DefaultModel: "moonshot-v1-auto", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{ID: "minimax", DisplayName: "MiniMax", DefaultModel: "MiniMax-M2.5", CredentialLabelZH: "API Key", CredentialLabelEN: "API key", SupportsCustomAPIURL: true, SupportsCustomModel: true},
{
ID: "claw402",
DisplayName: "Claw402 (Base USDC)",
DefaultModel: "deepseek",
CredentialLabelZH: "钱包私钥",
CredentialLabelEN: "wallet private key",
SupportsCustomAPIURL: false,
SupportsCustomModel: true,
UsesWalletCredential: true,
Recommended: true,
RecommendedModelHints: []string{"deepseek", "glm-5", "gpt-5.4", "claude-opus", "qwen-max", "grok-4.1"},
},
{
ID: "blockrun-base",
DisplayName: "BlockRun (Base Wallet)",
DefaultModel: "auto",
CredentialLabelZH: "钱包私钥",
CredentialLabelEN: "wallet private key",
SupportsCustomAPIURL: false,
SupportsCustomModel: false,
UsesWalletCredential: true,
},
{
ID: "blockrun-sol",
DisplayName: "BlockRun (Solana Wallet)",
DefaultModel: "auto",
CredentialLabelZH: "钱包私钥",
CredentialLabelEN: "wallet private key",
SupportsCustomAPIURL: false,
SupportsCustomModel: false,
UsesWalletCredential: true,
},
}
}
func modelProviderSpecByID(provider string) (modelProviderSpec, bool) {
provider = strings.ToLower(strings.TrimSpace(provider))
for _, spec := range supportedModelProviders() {
if spec.ID == provider {
return spec, true
}
}
return modelProviderSpec{}, false
}
func supportedModelProviderIDs() []string {
specs := supportedModelProviders()
out := make([]string, 0, len(specs))
for _, spec := range specs {
out = append(out, spec.ID)
}
return out
}
func defaultModelNameForProvider(provider string) string {
spec, ok := modelProviderSpecByID(provider)
if !ok {
return ""
}
return strings.TrimSpace(spec.DefaultModel)
}
func defaultModelConfigName(provider string) string {
spec, ok := modelProviderSpecByID(provider)
if !ok {
provider = strings.TrimSpace(provider)
if provider == "" {
return ""
}
return provider + " AI"
}
return spec.DisplayName
}
func modelProviderSupportsCustomAPIURL(provider string) bool {
spec, ok := modelProviderSpecByID(provider)
return ok && spec.SupportsCustomAPIURL
}
func modelProviderSupportsCustomModel(provider string) bool {
spec, ok := modelProviderSpecByID(provider)
return ok && spec.SupportsCustomModel
}
func modelProviderCredentialLabel(lang, provider string) string {
spec, ok := modelProviderSpecByID(provider)
if !ok {
if lang == "zh" {
return "API Key"
}
return "API key"
}
if lang == "zh" {
return spec.CredentialLabelZH
}
return spec.CredentialLabelEN
}
func modelProviderSummaryList(lang string) string {
parts := make([]string, 0, len(supportedModelProviders()))
for _, spec := range supportedModelProviders() {
if lang == "zh" {
item := fmt.Sprintf("%s默认 %s", spec.ID, spec.DefaultModel)
if spec.Recommended {
item += " [推荐]"
}
parts = append(parts, item)
continue
}
item := fmt.Sprintf("%s (default %s)", spec.ID, spec.DefaultModel)
if spec.Recommended {
item += " [recommended]"
}
parts = append(parts, item)
}
if lang == "zh" {
return strings.Join(parts, "、")
}
return strings.Join(parts, ", ")
}
func modelProviderChoicePrompt(lang string) string {
if lang == "zh" {
return "可选模型 provider" + modelProviderSummaryList(lang) + "。这些 provider 是并列可选的:你可以直接选 `claw402`、DeepSeek / OpenAI / Claude / Gemini / Qwen / Kimi / Grok / MiniMax 这类 API Key provider或者选 `blockrun-base` / `blockrun-sol` 这类钱包 provider。我们优先推荐 `claw402`,因为它按次付费、用 Base USDC 钱包支付、默认配置更省事。对于第一次使用的新手,也可以直接去产品配置页的模型配置里选择 `claw402`:那里支持直接创建 Base 钱包,并且可以直接扫码充值/支付。请先告诉我你想用哪个 provider。"
}
return "Available model providers: " + modelProviderSummaryList(lang) + ". These providers are peer options: you can choose `claw402`, an API-key provider such as DeepSeek / OpenAI / Claude / Gemini / Qwen / Kimi / Grok / MiniMax, or a wallet-based provider such as `blockrun-base` / `blockrun-sol`. We recommend `claw402` first because it is pay-per-use, uses Base USDC wallet payment, and has the simplest default setup. If this is your first time, you can also open the product's model config page, choose `claw402`, create a Base wallet there directly, and pay by scanning the QR/deposit flow. Tell me which provider you want first."
}
func modelProviderDetailedGuidance(lang, provider string) string {
spec, ok := modelProviderSpecByID(provider)
if !ok {
return ""
}
if lang == "zh" {
lines := []string{
fmt.Sprintf("你现在选的是 %s。", spec.DisplayName),
fmt.Sprintf("- 默认模型名:%s", spec.DefaultModel),
fmt.Sprintf("- 凭证类型:%s", spec.CredentialLabelZH),
}
if spec.SupportsCustomModel {
lines = append(lines, "- `custom_model_name` 可选;留空时默认用上面的默认模型。")
} else {
lines = append(lines, "- 这个 provider 不需要单独填写 `custom_model_name`。")
}
if spec.SupportsCustomAPIURL {
lines = append(lines, "- `custom_api_url` 可选;留空时使用官方默认地址。")
} else {
lines = append(lines, "- 这个 provider 不需要 `custom_api_url`。")
}
if len(spec.RecommendedModelHints) > 0 {
lines = append(lines, "- 常见可选模型:"+strings.Join(spec.RecommendedModelHints, "、"))
}
if provider == "claw402" {
lines = append(lines, "- 这是我们优先推荐的 provider按次付费、Base USDC 钱包支付,对新手最省事。")
lines = append(lines, "- 如果你是第一次用,也可以直接去配置页的模型配置里选择 `claw402`,那里支持直接创建 Base 钱包,并可直接扫码充值/支付。")
}
return strings.Join(lines, "\n")
}
lines := []string{
fmt.Sprintf("You selected %s.", spec.DisplayName),
fmt.Sprintf("- Default model: %s", spec.DefaultModel),
fmt.Sprintf("- Credential type: %s", spec.CredentialLabelEN),
}
if spec.SupportsCustomModel {
lines = append(lines, "- `custom_model_name` is optional; if omitted, the default model will be used.")
} else {
lines = append(lines, "- This provider does not need a separate `custom_model_name`.")
}
if spec.SupportsCustomAPIURL {
lines = append(lines, "- `custom_api_url` is optional; if omitted, the official default endpoint will be used.")
} else {
lines = append(lines, "- This provider does not need `custom_api_url`.")
}
if len(spec.RecommendedModelHints) > 0 {
lines = append(lines, "- Common model choices: "+strings.Join(spec.RecommendedModelHints, ", "))
}
if provider == "claw402" {
lines = append(lines, "- This is our recommended provider: pay-per-use, Base USDC wallet payment, and the easiest setup for first-time users.")
lines = append(lines, "- If this is your first time, you can also open the model config page, choose `claw402`, create a Base wallet there directly, and pay through the QR/deposit flow.")
}
return strings.Join(lines, "\n")
}
func modelProviderCredentialGuidance(lang, provider string) string {
spec, ok := modelProviderSpecByID(provider)
if !ok {
return ""
}
provider = strings.TrimSpace(spec.ID)
if lang == "zh" {
switch provider {
case "claw402":
return "claw402 这里要填的是 Base 链 EVM 钱包私钥。\n- 如果你是第一次用,最省事的方式是直接去配置页的模型配置里选择 `claw402`。\n- 那里可以一键快速创建钱包,界面会直接展示新钱包私钥,并且提供 Base USDC 充值入口。\n- 创建后请立刻备份私钥;系统会用它完成 claw402 支付和模型调用。\n- 如果你已经有 MetaMask、Rabby、Coinbase Wallet 这类 Base/EVM 钱包,也可以从钱包里导出现有私钥再发我。"
case "blockrun-base":
return "blockrun-base 这里要填的是 Base 链 EVM 钱包私钥。你可以从现有 EVM 钱包导出私钥后发我。"
case "blockrun-sol":
return "blockrun-sol 这里要填的是 Solana 钱包私钥。你可以从现有 Solana 钱包导出私钥后发我。"
default:
return fmt.Sprintf("%s 这里要填的是 %s。你把完整值发我就行我会继续当前模型草稿。", spec.DisplayName, spec.CredentialLabelZH)
}
}
switch provider {
case "claw402":
return "For claw402, this field expects a Base-chain EVM wallet private key.\n- If this is your first time, the easiest path is to open the model config page and choose `claw402`.\n- That flow can quickly create a wallet for you, show the new private key, and provide a Base USDC deposit path.\n- Back up the key immediately after creation; the system uses it for claw402 payments and model access.\n- If you already use MetaMask, Rabby, or Coinbase Wallet, you can also export an existing Base/EVM wallet private key and send it to me."
case "blockrun-base":
return "For blockrun-base, this field expects a Base-chain EVM wallet private key. You can export it from an existing EVM wallet and send it to me."
case "blockrun-sol":
return "For blockrun-sol, this field expects a Solana wallet private key. You can export it from an existing Solana wallet and send it to me."
default:
return fmt.Sprintf("For %s, this field expects your %s. Send me the full value and I'll continue the current model draft.", spec.DisplayName, spec.CredentialLabelEN)
}
}