fix: context propagation in LLM calls, SSE error handling, security hardening

- Propagate request context through MCP client (Request.Ctx field)
  — Client disconnects now cancel in-flight LLM API calls (both streaming and non-streaming)
  — Prevents wasted LLM tokens when user navigates away mid-response
- proxyBinance: use http.NewRequestWithContext for context-aware upstream calls
  — Client disconnects cancel Binance proxy requests
  — Distinguishes client cancellation from upstream failures
- Fix SSE parse bug in AgentChatPage: catch block was swallowing error events
  — throw new Error(data) for 'error' events was caught by the same try/catch
  — Now parse JSON separately, then handle events outside try/catch
- Add io.LimitReader to Hyperliquid coins.go JSON decoder (4MB limit)
- Use safe.ReadAllLimited in batch ticker handler for consistency
- Sanitize URL validation error in handler_ai_model.go (was leaking raw error)
- Cache agent tool definitions (built once, reused per message)
- Sort trade history by exit time for consistent ordering
This commit is contained in:
shinchan-zhai
2026-03-23 15:37:36 +08:00
parent 4c73a7960d
commit 3f1dd71f2b
8 changed files with 189 additions and 77 deletions

View File

@@ -4,14 +4,20 @@ import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"nofx/mcp"
)
// agentTools defines the tools available to the LLM for autonomous action.
func agentTools() []mcp.Tool {
// cachedTools holds the static tool definitions (built once, reused per message).
var cachedTools = buildAgentTools()
// agentTools returns the tools available to the LLM for autonomous action.
func agentTools() []mcp.Tool { return cachedTools }
func buildAgentTools() []mcp.Tool {
return []mcp.Tool{
{
Type: "function",
@@ -423,6 +429,13 @@ func (a *Agent) toolGetTradeHistory(argsJSON string) string {
return `{"trades": [], "message": "no closed trades found"}`
}
// Sort trades by exit time (most recent first) for consistent ordering across traders
sort.Slice(trades, func(i, j int) bool {
ti, _ := trades[i]["exit_time"].(string)
tj, _ := trades[j]["exit_time"].(string)
return ti > tj // reverse chronological
})
// Only return up to the limit
if len(trades) > args.Limit {
trades = trades[:args.Limit]