From 70b144f1e51056a24c8e8c775567fbff5166389b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9A=E7=AB=A0=E6=B5=A9?= Date: Tue, 22 Sep 2026 16:10:07 +0800 Subject: [PATCH] fix(weknora): drop 120s client total timeout so long agent streams are not cut The weknora HTTP client used a hardcoded 120s total-duration timeout, which kills any smart-reasoning agent stream that legitimately runs longer (22 tool rounds measured in prod) and the failure branch then overwrote the already streamed card with the error text. Pass 0 and keep Go's default (no timeout). --- cmd/dobotai/main.go | 5 ++++- internal/weknora/client.go | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/dobotai/main.go b/cmd/dobotai/main.go index 8d24183..baf825b 100644 --- a/cmd/dobotai/main.go +++ b/cmd/dobotai/main.go @@ -71,7 +71,10 @@ func main() { if strings.TrimSpace(settingsRuntime.clientID) == "" || strings.TrimSpace(settingsRuntime.secret) == "" { log.Fatal("DingTalk credentials are required; configure DINGTALK_CLIENT_ID and DINGTALK_CLIENT_SECRET in the protected runtime environment") } - client, err := weknora.NewClient(os.Getenv("WEKNORA_BASE_URL"), os.Getenv("WEKNORA_API_KEY"), 120*time.Second) + // 0 = no client-side total timeout. WeKnora's smart-reasoning agent can run + // 20+ tool rounds and stream far longer than 120s; the total-time cap cut the + // SSE mid-answer and the failure branch overwrote the streamed card. + client, err := weknora.NewClient(os.Getenv("WEKNORA_BASE_URL"), os.Getenv("WEKNORA_API_KEY"), 0) if err != nil { log.Fatal(err) } diff --git a/internal/weknora/client.go b/internal/weknora/client.go index 7376567..b14ba09 100644 --- a/internal/weknora/client.go +++ b/internal/weknora/client.go @@ -86,9 +86,8 @@ func NewClient(baseURL, apiKey string, timeout time.Duration) (*Client, error) { if strings.TrimSpace(apiKey) == "" { return nil, errors.New("WEKNORA_API_KEY is required") } - if timeout <= 0 { - timeout = 120 * time.Second - } + // timeout <= 0 keeps Go's default: no client-side total timeout on the HTTP + // client, so long-lived agent SSE streams are never cut by a duration cap. return &Client{baseURL: parsed.String(), apiKey: apiKey, http: &http.Client{Timeout: timeout}}, nil }