fix(resilience): surface Responses failed.error.message in 502s (#12472)

Validado em lote numa worktree combinada com os 10 PRs desta leva sobre o tip de `release/v3.8.51`: `typecheck:core` limpo, `check-file-size` OK e **241/242** nos 29 arquivos de teste que os PRs tocam.

A única "falha" não é falha: `tests/unit/autoCombo/strict-zero-cost-filter.test.ts` é um teste em estilo Vitest que eu incluí por engano na invocação do runner nativo do Node — ele quebra no import (`@vitest/runner`), não numa asserção. Ao investigar, descobri que esse arquivo não roda em nenhum dos dois runners hoje (o glob do `test:unit` não lista `autoCombo` e o `include` do Vitest só pega `.tsx` nessa pasta); é um problema pré-existente do repositório, sem relação com esta leva, e vou registrá-lo separadamente.

O #12636 conflitava apenas na lista de testes do `@omniroute/opencode-plugin/package.json`, de forma aditiva: o tip já tinha `models-fetcher.test.ts` (do #12607, irmão desta mesma leva) e o #12636 acrescenta `telemetry.test.ts`. Fiz a união dos dois lados (25 arquivos contra 24 de cada) em vez de escolher um, o que teria removido um arquivo da suíte do plugin em silêncio.

Obrigado, @RaviTharuma.
This commit is contained in:
Ravi Tharuma
2026-09-04 04:37:47 +02:00
committed by GitHub
parent 04ba19fa62
commit bb8e75a00d
2 changed files with 23 additions and 1 deletions

View File

@@ -323,8 +323,14 @@ export function describeMalformedNonStream(
): { message: string; code: string; type: string } {
const body = resp && typeof resp === "object" ? (resp as Record<string, unknown>) : null;
if (body?.object === "response" && body.status === "failed") {
const err = body.error && typeof body.error === "object" ? (body.error as Record<string, unknown>) : null;
const rawMessage =
typeof err?.message === "string" && err.message.trim().length > 0 ? err.message.trim() : null;
return {
message: "upstream reported a failed response without usable output",
// Trim only here; buildErrorBody (chatCore) does the single sanitization pass.
message: rawMessage
? `upstream reported a failed response: ${rawMessage}`
: "upstream reported a failed response without usable output",
code: "upstream_response_failed",
type: "upstream_response_error",
};

View File

@@ -105,6 +105,22 @@ test("failed Responses API body gets a request-scoped machine-readable classific
});
});
test("failed Responses API body surfaces the upstream error message when present", () => {
const failed = {
object: "response",
status: "failed",
output: [],
error: { code: "server_error", message: " Gemini 503: overloaded " },
};
const reason = detectMalformedNonStream(failed);
assert.equal(reason, "empty_choices");
assert.deepEqual(describeMalformedNonStream(failed, reason), {
message: "upstream reported a failed response: Gemini 503: overloaded",
code: "upstream_response_failed",
type: "upstream_response_error",
});
});
test("detectMalformedNonStream returns 'empty_choices' when choice message has no content", () => {
const body = {
choices: [{ message: { content: "", tool_calls: null }, finish_reason: "stop" }],