feat: Add Telegram AI Assistant (moltbot-nofx integration)

- Add assistant package with AI Agent runtime
  - agent.go: Core agent loop with tool calling
  - session.go: Conversation memory management
  - tool.go: Tool interface and base implementation
  - trading_tools.go: Trading-specific tools (13 tools)
  - prompts.go: Trading expert system prompts (EN/ZH)

- Add telegram package for Telegram bot integration
  - bot.go: Telegram bot with rate limiting & access control
  - config.go: Environment-based configuration

- Update main.go to initialize Telegram bot on startup
- Update .env.example with new configuration options
- Add gopkg.in/telebot.v3 dependency

Trading tools available:
- Query: get_balance, get_positions, list_traders, get_trader_status
- Control: start_trader, stop_trader
- Trading: get_market_price, open_long, open_short, close_position
- Config: list_strategies, list_exchanges, list_ai_models
This commit is contained in:
tinklefund
2026-01-30 03:29:22 +08:00
parent 9dbc861cdf
commit 01ba348841
12 changed files with 2668 additions and 36 deletions

91
main.go
View File

@@ -2,6 +2,7 @@ package main
import (
"nofx/api"
"nofx/assistant"
"nofx/auth"
"nofx/backtest"
"nofx/config"
@@ -11,6 +12,7 @@ import (
"nofx/manager"
"nofx/mcp"
"nofx/store"
"nofx/telegram"
"os"
"os/signal"
"path/filepath"
@@ -136,6 +138,41 @@ func main() {
}
}()
// Initialize and start Telegram bot (if configured)
var telegramBot *telegram.Bot
telegramConfig := telegram.LoadConfigFromEnv()
if telegramConfig.Token != "" {
logger.Info("🤖 Initializing Telegram AI Assistant...")
// Create AI client for the assistant
aiClient := createAssistantAIClient()
// Create AI Agent with trading tools
agentConfig := assistant.DefaultAgentConfig()
agent := assistant.NewAgent(aiClient, agentConfig)
// Register trading tools
tradingTools := assistant.NewTradingTools(traderManager, st)
agent.RegisterTools(tradingTools.GetAllTools()...)
// Set system prompt based on language
if telegramConfig.DefaultLanguage == "zh" {
agent.SetSystemPrompt(assistant.ChineseSystemPrompt())
}
// Create and start Telegram bot
var err error
telegramBot, err = telegram.NewBot(telegramConfig, agent)
if err != nil {
logger.Errorf("❌ Failed to create Telegram bot: %v", err)
} else {
go telegramBot.Start()
logger.Info("✅ Telegram AI Assistant started successfully")
}
} else {
logger.Info(" Telegram bot not configured (set TELEGRAM_BOT_TOKEN to enable)")
}
// Wait for interrupt signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
@@ -146,6 +183,11 @@ func main() {
<-quit
logger.Info("📴 Shutdown signal received, closing system...")
// Stop Telegram bot
if telegramBot != nil {
telegramBot.Stop()
}
// Stop all traders
traderManager.StopAll()
logger.Info("✅ System shut down safely")
@@ -161,6 +203,55 @@ func newSharedMCPClient() mcp.AIClient {
return mcp.NewDeepSeekClient()
}
// createAssistantAIClient creates an AI client for the Telegram assistant
// Supports multiple providers based on environment configuration
func createAssistantAIClient() mcp.AIClient {
// Try different providers in order of preference
// 1. DeepSeek (cost-effective, recommended)
if apiKey := os.Getenv("DEEPSEEK_API_KEY"); apiKey != "" {
client := mcp.NewDeepSeekClient()
customURL := os.Getenv("DEEPSEEK_API_URL")
customModel := os.Getenv("DEEPSEEK_MODEL")
client.SetAPIKey(apiKey, customURL, customModel)
logger.Info("🧠 Assistant using DeepSeek AI")
return client
}
// 2. Claude
if apiKey := os.Getenv("CLAUDE_API_KEY"); apiKey != "" {
client := mcp.NewClaudeClient()
customURL := os.Getenv("CLAUDE_API_URL")
customModel := os.Getenv("CLAUDE_MODEL")
client.SetAPIKey(apiKey, customURL, customModel)
logger.Info("🧠 Assistant using Claude AI")
return client
}
// 3. OpenAI
if apiKey := os.Getenv("OPENAI_API_KEY"); apiKey != "" {
client := mcp.NewOpenAIClient()
customURL := os.Getenv("OPENAI_API_URL")
customModel := os.Getenv("OPENAI_MODEL")
client.SetAPIKey(apiKey, customURL, customModel)
logger.Info("🧠 Assistant using OpenAI")
return client
}
// 4. Qwen
if apiKey := os.Getenv("QWEN_API_KEY"); apiKey != "" {
client := mcp.NewQwenClient()
customURL := os.Getenv("QWEN_API_URL")
customModel := os.Getenv("QWEN_MODEL")
client.SetAPIKey(apiKey, customURL, customModel)
logger.Info("🧠 Assistant using Qwen AI")
return client
}
logger.Warn("⚠️ No AI API key configured for assistant")
return nil
}
// initInstallationID initializes the anonymous installation ID for experience improvement
// This ID is persisted in database and used for anonymous usage statistics
func initInstallationID(st *store.Store) {