mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-17 17:34:39 +08:00
feat: add blockRun (x402 USDC) support to all AI model consumers
- telegram/bot.go: add blockrun-base, blockrun-sol, minimax to clientForProvider; fix newLLMClient to prefer TelegramConfig.ModelID over GetDefault; log USDC payment provider usage - debate/engine.go: add blockrun-base, blockrun-sol to InitializeClients - api/strategy.go: add blockrun-base, blockrun-sol to runRealAITest - backtest/ai_client.go: add blockrun-base, blockrun-sol to configureMCPClient
This commit is contained in:
@@ -668,6 +668,12 @@ func (s *Server) runRealAITest(userID, modelID, systemPrompt, userPrompt string)
|
|||||||
case "minimax":
|
case "minimax":
|
||||||
aiClient = mcp.NewMiniMaxClient()
|
aiClient = mcp.NewMiniMaxClient()
|
||||||
aiClient.SetAPIKey(apiKey, model.CustomAPIURL, model.CustomModelName)
|
aiClient.SetAPIKey(apiKey, model.CustomAPIURL, model.CustomModelName)
|
||||||
|
case "blockrun-base":
|
||||||
|
aiClient = mcp.NewBlockRunBaseClient()
|
||||||
|
aiClient.SetAPIKey(apiKey, "", model.CustomModelName)
|
||||||
|
case "blockrun-sol":
|
||||||
|
aiClient = mcp.NewBlockRunSolClient()
|
||||||
|
aiClient.SetAPIKey(apiKey, "", model.CustomModelName)
|
||||||
default:
|
default:
|
||||||
// Use generic client
|
// Use generic client
|
||||||
aiClient = mcp.NewClient()
|
aiClient = mcp.NewClient()
|
||||||
|
|||||||
@@ -78,6 +78,20 @@ func configureMCPClient(cfg BacktestConfig, base mcp.AIClient) (mcp.AIClient, er
|
|||||||
mmC := mcp.NewMiniMaxClientWithOptions()
|
mmC := mcp.NewMiniMaxClientWithOptions()
|
||||||
mmC.(*mcp.MiniMaxClient).SetAPIKey(cfg.AICfg.APIKey, cfg.AICfg.BaseURL, cfg.AICfg.Model)
|
mmC.(*mcp.MiniMaxClient).SetAPIKey(cfg.AICfg.APIKey, cfg.AICfg.BaseURL, cfg.AICfg.Model)
|
||||||
return mmC, nil
|
return mmC, nil
|
||||||
|
case "blockrun-base":
|
||||||
|
if cfg.AICfg.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("blockrun-base provider requires wallet private key")
|
||||||
|
}
|
||||||
|
brBase := mcp.NewBlockRunBaseClient()
|
||||||
|
brBase.SetAPIKey(cfg.AICfg.APIKey, "", cfg.AICfg.Model)
|
||||||
|
return brBase, nil
|
||||||
|
case "blockrun-sol":
|
||||||
|
if cfg.AICfg.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("blockrun-sol provider requires wallet keypair")
|
||||||
|
}
|
||||||
|
brSol := mcp.NewBlockRunSolClient()
|
||||||
|
brSol.SetAPIKey(cfg.AICfg.APIKey, "", cfg.AICfg.Model)
|
||||||
|
return brSol, nil
|
||||||
case "custom":
|
case "custom":
|
||||||
if cfg.AICfg.BaseURL == "" || cfg.AICfg.APIKey == "" || cfg.AICfg.Model == "" {
|
if cfg.AICfg.BaseURL == "" || cfg.AICfg.APIKey == "" || cfg.AICfg.Model == "" {
|
||||||
return nil, fmt.Errorf("custom provider requires base_url, api key and model")
|
return nil, fmt.Errorf("custom provider requires base_url, api key and model")
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ func (e *DebateEngine) InitializeClients(participants []*store.DebateParticipant
|
|||||||
client = mcp.NewKimiClient()
|
client = mcp.NewKimiClient()
|
||||||
case "minimax":
|
case "minimax":
|
||||||
client = mcp.NewMiniMaxClient()
|
client = mcp.NewMiniMaxClient()
|
||||||
|
case "blockrun-base":
|
||||||
|
client = mcp.NewBlockRunBaseClient()
|
||||||
|
case "blockrun-sol":
|
||||||
|
client = mcp.NewBlockRunSolClient()
|
||||||
default:
|
default:
|
||||||
client = mcp.New()
|
client = mcp.New()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,15 +266,39 @@ func sendMarkdownMsg(bot *tgbotapi.BotAPI, chatID int64, text string) {
|
|||||||
// ── LLM client ───────────────────────────────────────────────────────────────
|
// ── LLM client ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func newLLMClient(st *store.Store, userID string) mcp.AIClient {
|
func newLLMClient(st *store.Store, userID string) mcp.AIClient {
|
||||||
|
// 1. Prefer the model explicitly configured for Telegram (Settings → Telegram → AI Model)
|
||||||
|
if tgCfg, err := st.TelegramConfig().Get(); err == nil && tgCfg.ModelID != "" {
|
||||||
|
if model, err := st.AIModel().Get(userID, tgCfg.ModelID); err == nil && model.Enabled {
|
||||||
|
apiKey := string(model.APIKey)
|
||||||
|
if apiKey != "" {
|
||||||
|
client := clientForProvider(model.Provider)
|
||||||
|
client.SetAPIKey(apiKey, model.CustomAPIURL, model.CustomModelName)
|
||||||
|
if isUSDCProvider(model.Provider) {
|
||||||
|
logger.Infof("Telegram agent: provider=%s (USDC payment) user=%s", model.Provider, userID)
|
||||||
|
} else {
|
||||||
|
logger.Infof("Telegram agent: provider=%s user=%s", model.Provider, userID)
|
||||||
|
}
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fall back to first enabled model
|
||||||
if model, err := st.AIModel().GetDefault(userID); err == nil {
|
if model, err := st.AIModel().GetDefault(userID); err == nil {
|
||||||
apiKey := string(model.APIKey)
|
apiKey := string(model.APIKey)
|
||||||
if apiKey != "" {
|
if apiKey != "" {
|
||||||
client := clientForProvider(model.Provider)
|
client := clientForProvider(model.Provider)
|
||||||
client.SetAPIKey(apiKey, model.CustomAPIURL, model.CustomModelName)
|
client.SetAPIKey(apiKey, model.CustomAPIURL, model.CustomModelName)
|
||||||
logger.Infof("Telegram agent: provider=%s user=%s", model.Provider, userID)
|
if isUSDCProvider(model.Provider) {
|
||||||
|
logger.Infof("Telegram agent: provider=%s (USDC payment) user=%s", model.Provider, userID)
|
||||||
|
} else {
|
||||||
|
logger.Infof("Telegram agent: provider=%s user=%s", model.Provider, userID)
|
||||||
|
}
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Environment variable fallback
|
||||||
for _, pair := range []struct{ provider, key, url string }{
|
for _, pair := range []struct{ provider, key, url string }{
|
||||||
{"deepseek", os.Getenv("DEEPSEEK_API_KEY"), mcp.DefaultDeepSeekBaseURL},
|
{"deepseek", os.Getenv("DEEPSEEK_API_KEY"), mcp.DefaultDeepSeekBaseURL},
|
||||||
{"openai", os.Getenv("OPENAI_API_KEY"), ""},
|
{"openai", os.Getenv("OPENAI_API_KEY"), ""},
|
||||||
@@ -289,6 +313,11 @@ func newLLMClient(st *store.Store, userID string) mcp.AIClient {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isUSDCProvider returns true for providers that pay per call with USDC (x402 protocol).
|
||||||
|
func isUSDCProvider(provider string) bool {
|
||||||
|
return provider == "blockrun-base" || provider == "blockrun-sol"
|
||||||
|
}
|
||||||
|
|
||||||
func clientForProvider(provider string) mcp.AIClient {
|
func clientForProvider(provider string) mcp.AIClient {
|
||||||
switch provider {
|
switch provider {
|
||||||
case "openai":
|
case "openai":
|
||||||
@@ -305,6 +334,12 @@ func clientForProvider(provider string) mcp.AIClient {
|
|||||||
return mcp.NewGrokClient()
|
return mcp.NewGrokClient()
|
||||||
case "gemini":
|
case "gemini":
|
||||||
return mcp.NewGeminiClient()
|
return mcp.NewGeminiClient()
|
||||||
|
case "minimax":
|
||||||
|
return mcp.NewMiniMaxClient()
|
||||||
|
case "blockrun-base":
|
||||||
|
return mcp.NewBlockRunBaseClient()
|
||||||
|
case "blockrun-sol":
|
||||||
|
return mcp.NewBlockRunSolClient()
|
||||||
default:
|
default:
|
||||||
return mcp.NewDeepSeekClient()
|
return mcp.NewDeepSeekClient()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user