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.
This commit is contained in:
robomp-bot
2026-07-09 15:46:53 +09:00
parent 998b6be655
commit ea5503bc53
3 changed files with 15 additions and 7 deletions
+1 -1
View File
@@ -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
@@ -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<string, unknown> {
{ role: "user", content: params.query },
],
tools: [{ type: "web_search" }],
reasoning: { effort: XAI_WEB_SEARCH_REASONING_EFFORT },
};
if (params.maxOutputTokens !== undefined) {
@@ -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 () => {