chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
+72
-1
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { fauxAssistantMessage } from "../src/providers/faux.ts";
|
||||
import { isRetryableAssistantError, type RetryPolicy, retryAssistantCall } from "../src/utils/retry.ts";
|
||||
import { isRetryableAssistantError, type RetryPolicy, retryAssistantCall, retryDelayMs } from "../src/utils/retry.ts";
|
||||
|
||||
const openAIExplicitRetryMessage =
|
||||
"An error occurred while processing your request. You can retry your request, or contact us through our help center at help.openai.com if the error persists. Please include the request ID req_******** in your message.";
|
||||
@@ -12,6 +12,8 @@ const bunFetchSocketClosedMessage =
|
||||
const openAIResponsesEarlyEofMessage = "OpenAI Responses stream ended before a terminal response event";
|
||||
const wrappedDnsLookupError =
|
||||
"The pending stream has been canceled (caused by: getaddrinfo ENOTFOUND bedrock-runtime.us-east-1.amazonaws.com)";
|
||||
const azurePeakLoadError =
|
||||
"The system is currently experiencing high demand and cannot process your request. Your request exceeds the maximum usage size allowed during peak load. For improved capacity reliability, consider switching to Provisioned Throughput.";
|
||||
|
||||
describe("provider retry classification", () => {
|
||||
it("matches explicit provider retry guidance", () => {
|
||||
@@ -60,6 +62,23 @@ describe("provider retry classification", () => {
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
});
|
||||
|
||||
it.each(["The pending stream has been canceled", "The pending stream has been canceled (caused by: socket closed)"])(
|
||||
"matches HTTP/2 pending stream cancellation: %s",
|
||||
(errorMessage) => {
|
||||
// Regression for #10379.
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
// Regression for #10965 (provider unknown, no status code in the message).
|
||||
"The service is temporarily unavailable. Please retry later.",
|
||||
// Bedrock ServiceUnavailableException as formatted by formatBedrockError.
|
||||
"Service unavailable: The service is temporarily unavailable.",
|
||||
])("matches service unavailable wording: %s", (errorMessage) => {
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
});
|
||||
|
||||
it("matches OpenAI Responses streams that end before terminal events", () => {
|
||||
expect(
|
||||
isRetryableAssistantError(
|
||||
@@ -68,6 +87,13 @@ describe("provider retry classification", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("matches Azure peak-load capacity errors", () => {
|
||||
// Regression for #9669.
|
||||
expect(
|
||||
isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage: azurePeakLoadError })),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps provider limit errors non-retryable", () => {
|
||||
expect(
|
||||
isRetryableAssistantError(
|
||||
@@ -76,10 +102,29 @@ describe("provider retry classification", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps the ChatGPT subscription usage limit non-retryable", () => {
|
||||
const errorMessage =
|
||||
'OpenAI API error (429): {"code":"subscription_sharing_usage_limit_exceeded","message":"Usage limit reached."}';
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(false);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"subscription_sharing_usage_unavailable: Usage cannot be checked.",
|
||||
"subscription_sharing_user_unavailable: User cannot be loaded.",
|
||||
])("retries temporary ChatGPT subscription errors: %s", (errorMessage) => {
|
||||
expect(isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage }))).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies assistant error messages", () => {
|
||||
expect(
|
||||
isRetryableAssistantError(fauxAssistantMessage("", { stopReason: "error", errorMessage: "overloaded_error" })),
|
||||
).toBe(true);
|
||||
// Regression for #9627.
|
||||
expect(
|
||||
isRetryableAssistantError(
|
||||
fauxAssistantMessage("", { stopReason: "error", errorMessage: "520 status code (no body)" }),
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isRetryableAssistantError(
|
||||
fauxAssistantMessage("", { stopReason: "error", errorMessage: "524 status code (no body)" }),
|
||||
@@ -89,6 +134,15 @@ describe("provider retry classification", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("retryDelayMs", () => {
|
||||
it("caps agent retry delay", () => {
|
||||
// Regression for #8826.
|
||||
expect(retryDelayMs({ baseDelayMs: 2000 }, 6)).toBe(60000);
|
||||
expect(retryDelayMs({ baseDelayMs: 2000, maxAgentDelayMs: 5000 }, 5)).toBe(5000);
|
||||
expect(retryDelayMs({ baseDelayMs: 2000, maxAgentDelayMs: 0 }, 5)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("retryAssistantCall", () => {
|
||||
const disabled: RetryPolicy = { enabled: false, maxRetries: 3, baseDelayMs: 0 };
|
||||
const enabled: RetryPolicy = { enabled: true, maxRetries: 3, baseDelayMs: 0 };
|
||||
@@ -133,6 +187,23 @@ describe("retryAssistantCall", () => {
|
||||
expect(onRetryFinished).toHaveBeenCalledWith(false, 3, "terminated");
|
||||
});
|
||||
|
||||
it("reports capped retry delays", async () => {
|
||||
// Regression for #8826.
|
||||
let n = 0;
|
||||
const policy: RetryPolicy = { enabled: true, maxRetries: 4, baseDelayMs: 10, maxAgentDelayMs: 15 };
|
||||
const produce = vi.fn(async () => {
|
||||
n++;
|
||||
return n < 5
|
||||
? fauxAssistantMessage("", { stopReason: "error", errorMessage: "terminated" })
|
||||
: fauxAssistantMessage("recovered");
|
||||
});
|
||||
const onRetryScheduled = vi.fn();
|
||||
|
||||
await retryAssistantCall(produce, policy, undefined, { onRetryScheduled });
|
||||
|
||||
expect(onRetryScheduled.mock.calls.map((call) => call[2])).toEqual([10, 15, 15, 15]);
|
||||
});
|
||||
|
||||
it("stops retrying once a call succeeds", async () => {
|
||||
let n = 0;
|
||||
const produce = vi.fn(async () => {
|
||||
|
||||
Reference in new issue
Block a user