Files
nofx/agent/router.go
shinchan-zhai 27498b8ec9 feat: NOFXi Agent integrated into NOFX core
This is the key architectural change: NOFXi is no longer a separate
sub-project in nofxi/, but a first-class module in agent/ that sits
on top of NOFX's existing engine.

agent/ package:
- agent.go: Core orchestrator, directly uses NOFX's TraderManager,
  Store, and Market packages. No wrapper/bridge needed.
- brain.go: Proactive intelligence (news scan, market briefs, signal handling)
- sentinel.go: Market anomaly detection (price breakout, volume spike, funding rate)
- scheduler.go: Daily reports, position risk checks
- router.go: Intent routing for natural language (中/英 bilingual)
- i18n.go: Full Chinese/English message catalog
- web.go: Agent REST API on :8900 (chat, klines, ticker)

main.go changes:
- Banner: NOFX → NOFXi
- Agent auto-starts with NOFX (sentinel + brain + scheduler + web)
- Zero breaking changes to existing NOFX functionality

Key difference from old nofxi/:
- Agent reads LIVE data from TraderManager (positions, balances, status)
- Uses market.Get() for full technical indicators (EMA/MACD/RSI/BB)
- No duplicate code — kernel, trader, store all used directly
- Old nofxi/ sub-project will be removed once migration is verified

Architecture:
  NOFX (engine) → kernel + trader + market + store + mcp + telegram
  NOFXi (brain) → agent/ package → uses all of the above
2026-03-22 23:26:55 +08:00

103 lines
2.6 KiB
Go

package agent
import (
"regexp"
"strings"
)
type IntentType int
const (
IntentChat IntentType = iota
IntentTrade
IntentQuery
IntentAnalyze
IntentSettings
IntentHelp
IntentStatus
IntentWatch
IntentStrategy
)
type Intent struct {
Type IntentType
Params map[string]string
Raw string
}
type Router struct {
tradePatterns []*regexp.Regexp
queryPatterns []*regexp.Regexp
analyzePatterns []*regexp.Regexp
}
func NewRouter() *Router {
return &Router{
tradePatterns: []*regexp.Regexp{
regexp.MustCompile(`(?i)(buy|sell|long|short|open|close)\s+(.+)`),
regexp.MustCompile(`(?i)(做多|做空|买入|卖出|开仓|平仓)\s*(.+)`),
},
queryPatterns: []*regexp.Regexp{
regexp.MustCompile(`(?i)(position|balance|pnl|profit|loss|持仓|余额|盈亏|trader|交易员)`),
},
analyzePatterns: []*regexp.Regexp{
regexp.MustCompile(`(?i)(analyze|analysis|分析|看看)\s+(.+)`),
regexp.MustCompile(`(?i)(what.*think|怎么看|你觉得)\s*(.+)?`),
},
}
}
func (r *Router) Route(text string) Intent {
text = strings.TrimSpace(text)
if strings.HasPrefix(text, "/") {
return r.routeCommand(text)
}
for _, p := range r.tradePatterns {
if m := p.FindStringSubmatch(text); m != nil {
return Intent{Type: IntentTrade, Params: map[string]string{"action": strings.ToLower(m[1]), "detail": m[2]}, Raw: text}
}
}
for _, p := range r.queryPatterns {
if p.MatchString(text) {
return Intent{Type: IntentQuery, Raw: text}
}
}
for _, p := range r.analyzePatterns {
if m := p.FindStringSubmatch(text); m != nil {
d := ""
if len(m) > 2 { d = m[2] }
return Intent{Type: IntentAnalyze, Params: map[string]string{"detail": d}, Raw: text}
}
}
return Intent{Type: IntentChat, Raw: text}
}
func (r *Router) routeCommand(text string) Intent {
cmd := strings.ToLower(strings.Fields(text)[0])
parts := strings.SplitN(text, " ", 2)
detail := ""
if len(parts) > 1 { detail = parts[1] }
switch cmd {
case "/start", "/help":
return Intent{Type: IntentHelp, Raw: text}
case "/status":
return Intent{Type: IntentStatus, Raw: text}
case "/buy", "/sell", "/long", "/short", "/open", "/close":
return Intent{Type: IntentTrade, Params: map[string]string{"action": strings.TrimPrefix(cmd, "/"), "detail": detail}, Raw: text}
case "/positions", "/balance", "/pnl", "/traders":
return Intent{Type: IntentQuery, Raw: text}
case "/analyze":
return Intent{Type: IntentAnalyze, Params: map[string]string{"detail": detail}, Raw: text}
case "/watch", "/unwatch":
return Intent{Type: IntentWatch, Raw: text}
case "/strategy":
return Intent{Type: IntentStrategy, Raw: text}
default:
return Intent{Type: IntentChat, Raw: text}
}
}