From 8764b1b6030675616d3662590a6f9f9edd048ef8 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 11:57:12 +1100 Subject: [PATCH 1/5] fix(grok): failed Grok text generation shows Grok's error message Co-Authored-By: Claude Opus 5.5 --- .../testFixtures/grok-text-mock-agent.mjs | 8 +++++++ .../textGeneration/GrokTextGeneration.test.ts | 22 +++++++++++++++++++ .../src/server/textGeneration.ts | 7 ++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs b/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs index 357bdb7fe564d..baed6bde814c8 100644 --- a/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs +++ b/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs @@ -12,6 +12,14 @@ for await (const line of NodeReadline.createInterface({ input: process.stdin })) NodeFS.appendFileSync(process.env.T3_ACP_REQUEST_LOG_PATH, `${line}\n`); } if (request.id === undefined) continue; + if (request.method === "session/prompt" && process.env.T3_ACP_PROMPT_ERROR_MESSAGE) { + write({ + jsonrpc: "2.0", + id: request.id, + error: { code: -32003, message: process.env.T3_ACP_PROMPT_ERROR_MESSAGE }, + }); + continue; + } let result; switch (request.method) { case "initialize": diff --git a/apps/server/src/textGeneration/GrokTextGeneration.test.ts b/apps/server/src/textGeneration/GrokTextGeneration.test.ts index 26ab9e79c7103..5244cdf54ecac 100644 --- a/apps/server/src/textGeneration/GrokTextGeneration.test.ts +++ b/apps/server/src/textGeneration/GrokTextGeneration.test.ts @@ -133,4 +133,26 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { }), ), ); + + it.effect("keeps Grok's error message when the prompt request fails", () => + withFakeAcpGrok( + { T3_ACP_PROMPT_ERROR_MESSAGE: "Grok usage limit reached. Try again later." }, + (textGeneration) => + Effect.gen(function* () { + const error = yield* textGeneration + .generateThreadTitle({ + cwd: process.cwd(), + message: "the lint job is red", + modelSelection: createModelSelection( + ProviderInstanceId.make("grok"), + "grok-mock-alt", + ), + }) + .pipe(Effect.flip); + expect(error.detail).toBe( + "Grok ACP request failed: Grok usage limit reached. Try again later.", + ); + }), + ), + ); }); diff --git a/packages/provider-grok/src/server/textGeneration.ts b/packages/provider-grok/src/server/textGeneration.ts index 61a6b2d482f53..ff6fd1f263781 100644 --- a/packages/provider-grok/src/server/textGeneration.ts +++ b/packages/provider-grok/src/server/textGeneration.ts @@ -4,7 +4,7 @@ import * as Option from "effect/Option"; import * as Ref from "effect/Ref"; import * as Schema from "effect/Schema"; import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"; -import type * as EffectAcpErrors from "effect-acp/errors"; +import * as EffectAcpErrors from "effect-acp/errors"; import { TextGenerationError } from "@t3tools/contracts"; import type { GrokSettings } from "../settings.ts"; @@ -22,6 +22,7 @@ import { const GROK_TIMEOUT_MS = 180_000; const isTextGenerationError = Schema.is(TextGenerationError); +const isAcpRequestError = Schema.is(EffectAcpErrors.AcpRequestError); export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* ( grokSettings: GrokSettings, @@ -98,7 +99,9 @@ export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(functi ? cause : new TextGenerationError({ operation, - detail: "Grok ACP request failed.", + detail: isAcpRequestError(cause) + ? `Grok ACP request failed: ${cause.errorMessage}` + : "Grok ACP request failed.", cause, }), ), From 36464020efa626b3f33b7f88985ef4e446cd38e8 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 12:22:52 +1100 Subject: [PATCH 2/5] fix(grok): failed Grok model switch in text generation shows Grok's error message Co-Authored-By: Claude Opus 5.5 --- .../textGeneration/GrokTextGeneration.test.ts | 20 +++++++++++++++++++ .../src/server/textGeneration.ts | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/server/src/textGeneration/GrokTextGeneration.test.ts b/apps/server/src/textGeneration/GrokTextGeneration.test.ts index 5244cdf54ecac..964919f851004 100644 --- a/apps/server/src/textGeneration/GrokTextGeneration.test.ts +++ b/apps/server/src/textGeneration/GrokTextGeneration.test.ts @@ -155,4 +155,24 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { }), ), ); + + it.effect("keeps Grok's error message when switching models fails", () => + withFakeAcpGrok({}, (textGeneration) => + Effect.gen(function* () { + const error = yield* textGeneration + .generateThreadTitle({ + cwd: process.cwd(), + message: "the lint job is red", + modelSelection: createModelSelection( + ProviderInstanceId.make("grok"), + "grok-mock-missing", + ), + }) + .pipe(Effect.flip); + expect(error.detail).toBe( + "Failed to set Grok ACP base model for text generation: Unknown Grok model", + ); + }), + ), + ); }); diff --git a/packages/provider-grok/src/server/textGeneration.ts b/packages/provider-grok/src/server/textGeneration.ts index ff6fd1f263781..425477e195b79 100644 --- a/packages/provider-grok/src/server/textGeneration.ts +++ b/packages/provider-grok/src/server/textGeneration.ts @@ -76,7 +76,9 @@ export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(functi mapError: (cause) => new TextGenerationError({ operation, - detail: "Failed to set Grok ACP base model for text generation.", + detail: isAcpRequestError(cause) + ? `Failed to set Grok ACP base model for text generation: ${cause.errorMessage}` + : "Failed to set Grok ACP base model for text generation.", cause, }), }); From 46140b2769bb312d0c9fdddf2a6b5fe3f92e9fee Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Tue, 3 Nov 2026 01:51:09 +0000 Subject: [PATCH 3/5] fix(grok): map text generation failures to safe details --- .../testFixtures/grok-text-mock-agent.mjs | 5 +- .../textGeneration/GrokTextGeneration.test.ts | 60 +++++++++++-------- .../src/server/textGeneration.ts | 27 +++++++-- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs b/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs index baed6bde814c8..b3c6e49ec6b4c 100644 --- a/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs +++ b/apps/server/src/provider/testFixtures/grok-text-mock-agent.mjs @@ -16,7 +16,10 @@ for await (const line of NodeReadline.createInterface({ input: process.stdin })) write({ jsonrpc: "2.0", id: request.id, - error: { code: -32003, message: process.env.T3_ACP_PROMPT_ERROR_MESSAGE }, + error: { + code: Number(process.env.T3_ACP_PROMPT_ERROR_CODE ?? -32003), + message: process.env.T3_ACP_PROMPT_ERROR_MESSAGE, + }, }); continue; } diff --git a/apps/server/src/textGeneration/GrokTextGeneration.test.ts b/apps/server/src/textGeneration/GrokTextGeneration.test.ts index 964919f851004..68d5b33e164bd 100644 --- a/apps/server/src/textGeneration/GrokTextGeneration.test.ts +++ b/apps/server/src/textGeneration/GrokTextGeneration.test.ts @@ -134,29 +134,42 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { ), ); - it.effect("keeps Grok's error message when the prompt request fails", () => - withFakeAcpGrok( - { T3_ACP_PROMPT_ERROR_MESSAGE: "Grok usage limit reached. Try again later." }, - (textGeneration) => - Effect.gen(function* () { - const error = yield* textGeneration - .generateThreadTitle({ - cwd: process.cwd(), - message: "the lint job is red", - modelSelection: createModelSelection( - ProviderInstanceId.make("grok"), - "grok-mock-alt", - ), - }) - .pipe(Effect.flip); - expect(error.detail).toBe( - "Grok ACP request failed: Grok usage limit reached. Try again later.", - ); - }), - ), + it.effect("maps ACP failures to safe details and preserves their cause", () => + Effect.gen(function* () { + for (const [code, detail] of [ + [-32003, "Grok usage limit reached. Try again later."], + [-32000, "Grok authentication is required."], + [-32603, "Grok ACP request failed."], + ] as const) { + yield* withFakeAcpGrok( + { + T3_ACP_PROMPT_ERROR_MESSAGE: "private provider payload " + "x".repeat(4096), + T3_ACP_PROMPT_ERROR_CODE: String(code), + }, + (textGeneration) => + Effect.gen(function* () { + const error = yield* textGeneration + .generateThreadTitle({ + cwd: process.cwd(), + message: "the lint job is red", + modelSelection: createModelSelection( + ProviderInstanceId.make("grok"), + "grok-mock-alt", + ), + }) + .pipe(Effect.flip); + expect(error.detail).toBe(detail); + expect(error.cause).toMatchObject({ + code, + errorMessage: "private provider payload " + "x".repeat(4096), + }); + }), + ); + } + }), ); - it.effect("keeps Grok's error message when switching models fails", () => + it.effect("explains rejected model settings without copying provider text", () => withFakeAcpGrok({}, (textGeneration) => Effect.gen(function* () { const error = yield* textGeneration @@ -169,9 +182,8 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { ), }) .pipe(Effect.flip); - expect(error.detail).toBe( - "Failed to set Grok ACP base model for text generation: Unknown Grok model", - ); + expect(error.cause).toMatchObject({ code: -32602, errorMessage: "Unknown Grok model" }); + expect(error.detail).toBe("Grok rejected the text generation model settings."); }), ), ); diff --git a/packages/provider-grok/src/server/textGeneration.ts b/packages/provider-grok/src/server/textGeneration.ts index 425477e195b79..b609bf358e48a 100644 --- a/packages/provider-grok/src/server/textGeneration.ts +++ b/packages/provider-grok/src/server/textGeneration.ts @@ -19,11 +19,27 @@ import { resolveGrokAcpBaseModelId, } from "./acpSupport.ts"; +import { xAiRateLimitedErrorCode } from "./xaiAcpExtension.ts"; + const GROK_TIMEOUT_MS = 180_000; const isTextGenerationError = Schema.is(TextGenerationError); const isAcpRequestError = Schema.is(EffectAcpErrors.AcpRequestError); +function grokAcpFailureDetail(cause: EffectAcpErrors.AcpError, fallback: string) { + if (!isAcpRequestError(cause)) return fallback; + switch (cause.code) { + case xAiRateLimitedErrorCode: + return "Grok usage limit reached. Try again later."; + case -32000: + return "Grok authentication is required."; + case -32602: + return "Grok rejected the text generation model settings."; + default: + return fallback; + } +} + export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* ( grokSettings: GrokSettings, environment: NodeJS.ProcessEnv = process.env, @@ -76,9 +92,10 @@ export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(functi mapError: (cause) => new TextGenerationError({ operation, - detail: isAcpRequestError(cause) - ? `Failed to set Grok ACP base model for text generation: ${cause.errorMessage}` - : "Failed to set Grok ACP base model for text generation.", + detail: grokAcpFailureDetail( + cause, + "Failed to set Grok ACP base model for text generation.", + ), cause, }), }); @@ -101,9 +118,7 @@ export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(functi ? cause : new TextGenerationError({ operation, - detail: isAcpRequestError(cause) - ? `Grok ACP request failed: ${cause.errorMessage}` - : "Grok ACP request failed.", + detail: grokAcpFailureDetail(cause, "Grok ACP request failed."), cause, }), ), From 64489be17373095b7844e1e9afeedf7c12c52951 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Tue, 3 Nov 2026 02:00:53 +0000 Subject: [PATCH 4/5] fix(grok): scope invalid model errors to model selection --- apps/server/src/textGeneration/GrokTextGeneration.test.ts | 1 + packages/provider-grok/src/server/textGeneration.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/server/src/textGeneration/GrokTextGeneration.test.ts b/apps/server/src/textGeneration/GrokTextGeneration.test.ts index 68d5b33e164bd..aa95b81a23f57 100644 --- a/apps/server/src/textGeneration/GrokTextGeneration.test.ts +++ b/apps/server/src/textGeneration/GrokTextGeneration.test.ts @@ -140,6 +140,7 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { [-32003, "Grok usage limit reached. Try again later."], [-32000, "Grok authentication is required."], [-32603, "Grok ACP request failed."], + [-32602, "Grok ACP request failed."], ] as const) { yield* withFakeAcpGrok( { diff --git a/packages/provider-grok/src/server/textGeneration.ts b/packages/provider-grok/src/server/textGeneration.ts index b609bf358e48a..cd24b0284bdfc 100644 --- a/packages/provider-grok/src/server/textGeneration.ts +++ b/packages/provider-grok/src/server/textGeneration.ts @@ -33,8 +33,6 @@ function grokAcpFailureDetail(cause: EffectAcpErrors.AcpError, fallback: string) return "Grok usage limit reached. Try again later."; case -32000: return "Grok authentication is required."; - case -32602: - return "Grok rejected the text generation model settings."; default: return fallback; } @@ -94,7 +92,9 @@ export const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(functi operation, detail: grokAcpFailureDetail( cause, - "Failed to set Grok ACP base model for text generation.", + isAcpRequestError(cause) && cause.code === -32602 + ? "Grok rejected the text generation model settings." + : "Failed to set Grok ACP base model for text generation.", ), cause, }), From 879b7595e88b4bc04d9a8a990fdfdc64ef6dd1b4 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sat, 14 Nov 2026 15:09:10 +0000 Subject: [PATCH 5/5] test(grok): trim text generation failure cases Co-Authored-By: Claude Opus 5.5 --- apps/server/src/textGeneration/GrokTextGeneration.test.ts | 5 ++--- packages/provider-grok/src/server/textGeneration.ts | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/server/src/textGeneration/GrokTextGeneration.test.ts b/apps/server/src/textGeneration/GrokTextGeneration.test.ts index aa95b81a23f57..f91a06c627827 100644 --- a/apps/server/src/textGeneration/GrokTextGeneration.test.ts +++ b/apps/server/src/textGeneration/GrokTextGeneration.test.ts @@ -139,12 +139,11 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { for (const [code, detail] of [ [-32003, "Grok usage limit reached. Try again later."], [-32000, "Grok authentication is required."], - [-32603, "Grok ACP request failed."], [-32602, "Grok ACP request failed."], ] as const) { yield* withFakeAcpGrok( { - T3_ACP_PROMPT_ERROR_MESSAGE: "private provider payload " + "x".repeat(4096), + T3_ACP_PROMPT_ERROR_MESSAGE: "private provider payload", T3_ACP_PROMPT_ERROR_CODE: String(code), }, (textGeneration) => @@ -162,7 +161,7 @@ it.layer(layerGrokTextGenerationTest)("GrokTextGeneration", (it) => { expect(error.detail).toBe(detail); expect(error.cause).toMatchObject({ code, - errorMessage: "private provider payload " + "x".repeat(4096), + errorMessage: "private provider payload", }); }), ); diff --git a/packages/provider-grok/src/server/textGeneration.ts b/packages/provider-grok/src/server/textGeneration.ts index cd24b0284bdfc..1b9ede6652e85 100644 --- a/packages/provider-grok/src/server/textGeneration.ts +++ b/packages/provider-grok/src/server/textGeneration.ts @@ -18,7 +18,6 @@ import { makeGrokAcpRuntime, resolveGrokAcpBaseModelId, } from "./acpSupport.ts"; - import { xAiRateLimitedErrorCode } from "./xaiAcpExtension.ts"; const GROK_TIMEOUT_MS = 180_000; @@ -31,6 +30,7 @@ function grokAcpFailureDetail(cause: EffectAcpErrors.AcpError, fallback: string) switch (cause.code) { case xAiRateLimitedErrorCode: return "Grok usage limit reached. Try again later."; + // ACP auth_required case -32000: return "Grok authentication is required."; default: