mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-04 19:41:02 +08:00
- Add Telegram bot with long-polling and AI agent loop (api_call tool)
- SSE streaming with real-time message editing and ⏳ placeholder
- Account state injection at conversation start (models, exchanges,
strategies, traders, per-trader PnL and statistics)
- Lane semaphore per chat serializes concurrent messages (60s timeout)
- Idle timeout watchdog (60s) prevents hung streaming connections
- Look-ahead buffer prevents partial <api_call> tag leaking to user
- Fix PUT /strategies/:id to merge config (read-then-merge pattern)
- Add route registry with full API schema for LLM documentation
- Add TelegramConfig store and Web UI config modal
- Add GetAnyEnabled to AIModel store for bot LLM client selection
35 lines
1.2 KiB
Go
35 lines
1.2 KiB
Go
package mcp
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// AIClient public AI client interface (for external use)
|
|
type AIClient interface {
|
|
SetAPIKey(apiKey string, customURL string, customModel string)
|
|
SetTimeout(timeout time.Duration)
|
|
CallWithMessages(systemPrompt, userPrompt string) (string, error)
|
|
CallWithRequest(req *Request) (string, error)
|
|
// CallWithRequestStream streams the LLM response via SSE.
|
|
// onChunk is called with the full accumulated text so far (not raw deltas).
|
|
// Returns the complete final text when done.
|
|
CallWithRequestStream(req *Request, onChunk func(string)) (string, error)
|
|
}
|
|
|
|
// clientHooks internal hook interface (for subclass to override specific steps)
|
|
// These methods are only used inside the package to implement dynamic dispatch
|
|
type clientHooks interface {
|
|
// Hook methods that can be overridden by subclass
|
|
|
|
call(systemPrompt, userPrompt string) (string, error)
|
|
|
|
buildMCPRequestBody(systemPrompt, userPrompt string) map[string]any
|
|
buildUrl() string
|
|
buildRequest(url string, jsonData []byte) (*http.Request, error)
|
|
setAuthHeader(reqHeaders http.Header)
|
|
marshalRequestBody(requestBody map[string]any) ([]byte, error)
|
|
parseMCPResponse(body []byte) (string, error)
|
|
isRetryableError(err error) bool
|
|
}
|