Q87: provider errors keep status and provider code; text never decides recovery

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-08 14:52:31 -04:00
1 parent 7ecffe84e3
commit 4668396f25
28 files changed
+285 -108

No files matched your search

+1 -29
View File
@@ -35,37 +35,9 @@ export interface ProviderRateLimitObservationRecord extends ProviderObservedRate
observedAt: string;
}
/**
* Exact message recorded on runs blocked by a provider's monthly usage window.
* The heartbeat scheduler matches task_runs.error_message against this string
* so quota-blocked attempts never consume a task's retry budget — the text is
* a cross-module contract and also matches rows written by earlier builds
* that inlined it.
*/
/** The message of the typed error a run gets when its provider's monthly request allowance is used up. */
export const PROVIDER_MONTHLY_LIMIT_MESSAGE = "Provider monthly request limit has been reached.";
/**
* Failure-message signatures of transient provider conditions — the account's
* usage window filling up, rate limiting, or momentary overload. These verdicts
* come from the provider's side of the wire and say nothing about the task, so
* schedulers must treat them as "try again later", never as attempts consumed.
* Matched case-insensitively against recorded task_runs.error_message rows,
* which also heals historical rows written before this classification existed.
*/
export const TRANSIENT_PROVIDER_FAILURE_SIGNATURES = [
PROVIDER_MONTHLY_LIMIT_MESSAGE,
"usage limit", // ChatGPT-account plans: "The usage limit has been reached"
"rate limit",
"too many requests", // HTTP 429 status text
"overloaded", // "Our servers are currently overloaded. Please try again later."
].map((signature) => signature.toLowerCase());
export function isTransientProviderFailure(message: string | null | undefined): boolean {
if (!message) return false;
const normalized = message.toLowerCase();
return TRANSIENT_PROVIDER_FAILURE_SIGNATURES.some((signature) => normalized.includes(signature));
}
export function currentProviderUsageWindow(now = new Date()): { start: string; end: string } {
const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));