From dd2fbacda9152de5244e9a1ac800b543b1d29d4e Mon Sep 17 00:00:00 2001 From: Allen Zhou <46854522+allenzhou101@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:02:37 -0700 Subject: [PATCH] fix(eve): surface gateway rejection details Signed-off-by: Allen Zhou <46854522+allenzhou101@users.noreply.github.com> --- .changeset/gateway-error-detail.md | 5 ++++ .../eve/src/harness/model-call-error.test.ts | 19 ++++++++++++++ packages/eve/src/harness/model-call-error.ts | 25 ++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 .changeset/gateway-error-detail.md diff --git a/.changeset/gateway-error-detail.md b/.changeset/gateway-error-detail.md new file mode 100644 index 000000000..8903686b2 --- /dev/null +++ b/.changeset/gateway-error-detail.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +Preserve specific AI Gateway 400 rejection details in model-call failure summaries so channels surface actionable context instead of only a generic request-rejected message. diff --git a/packages/eve/src/harness/model-call-error.test.ts b/packages/eve/src/harness/model-call-error.test.ts index b3b3626e1..352145d08 100644 --- a/packages/eve/src/harness/model-call-error.test.ts +++ b/packages/eve/src/harness/model-call-error.test.ts @@ -260,6 +260,25 @@ describe("summarizeKnownModelCallRequestError", () => { message: "AI Gateway rejected the model request before the agent produced a response.", }); }); + + it("keeps specific Gateway 400 rejection details in the summary", () => { + const summary = summarizeKnownModelCallRequestError( + gatewayModelCallError({ + gatewayName: "GatewayInvalidRequestError", + gatewayType: "invalid_request_error", + statusCode: 400, + upstreamMessage: "input tokens exceed the model context window", + upstreamStatusCode: 400, + upstreamType: "invalid_request_error", + }), + ); + + expect(summary).toEqual({ + name: "AI Gateway model request rejected", + message: + "AI Gateway rejected the model request before the agent produced a response. Gateway detail: input tokens exceed the model context window", + }); + }); }); /** diff --git a/packages/eve/src/harness/model-call-error.ts b/packages/eve/src/harness/model-call-error.ts index 98936ffe5..cf5e13edb 100644 --- a/packages/eve/src/harness/model-call-error.ts +++ b/packages/eve/src/harness/model-call-error.ts @@ -2,6 +2,7 @@ import { isObject } from "#shared/guards.js"; import type { JsonObject, JsonValue } from "#shared/json.js"; const RESPONSE_BODY_SNIPPET_LIMIT = 1_000; +const GATEWAY_REQUEST_SUMMARY_DETAIL_LIMIT = 240; const GATEWAY_MODEL_REQUEST_REJECTED_MESSAGE = "AI Gateway rejected the model request before the agent produced a response."; @@ -131,13 +132,35 @@ export function summarizeKnownModelCallRequestError( if (signals.statusCode === 400 && isGatewayErrorSignal(signals)) { return { name: "AI Gateway model request rejected", - message: GATEWAY_MODEL_REQUEST_REJECTED_MESSAGE, + message: formatGatewayModelRequestRejectedMessage(signals), }; } return null; } +function formatGatewayModelRequestRejectedMessage(signals: ModelCallErrorSignals): string { + const detail = signals.upstreamMessage?.trim(); + if (detail === undefined || detail.length === 0 || isGenericGatewayRejectionMessage(detail)) { + return GATEWAY_MODEL_REQUEST_REJECTED_MESSAGE; + } + + return `${GATEWAY_MODEL_REQUEST_REJECTED_MESSAGE} Gateway detail: ${truncateSummaryDetail( + detail, + )}`; +} + +function isGenericGatewayRejectionMessage(message: string): boolean { + return /^(bad request|internal server error)$/i.test(message.trim()); +} + +function truncateSummaryDetail(value: string): string { + if (value.length <= GATEWAY_REQUEST_SUMMARY_DETAIL_LIMIT) { + return value; + } + return `${value.slice(0, GATEWAY_REQUEST_SUMMARY_DETAIL_LIMIT - 1).trimEnd()}…`; +} + /** * Returns the distinct upstream tool types referenced by any * "tool type 'X' is not supported" rejection in an AI Gateway error's