fix(reef): close provider streams after guard errors (#109196)

This commit is contained in:
xingzhou
2026-07-17 06:53:23 +08:00
committed by GitHub
parent 6d20432a29
commit 2cd236385b
2 changed files with 35 additions and 11 deletions
@@ -58,6 +58,7 @@ export function createOpenAiGuard(options: AdapterOptions): GuardAdapter {
}),
});
if (!response.ok) {
await response.body?.cancel().catch(() => undefined);
throw new Error(`guard HTTP ${response.status}`);
}
const envelope = await parseJsonResponse(response);
@@ -113,6 +114,7 @@ export function createAnthropicGuard(options: AdapterOptions): GuardAdapter {
}),
});
if (!response.ok) {
await response.body?.cancel().catch(() => undefined);
throw new Error(`guard HTTP ${response.status}`);
}
const envelope = await parseJsonResponse(response);
+33 -11
View File
@@ -169,17 +169,39 @@ describe("provider adapters", () => {
});
});
it("fails closed on non-200 provider responses", async () => {
const guard = createOpenAiGuard({
apiKey: "test",
pinnedModel: model,
fetch: async () => jsonResponse({ error: "no" }, 500),
});
await expect(guard.classify(request)).resolves.toMatchObject({
decision: "deny",
category: "guard_failure",
});
});
it.each([
[
"OpenAI",
(fetch: FetchLike) => createOpenAiGuard({ apiKey: "test", pinnedModel: model, fetch }),
],
[
"Anthropic",
(fetch: FetchLike) => createAnthropicGuard({ apiKey: "test", pinnedModel: model, fetch }),
],
])(
"cancels %s non-200 provider response bodies before failing closed",
async (_name, createGuard) => {
let cancelled = false;
const response = new Response(
new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new TextEncoder().encode("partial error body"));
},
cancel() {
cancelled = true;
},
}),
{ status: 503 },
);
const guard = createGuard(async () => response);
await expect(guard.classify(request)).resolves.toMatchObject({
decision: "deny",
category: "guard_failure",
});
expect(cancelled).toBe(true);
},
);
it("cancels oversized provider response streams before buffering them fully", async () => {
const maxBytes = 256 * 1024;