From ea5503bc53684ffe38207942c1b5df0074b35b0c Mon Sep 17 00:00:00 2001 From: robomp-bot Date: Thu, 9 Jul 2026 15:46:53 +0900 Subject: [PATCH] fix(coding-agent): pin xAI web search to low reasoning effort Address PR #4890 review: grok-4.5 defaults reasoning.effort to high, but xAI documents low as the tier for latency-sensitive tool calling. buildRequestBody now sets reasoning.effort=low so web search avoids paying for high-reasoning tokens and is less likely to hit the 60s hard timeout. Update the request-body regression tests to defend the new shape. --- packages/coding-agent/CHANGELOG.md | 2 +- .../coding-agent/src/web/search/providers/xai.ts | 6 ++++++ .../coding-agent/test/tools/web-search-xai.test.ts | 14 ++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index aeee3609a..ec477f71b 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -4,7 +4,7 @@ ### Changed -- xAI web search now uses `grok-4.5` instead of `grok-4.3`. +- xAI web search now uses `grok-4.5` (at low reasoning effort) instead of `grok-4.3`. ## [16.3.12] - 2026-07-08 diff --git a/packages/coding-agent/src/web/search/providers/xai.ts b/packages/coding-agent/src/web/search/providers/xai.ts index 438bc4ebf..ecc6daf29 100644 --- a/packages/coding-agent/src/web/search/providers/xai.ts +++ b/packages/coding-agent/src/web/search/providers/xai.ts @@ -9,6 +9,11 @@ import { classifyProviderHttpError, withHardTimeout } from "./utils"; const XAI_RESPONSES_URL = "https://api.x.ai/v1/responses"; const XAI_WEB_SEARCH_MODEL = "grok-4.5"; +// grok-4.5 defaults reasoning.effort to "high"; xAI documents "low" for +// latency-sensitive agentic use and simple tool calling +// (docs.x.ai/developers/model-capabilities/text/reasoning). Web search is +// exactly that and runs under a 60s hard timeout, so pin the search calls low. +const XAI_WEB_SEARCH_REASONING_EFFORT = "low"; const DEFAULT_NUM_RESULTS = 10; const MAX_NUM_RESULTS = 30; @@ -59,6 +64,7 @@ function buildRequestBody(params: SearchParams): Record { { role: "user", content: params.query }, ], tools: [{ type: "web_search" }], + reasoning: { effort: XAI_WEB_SEARCH_REASONING_EFFORT }, }; if (params.maxOutputTokens !== undefined) { diff --git a/packages/coding-agent/test/tools/web-search-xai.test.ts b/packages/coding-agent/test/tools/web-search-xai.test.ts index ad64fcbc9..92a46313c 100644 --- a/packages/coding-agent/test/tools/web-search-xai.test.ts +++ b/packages/coding-agent/test/tools/web-search-xai.test.ts @@ -146,6 +146,7 @@ describe("xAI web search provider", () => { { role: "user", content: "latest xAI web search" }, ], tools: [{ type: "web_search" }], + reasoning: { effort: "low" }, max_output_tokens: 512, temperature: 0.2, }); @@ -336,6 +337,7 @@ describe("xAI web search provider", () => { expect(capture.capturedRequest).not.toBeNull(); const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); + expect(body?.reasoning).toEqual({ effort: "low" }); expect(body).not.toHaveProperty("search_parameters"); }); @@ -357,7 +359,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("rejects deprecated live-search 410 responses without retrying", async () => { @@ -384,7 +386,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequests[0]?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("maps output_text, URL citation annotations, top-level citations, id, model, usage, and auth mode", async () => { @@ -513,7 +515,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("clamps oversized xAI local cap requests to 30 sources and citations", async () => { @@ -539,7 +541,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("caps parsed sources and citations locally without changing Agent Tools request shape", async () => { @@ -607,7 +609,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("uses numSearchResults before limit for the local xAI output cap", async () => { @@ -651,7 +653,7 @@ describe("xAI web search provider", () => { const body = capture.capturedRequest?.body; expect(body?.tools).toEqual([{ type: "web_search" }]); expect(body).not.toHaveProperty("search_parameters"); - expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "tools"]); + expect(Object.keys(body ?? {}).sort()).toEqual(["input", "model", "reasoning", "tools"]); }); it("falls back to output content parts when output_text is absent", async () => {