fix(llm): remove package retry policy (#35003)
This commit is contained in:
parent
b0ca5520a1
commit
460cdc5aec
6 changed files with 77 additions and 244 deletions
|
|
@ -592,7 +592,7 @@ const step = (state: ParserState, event: BedrockEvent) =>
|
|||
event.modelStreamErrorException?.message ??
|
||||
event.serviceUnavailableException?.message ??
|
||||
"Bedrock Converse stream error"
|
||||
return [state, [LLMEvent.providerError({ message, retryable: true })]] as const
|
||||
return [state, [LLMEvent.providerError({ message })]] as const
|
||||
}
|
||||
|
||||
if (event.validationException || event.throttlingException) {
|
||||
|
|
@ -604,7 +604,6 @@ const step = (state: ParserState, event: BedrockEvent) =>
|
|||
LLMEvent.providerError({
|
||||
message,
|
||||
classification: event.validationException && isContextOverflow(message) ? "context-overflow" : undefined,
|
||||
retryable: event.throttlingException !== undefined,
|
||||
}),
|
||||
],
|
||||
] as const
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Cause, Context, Effect, Layer, Random } from "effect"
|
||||
import { Cause, Context, Effect, Layer } from "effect"
|
||||
import {
|
||||
FetchHttpClient,
|
||||
Headers,
|
||||
|
|
@ -33,9 +33,6 @@ export interface Interface {
|
|||
export class Service extends Context.Service<Service, Interface>()("@opencode/LLM/RequestExecutor") {}
|
||||
|
||||
const BODY_LIMIT = 16_384
|
||||
const MAX_RETRIES = 2
|
||||
const BASE_DELAY_MS = 500
|
||||
const MAX_DELAY_MS = 10_000
|
||||
const REDACTED = "<redacted>"
|
||||
|
||||
// One source of truth for what counts as a sensitive name across headers,
|
||||
|
|
@ -88,7 +85,7 @@ const requestId = (headers: Record<string, string>) => {
|
|||
)
|
||||
}
|
||||
|
||||
const retryableStatus = (status: number) => status === 429 || status === 503 || status === 504 || status === 529
|
||||
const providerInternalStatus = (status: number) => status === 429 || status === 503 || status === 504 || status === 529
|
||||
|
||||
const retryAfterMs = (headers: Record<string, string>) => {
|
||||
const millis = Number(headers["retry-after-ms"])
|
||||
|
|
@ -263,7 +260,7 @@ const statusReason = (input: {
|
|||
http: input.http,
|
||||
})
|
||||
}
|
||||
if (input.status >= 500 || retryableStatus(input.status)) {
|
||||
if (input.status >= 500 || providerInternalStatus(input.status)) {
|
||||
return new ProviderInternalReason({
|
||||
message: input.message,
|
||||
status: input.status,
|
||||
|
|
@ -342,27 +339,6 @@ const toHttpError = (redactedNames: ReadonlyArray<string | RegExp>) => (error: u
|
|||
})
|
||||
}
|
||||
|
||||
const retryDelay = (error: LLMError, attempt: number) => {
|
||||
if (error.retryAfterMs !== undefined) return Effect.succeed(Math.min(error.retryAfterMs, MAX_DELAY_MS))
|
||||
return Random.nextBetween(
|
||||
Math.min(BASE_DELAY_MS * 2 ** attempt * 0.8, MAX_DELAY_MS),
|
||||
Math.min(BASE_DELAY_MS * 2 ** attempt * 1.2, MAX_DELAY_MS),
|
||||
).pipe(Effect.map((delay) => Math.round(delay)))
|
||||
}
|
||||
|
||||
const retryStatusFailures = <A, R>(
|
||||
effect: Effect.Effect<A, LLMError, R>,
|
||||
retries = MAX_RETRIES,
|
||||
attempt = 0,
|
||||
): Effect.Effect<A, LLMError, R> =>
|
||||
Effect.catchTag(effect, "LLM.Error", (error): Effect.Effect<A, LLMError, R> => {
|
||||
if (!error.retryable || retries <= 0) return Effect.fail(error)
|
||||
return retryDelay(error, attempt).pipe(
|
||||
Effect.flatMap((delay) => Effect.sleep(delay)),
|
||||
Effect.flatMap(() => retryStatusFailures(effect, retries - 1, attempt + 1)),
|
||||
)
|
||||
})
|
||||
|
||||
export const layer: Layer.Layer<Service, never, HttpClient.HttpClient> = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -375,7 +351,7 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient> = Layer.e
|
|||
.pipe(Effect.mapError(toHttpError(redactedNames)), Effect.flatMap(statusError(request, redactedNames)))
|
||||
})
|
||||
return Service.of({
|
||||
execute: (request) => retryStatusFailures(executeOnce(request)),
|
||||
execute: executeOnce,
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -38,11 +38,7 @@ export class InvalidRequestReason extends Schema.Class<InvalidRequestReason>("LL
|
|||
classification: Schema.optional(ProviderFailureClassification),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class NoRouteReason extends Schema.Class<NoRouteReason>("LLM.Error.NoRoute")({
|
||||
_tag: Schema.tag("NoRoute"),
|
||||
|
|
@ -50,10 +46,6 @@ export class NoRouteReason extends Schema.Class<NoRouteReason>("LLM.Error.NoRout
|
|||
provider: ProviderID,
|
||||
model: ModelID,
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
|
||||
get message() {
|
||||
return `No LLM route for ${this.provider}/${this.model} using ${this.route}`
|
||||
}
|
||||
|
|
@ -65,11 +57,7 @@ export class AuthenticationReason extends Schema.Class<AuthenticationReason>("LL
|
|||
kind: Schema.Literals(["missing", "invalid", "expired", "insufficient-permissions", "unknown"]),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class RateLimitReason extends Schema.Class<RateLimitReason>("LLM.Error.RateLimit")({
|
||||
_tag: Schema.tag("RateLimit"),
|
||||
|
|
@ -78,33 +66,21 @@ export class RateLimitReason extends Schema.Class<RateLimitReason>("LLM.Error.Ra
|
|||
rateLimit: Schema.optional(HttpRateLimitDetails),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class QuotaExceededReason extends Schema.Class<QuotaExceededReason>("LLM.Error.QuotaExceeded")({
|
||||
_tag: Schema.tag("QuotaExceeded"),
|
||||
message: Schema.String,
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class ContentPolicyReason extends Schema.Class<ContentPolicyReason>("LLM.Error.ContentPolicy")({
|
||||
_tag: Schema.tag("ContentPolicy"),
|
||||
message: Schema.String,
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class ProviderInternalReason extends Schema.Class<ProviderInternalReason>("LLM.Error.ProviderInternal")({
|
||||
_tag: Schema.tag("ProviderInternal"),
|
||||
|
|
@ -113,11 +89,7 @@ export class ProviderInternalReason extends Schema.Class<ProviderInternalReason>
|
|||
retryAfterMs: Schema.optional(Schema.Number),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class TransportReason extends Schema.Class<TransportReason>("LLM.Error.Transport")({
|
||||
_tag: Schema.tag("Transport"),
|
||||
|
|
@ -125,11 +97,7 @@ export class TransportReason extends Schema.Class<TransportReason>("LLM.Error.Tr
|
|||
kind: Schema.optional(Schema.String),
|
||||
url: Schema.optional(Schema.String),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class InvalidProviderOutputReason extends Schema.Class<InvalidProviderOutputReason>(
|
||||
"LLM.Error.InvalidProviderOutput",
|
||||
|
|
@ -139,11 +107,7 @@ export class InvalidProviderOutputReason extends Schema.Class<InvalidProviderOut
|
|||
route: Schema.optional(Schema.String),
|
||||
raw: Schema.optional(Schema.String),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export class UnknownProviderReason extends Schema.Class<UnknownProviderReason>("LLM.Error.UnknownProvider")({
|
||||
_tag: Schema.tag("UnknownProvider"),
|
||||
|
|
@ -151,11 +115,7 @@ export class UnknownProviderReason extends Schema.Class<UnknownProviderReason>("
|
|||
status: Schema.optional(Schema.Number),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
http: Schema.optional(HttpContext),
|
||||
}) {
|
||||
get retryable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}) {}
|
||||
|
||||
export const LLMErrorReason = Schema.Union([
|
||||
InvalidRequestReason,
|
||||
|
|
@ -178,14 +138,6 @@ export class LLMError extends Schema.TaggedErrorClass<LLMError>()("LLM.Error", {
|
|||
}) {
|
||||
override readonly cause = this.reason
|
||||
|
||||
get retryable() {
|
||||
return this.reason.retryable
|
||||
}
|
||||
|
||||
get retryAfterMs() {
|
||||
return "retryAfterMs" in this.reason ? this.reason.retryAfterMs : undefined
|
||||
}
|
||||
|
||||
override get message() {
|
||||
return `${this.module}.${this.method}: ${this.reason.message}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,6 @@ export const ProviderErrorEvent = Schema.Struct({
|
|||
type: Schema.tag("provider-error"),
|
||||
message: Schema.String,
|
||||
classification: Schema.optional(ProviderFailureClassification),
|
||||
retryable: Schema.optional(Schema.Boolean),
|
||||
providerMetadata: Schema.optional(ProviderMetadata),
|
||||
}).annotate({ identifier: "LLM.Event.ProviderError" })
|
||||
export type ProviderErrorEvent = Schema.Schema.Type<typeof ProviderErrorEvent>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue