feat: real SSE streaming for agent chat + data cleanup on startup

SSE Streaming:
- Add POST /api/agent/chat/stream endpoint with real SSE streaming
- Agent.HandleMessageStream() streams final LLM response via onEvent callback
- Tool-calling rounds use non-streaming; tool status sent as 'tool' events
- Frontend uses ReadableStream API instead of fake word-by-word setTimeout
- SSE events: tool (tool execution), delta (text chunk), done (complete), error

Data Maintenance:
- Add cleanupOldData() on server startup (decisions >90d, equity >180d)
- Add CleanOldRecords to DecisionStore and EquityStore
- Add store-level logger for cleanup operations

Exchange Traders:
- Add GetAccountInfo() to Bitget, Bybit, Indodax, KuCoin, Lighter, OKX traders
- Remove unused imports in Aster/Lighter traders
This commit is contained in:
shinchan-zhai
2026-03-23 13:31:09 +08:00
parent 5fc826b4e0
commit bd3d532239
18 changed files with 422 additions and 43 deletions

View File

@@ -87,6 +87,8 @@ func Init(cfg *Config) error {
// Setup log file output (write to both stdout and file)
logDir := "data"
if err := os.MkdirAll(logDir, 0755); err == nil {
// Clean up logs older than 30 days on startup
cleanOldLogs(logDir, 30)
logFileName := filepath.Join(logDir, fmt.Sprintf("nofx_%s.log", time.Now().Format("2006-01-02")))
f, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err == nil {
@@ -111,6 +113,38 @@ func InitWithSimpleConfig(level string) error {
return Init(&Config{Level: level})
}
// cleanOldLogs removes log files older than maxAge days from the log directory.
// Called automatically during Init to prevent unbounded disk usage.
func cleanOldLogs(logDir string, maxAgeDays int) {
cutoff := time.Now().AddDate(0, 0, -maxAgeDays)
entries, err := os.ReadDir(logDir)
if err != nil {
return
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
// Match nofx_YYYY-MM-DD.log pattern
if !strings.HasPrefix(name, "nofx_") || !strings.HasSuffix(name, ".log") {
continue
}
dateStr := strings.TrimPrefix(name, "nofx_")
dateStr = strings.TrimSuffix(dateStr, ".log")
t, err := time.Parse("2006-01-02", dateStr)
if err != nil {
continue
}
if t.Before(cutoff) {
path := filepath.Join(logDir, name)
if removeErr := os.Remove(path); removeErr == nil {
fmt.Printf("[logger] cleaned old log: %s\n", name)
}
}
}
}
// Shutdown gracefully shuts down the logger
func Shutdown() {
if logFile != nil {