diff --git a/open-sse/config/providers/registry/grok-cli/index.ts b/open-sse/config/providers/registry/grok-cli/index.ts index 463e103ba6..85a6a05471 100644 --- a/open-sse/config/providers/registry/grok-cli/index.ts +++ b/open-sse/config/providers/registry/grok-cli/index.ts @@ -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"], }, ], diff --git a/open-sse/executors/grok-cli.ts b/open-sse/executors/grok-cli.ts index ced0ac1465..44d0d6c43a 100644 --- a/open-sse/executors/grok-cli.ts +++ b/open-sse/executors/grok-cli.ts @@ -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; } } diff --git a/tests/unit/grok-cli-strip-params.test.ts b/tests/unit/grok-cli-strip-params.test.ts index 906e02ae42..46c97598f5 100644 --- a/tests/unit/grok-cli-strip-params.test.ts +++ b/tests/unit/grok-cli-strip-params.test.ts @@ -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; + + 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; + + assert.deepEqual(out.tools, tools); +});