fix(studio): recover transient AI failures and report provider diagnostics

This commit is contained in:
Clintchiz committed 2026-10-19 19:42:55 +05:30
1 parent 98b3c5ff2f
commit e8c0f06d8f
4 files changed
+320 -41

No files matched your search

+120 -1
View File
@@ -3,6 +3,7 @@ import { CORE_DESIGN_SYSTEMS } from "@wrnexus/design-system";
import { designRevision, DEFAULT_DESIGN_BRIEF } from "@wrnexus/design-studio";
import {
AI_TIMEOUT_MS,
AI_OUTPUT_TOKENS,
apimartProvider,
studioAI,
} from "../app/lib/studio-ai.ts";
@@ -57,7 +58,7 @@ test("APIMart uses the specified model, bearer authentication, non-streaming JSO
const body = JSON.parse(init?.body as string);
expect(body.model).toBe("gpt-6-luna");
expect(body.stream).toBe(false);
expect(body.max_tokens).toBe(4096);
expect(body.max_tokens).toBe(AI_OUTPUT_TOKENS);
expect(body.messages).toEqual([
{ role: "system", content: "rules" },
{ role: "user", content: "brief" },
@@ -200,3 +201,121 @@ test("a public AI endpoint enforces a bounded generation rate", async () => {
expect((await handler(await request()))!.status).toBe(200);
expect((await handler(await request()))!.status).toBe(429);
});
test("temporary APIMart failures retry once and return three validated designs", async () => {
let calls = 0;
const handler = studioAI(
"test-secret",
mockFetch(async (_url, init) => {
calls++;
expect(JSON.parse(init!.body as string).max_tokens).toBe(8192);
return calls === 1
? new Response("sensitive upstream context test-secret", {
status: 503,
})
: completion();
}),
);
const batch = await (await handler(await request()))!.json();
expect(calls).toBe(2);
expect(batch.alternatives).toHaveLength(3);
expect(batch.provenance.attempts).toBe(2);
expect(batch.provenance.maxOutputTokens).toBe(8192);
});
test("authentication and quota failures provide actionable redacted diagnostics without retrying", async () => {
for (const [status, code, hint] of [
[401, "invalid_api_key", "server API key"],
[402, "insufficient_quota", "credit or quota"],
[404, "model_not_found", "gpt-6-luna"],
] as const) {
let calls = 0;
const handler = studioAI(
"test-secret",
mockFetch(async () => {
calls++;
return Response.json(
{ error: { code, message: "test-secret private brief" } },
{ status },
);
}),
);
const body = await (await handler(await request()))!.text();
expect(calls).toBe(1);
expect(body).toContain(hint);
expect(body).not.toContain("test-secret");
expect(body).not.toContain("private brief");
}
});
test("truncated and empty completions retry but never exceed two total upstream calls", async () => {
for (const kind of ["length", "empty", "invalid-then-outage"]) {
let calls = 0;
const handler = studioAI(
"test-secret",
mockFetch(async () => {
calls++;
if (kind === "invalid-then-outage")
return calls === 1
? Response.json({
choices: [{ message: { content: "invalid JSON" } }],
})
: new Response("private upstream body", { status: 502 });
return calls === 1
? Response.json({
choices: [
{
finish_reason: kind === "length" ? "length" : "stop",
message: { content: "" },
},
],
})
: completion();
}),
);
const batch = await (await handler(await request()))!.json();
expect(calls).toBe(2);
expect(batch.provenance.attempts).toBe(2);
expect(batch.alternatives).toHaveLength(
kind === "invalid-then-outage" ? 0 : 3,
);
}
});
test("network and repeated rate failures remain bounded and describe the actual failure category", async () => {
for (const network of [true, false]) {
let calls = 0;
const handler = studioAI(
"test-secret",
mockFetch(async () => {
calls++;
if (network) throw Error("private test-secret TLS details");
return new Response("private test-secret", { status: 429 });
}),
);
const body = await (await handler(await request()))!.text();
expect(calls).toBe(2);
expect(body).toContain(
network ? "could not reach APIMart" : "rate limiting",
);
expect(body).not.toContain("test-secret");
}
});
test("a retry followed by an invalid design does not spend a third request or mislabel a schema error", async () => {
let calls = 0;
const handler = studioAI(
"test-secret",
mockFetch(async () => {
calls++;
return calls === 1
? new Response("unavailable", { status: 503 })
: Response.json({ choices: [{ message: { content: "not JSON" } }] });
}),
);
const batch = await (await handler(await request()))!.json();
expect(calls).toBe(2);
expect(batch.alternatives).toHaveLength(0);
expect(batch.diagnostics[0].code).toBe("WRN-STUDIO-PROPOSAL");
expect(batch.diagnostics[0].message).toContain("schema");
});