From af6da309ecfcd6aff36e32f00b889e40cc875114 Mon Sep 17 00:00:00 2001 From: lpf Date: Sat, 14 Feb 2026 11:50:21 +0800 Subject: [PATCH] fix timeout --- config.example.json | 3 ++- pkg/agent/loop.go | 7 ++++--- pkg/config/config.go | 10 ++++++---- pkg/config/validate.go | 3 +++ pkg/providers/http_provider.go | 15 +++++++++------ 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/config.example.json b/config.example.json index 72e86db..14f5279 100644 --- a/config.example.json +++ b/config.example.json @@ -50,7 +50,8 @@ "proxy": { "api_key": "YOUR_CLIPROXYAPI_KEY", "api_base": "http://localhost:8080/v1", - "auth": "bearer" + "auth": "bearer", + "timeout_sec": 90 } }, "tools": { diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 0ef5888..58f1363 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -31,7 +31,6 @@ import ( var errGatewayNotRunningSlash = errors.New("gateway not running") -const llmCallTimeout = 90 * time.Second const perSessionQueueSize = 64 type sessionWorker struct { @@ -53,6 +52,7 @@ type AgentLoop struct { orchestrator *tools.Orchestrator running atomic.Bool compactionCfg config.ContextCompactionConfig + llmCallTimeout time.Duration workersMu sync.Mutex workers map[string]*sessionWorker } @@ -137,6 +137,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers tools: toolsRegistry, orchestrator: orchestrator, compactionCfg: cfg.Agents.Defaults.ContextCompaction, + llmCallTimeout: time.Duration(cfg.Providers.Proxy.TimeoutSec) * time.Second, workers: make(map[string]*sessionWorker), } @@ -561,7 +562,7 @@ func (al *AgentLoop) runLLMToolLoop( }) llmStart := time.Now() - llmCtx, cancelLLM := context.WithTimeout(ctx, llmCallTimeout) + llmCtx, cancelLLM := context.WithTimeout(ctx, al.llmCallTimeout) response, err := al.callLLMWithModelFallback(llmCtx, messages, providerToolDefs, map[string]interface{}{ "max_tokens": 8192, "temperature": 0.7, @@ -680,7 +681,7 @@ func (al *AgentLoop) runLLMToolLoop( }) finalizeMessages = sanitizeMessagesForToolCalling(finalizeMessages) - llmCtx, cancelLLM := context.WithTimeout(ctx, llmCallTimeout) + llmCtx, cancelLLM := context.WithTimeout(ctx, al.llmCallTimeout) finalResp, err := al.callLLMWithModelFallback(llmCtx, finalizeMessages, nil, map[string]interface{}{ "max_tokens": 1024, "temperature": 0.3, diff --git a/pkg/config/config.go b/pkg/config/config.go index eb7f299..07eed03 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -107,9 +107,10 @@ type ProvidersConfig struct { } type ProviderConfig struct { - APIKey string `json:"api_key" env:"CLAWGO_PROVIDERS_{{.Name}}_API_KEY"` - APIBase string `json:"api_base" env:"CLAWGO_PROVIDERS_{{.Name}}_API_BASE"` - Auth string `json:"auth" env:"CLAWGO_PROVIDERS_{{.Name}}_AUTH"` + APIKey string `json:"api_key" env:"CLAWGO_PROVIDERS_{{.Name}}_API_KEY"` + APIBase string `json:"api_base" env:"CLAWGO_PROVIDERS_{{.Name}}_API_BASE"` + Auth string `json:"auth" env:"CLAWGO_PROVIDERS_{{.Name}}_AUTH"` + TimeoutSec int `json:"timeout_sec" env:"CLAWGO_PROVIDERS_PROXY_TIMEOUT_SEC"` } type GatewayConfig struct { @@ -276,7 +277,8 @@ func DefaultConfig() *Config { }, Providers: ProvidersConfig{ Proxy: ProviderConfig{ - APIBase: "http://localhost:8080/v1", + APIBase: "http://localhost:8080/v1", + TimeoutSec: 90, }, }, Gateway: GatewayConfig{ diff --git a/pkg/config/validate.go b/pkg/config/validate.go index ee7acb6..bef09d1 100644 --- a/pkg/config/validate.go +++ b/pkg/config/validate.go @@ -39,6 +39,9 @@ func Validate(cfg *Config) []error { if cfg.Providers.Proxy.APIBase == "" { errs = append(errs, fmt.Errorf("providers.proxy.api_base is required")) } + if cfg.Providers.Proxy.TimeoutSec <= 0 { + errs = append(errs, fmt.Errorf("providers.proxy.timeout_sec must be > 0")) + } if cfg.Gateway.Port <= 0 || cfg.Gateway.Port > 65535 { errs = append(errs, fmt.Errorf("gateway.port must be in 1..65535")) diff --git a/pkg/providers/http_provider.go b/pkg/providers/http_provider.go index a09d4c1..45b9308 100644 --- a/pkg/providers/http_provider.go +++ b/pkg/providers/http_provider.go @@ -24,18 +24,18 @@ type HTTPProvider struct { apiKey string apiBase string authMode string + timeout time.Duration httpClient *http.Client } -const defaultChatTimeout = 90 * time.Second - -func NewHTTPProvider(apiKey, apiBase, authMode string) *HTTPProvider { +func NewHTTPProvider(apiKey, apiBase, authMode string, timeout time.Duration) *HTTPProvider { return &HTTPProvider{ apiKey: apiKey, apiBase: apiBase, authMode: authMode, + timeout: timeout, httpClient: &http.Client{ - Timeout: defaultChatTimeout, + Timeout: timeout, }, } } @@ -50,7 +50,7 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too "model": model, "messages_count": len(messages), "tools_count": len(tools), - "timeout": defaultChatTimeout.String(), + "timeout": p.timeout.String(), }) requestBody := map[string]interface{}{ @@ -208,6 +208,9 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) { if apiBase == "" { return nil, fmt.Errorf("no API base (CLIProxyAPI) configured") } + if cfg.Providers.Proxy.TimeoutSec <= 0 { + return nil, fmt.Errorf("invalid providers.proxy.timeout_sec: %d", cfg.Providers.Proxy.TimeoutSec) + } - return NewHTTPProvider(apiKey, apiBase, authMode), nil + return NewHTTPProvider(apiKey, apiBase, authMode, time.Duration(cfg.Providers.Proxy.TimeoutSec)*time.Second), nil }