fix(providers): cap grok-cli tools at 200 for cli-chat-proxy

xAI's cli-chat-proxy enforces a hard limit of 200 tools per request and
returns a 400 above that ceiling. A client fanning a large MCP toolset
through Grok Build/Composer (e.g. Claude Code with many registered
tools) can exceed it. transformRequest() now caps the tools array
defensively before forwarding, and the grok-cli registry entries are
annotated supportsReasoning:false to document the existing (already
unconditional) reasoning_effort/reasoning strip for these two models.

Co-authored-by: Joseph Yaksich <294273268+gitcommit90@users.noreply.github.com>
Inspired-by: https://github.com/decolua/9router/pull/2534
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-07-12 15:58:37 -03:00
parent b4c47f5cbf
commit 28af29fdd2
3 changed files with 53 additions and 0 deletions

View File

@@ -15,12 +15,18 @@ export const grok_cliProvider: RegistryEntry = {
id: "grok-build",
name: "Grok Build",
contextLength: 256000,
// cli-chat-proxy rejects reasoning_effort/reasoning outright (see grok-cli.ts
// executor's transformRequest, which strips them unconditionally for this model).
supportsReasoning: false,
unsupportedParams: ["presencePenalty", "frequencyPenalty", "logprobs", "topLogprobs"],
},
{
id: "grok-composer-2.5-fast",
name: "Grok Composer 2.5 Fast",
contextLength: 200000,
// cli-chat-proxy rejects reasoning_effort/reasoning outright (see grok-cli.ts
// executor's transformRequest, which strips them unconditionally for this model).
supportsReasoning: false,
unsupportedParams: ["presencePenalty", "frequencyPenalty", "logprobs", "topLogprobs"],
},
],

View File

@@ -18,6 +18,8 @@ import https from "node:https";
const GROK_TOKEN_URL = "https://auth.x.ai/oauth2/token";
const REQUEST_TIMEOUT_MS = 60_000;
// xAI cli-chat-proxy hard limit on tools per request.
const MAX_TOOLS = 200;
export class GrokCliExecutor extends BaseExecutor {
constructor() {
@@ -257,6 +259,14 @@ export class GrokCliExecutor extends BaseExecutor {
}
}
// xAI's cli-chat-proxy enforces a maximum of 200 tools per request and
// 400s above that ceiling. Clients that fan a large MCP toolset through
// Grok Build/Composer (e.g. Claude Code with many registered tools) can
// exceed it — cap defensively rather than let the request fail upstream.
if (Array.isArray(transformed.tools) && transformed.tools.length > MAX_TOOLS) {
transformed.tools = transformed.tools.slice(0, MAX_TOOLS);
}
return transformed;
}
}

View File

@@ -51,3 +51,40 @@ test("#5273 grok-cli transformRequest leaves a clean body unchanged (no false st
assert.equal(out.model, "grok-composer-2.5-fast");
assert.equal(out.stream, true);
});
// Ported from decolua/9router#2534 (@gitcommit90): xAI's cli-chat-proxy enforces a
// hard cap of 200 tools per request and 400s above it. Clients that fan a large MCP
// toolset through Grok Build/Composer can exceed that ceiling — transformRequest()
// must cap defensively instead of forwarding an oversized array upstream.
test("2534 grok-cli transformRequest caps tools at 200", () => {
const executor = new GrokCliExecutor();
const tools = Array.from({ length: 250 }, (_, i) => ({
type: "function",
function: { name: `tool_${i}` },
}));
const out = executor.transformRequest(
"grok-build",
{ messages: [{ role: "user", content: "hi" }], tools },
false,
{} as never
) as Record<string, unknown>;
assert.equal((out.tools as unknown[]).length, 200);
assert.deepEqual(out.tools, tools.slice(0, 200));
});
test("2534 grok-cli transformRequest leaves a tools array under the cap untouched", () => {
const executor = new GrokCliExecutor();
const tools = Array.from({ length: 10 }, (_, i) => ({
type: "function",
function: { name: `tool_${i}` },
}));
const out = executor.transformRequest(
"grok-composer-2.5-fast",
{ messages: [{ role: "user", content: "hi" }], tools },
false,
{} as never
) as Record<string, unknown>;
assert.deepEqual(out.tools, tools);
});