fix(ai): retry full transcript on blocked stateful OpenAI Responses prompts

This commit is contained in:
usr_bin_roygbiv
2026-07-16 00:20:24 -05:00
committed by can1357
parent 99ecfd6b6c
commit c55196eb30
2 changed files with 57 additions and 1 deletions
@@ -594,7 +594,11 @@ const streamOpenAIResponsesOnce = (
error instanceof Error &&
/previous[ _]?response/i.test(error.message) &&
/zero[ _-]?data[ _-]?retention/i.test(error.message);
if (!zdrRejection && !isOpenAIResponsesStalePreviousResponseError(error)) {
const isPromptBlocked =
error instanceof Error &&
((error as { code?: string }).code === "invalid_prompt" ||
/invalid_prompt|Request blocked/i.test(error.message));
if (!zdrRejection && !isPromptBlocked && !isOpenAIResponsesStalePreviousResponseError(error)) {
throw error;
}
// Server rejected the chain baseline: reset, count the failure (or
@@ -230,6 +230,58 @@ describe("openai-responses stateful chaining", () => {
expect(JSON.stringify(sentRequests[2]?.input)).toContain("First question");
expect(JSON.stringify(sentRequests[2]?.input)).toContain("Second question");
});
it("retries a blocked invalid_prompt previous_response_id with the full transcript", async () => {
const sentRequests: Array<Record<string, unknown>> = [];
const fetchMock = vi.fn(async (_input: string | URL | Request, init?: RequestInit) => {
const request = JSON.parse(String(init?.body)) as Record<string, unknown>;
sentRequests.push(request);
if (typeof request.previous_response_id === "string") {
return new Response(
JSON.stringify({
error: {
message: "Request blocked.",
type: "invalid_request_error",
code: "invalid_prompt",
},
}),
{ status: 400, headers: { "content-type": "application/json" } },
);
}
return createStatefulSse(`Answer ${sentRequests.length}`, `resp_${sentRequests.length}`);
}) as FetchImpl;
const providerSessionState = new Map<string, ProviderSessionState>();
const options = {
apiKey: "test-key",
sessionId: "stateful-blocked-session",
providerSessionState,
statefulResponses: true,
reasoning: "low" as const,
fetch: fetchMock,
};
const firstUser = { role: "user" as const, content: "First question", timestamp: 1000 };
const firstResponse = await streamOpenAIResponses(
model,
{ systemPrompt, messages: [firstUser] },
options,
).result();
const secondResponse = await streamOpenAIResponses(
model,
{
systemPrompt,
messages: [firstUser, firstResponse, { role: "user", content: "Second question", timestamp: 1001 }],
},
options,
).result();
expect(secondResponse.stopReason).toBe("stop");
expect(JSON.stringify(secondResponse.content)).toContain("Answer 3");
expect(sentRequests).toHaveLength(3);
expect(sentRequests[1]?.previous_response_id).toBe("resp_1");
expect(sentRequests[2]?.previous_response_id).toBeUndefined();
expect(JSON.stringify(sentRequests[2]?.input)).toContain("First question");
expect(JSON.stringify(sentRequests[2]?.input)).toContain("Second question");
});
it("disables chaining for the session after repeated stale failures and stops forcing store", async () => {
const sentRequests: Array<Record<string, unknown>> = [];