You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace LLxprt's independently composed retry/recovery paths with one request-scoped retry architecture that preserves transient recovery, Anthropic HTTP-200 overload handling, OAuth repair, credential-bucket rotation, and load-balanced failover while making replay after observable stream output impossible.
This is not a request to remove retries. Distinct recovery decisions must share one failure taxonomy, aggregate budget, and irreversible commit state.
Problem and file catalog
packages/providers/src/RetryOrchestrator.ts: central retry/backoff, first-chunk timeout, auth recovery, bucket rotation. yieldStreamUnprotected() marks post-yield failures, but streamWithTimeout()/raceFirstChunkWithTimeout() use a separate path.
packages/providers/src/anthropic/AnthropicStreamProcessor.ts: parses events and also retries networks in processAnthropicStream(). Usage metadata does not consistently set hasYieldedContent.
packages/providers/src/LoadBalancingProvider.ts: guards post-yield failover for immediate classes such as 429, but not universally for ordinary retryable failures.
packages/providers/src/loadBalancing/streamTimeout.ts: separate timeout/iterator cleanup.
packages/providers/src/ProviderManager.ts
error/auth/bucket helpers under packages/providers/src/**
active retry helpers under packages/core/src/utils/retry.ts
Anthropic tests under packages/providers/src/anthropic/**
Anthropic can return HTTP 200 and later send SSE event: error, including overloaded_error. This remains retryable before any observable event, but never after metadata, text, thinking, or a tool call escapes.
Known gaps:
streamWithTimeout() loses normal post-yield marking after the first chunk.
First-chunk timeout does not consistently close the losing iterator/request.
Anthropic owns a duplicate retry loop and can retry after usage metadata.
Load balancing does not universally block retry/failover after output.
Distributed counters and delays allow multiplicative attempts.
Provider-terminal validation for malformed/truncated streams is not unified.
Track aggregate attempts, deadline, total wait, visited credentials/targets, Retry-After, and an irreversible committed flag set before every outward event.
Mandatory policy:
After exposure, do not replay, rotate credentials for this request, retry a backend, or fail over.
Metadata counts as exposure.
HTTP-200 in-band errors remain retryable before exposure.
Auth repair after exposure can prepare future requests but cannot replay this one.
Tests prove partial output is not duplicated or mixed.
Retry telemetry reports phase, kind, budget, target, and commitment without secrets.
Architecture docs assign decoding and recovery ownership.
Verification
Run npm run format, npm run lint, npm run typecheck, npm run test, npm run build, and bun scripts/start.ts --profile-load ollamakimi "write me a haiku and nothing else", plus focused retry/Anthropic/OAuth/bucket/load-balancer/cancellation/noninteractive tests.
Appreciable outcome
LLxprt still recovers from failures that motivated its retry system—including Anthropic's non-HTTP overloads—but each request has a predictable budget, no leaked timeout request, no duplicate/mixed output after exposure, and one maintainable recovery model.
Objective
Replace LLxprt's independently composed retry/recovery paths with one request-scoped retry architecture that preserves transient recovery, Anthropic HTTP-200 overload handling, OAuth repair, credential-bucket rotation, and load-balanced failover while making replay after observable stream output impossible.
This is not a request to remove retries. Distinct recovery decisions must share one failure taxonomy, aggregate budget, and irreversible commit state.
Problem and file catalog
packages/providers/src/RetryOrchestrator.ts: central retry/backoff, first-chunk timeout, auth recovery, bucket rotation.yieldStreamUnprotected()marks post-yield failures, butstreamWithTimeout()/raceFirstChunkWithTimeout()use a separate path.packages/providers/src/anthropic/AnthropicStreamProcessor.ts: parses events and also retries networks inprocessAnthropicStream(). Usage metadata does not consistently sethasYieldedContent.packages/providers/src/anthropic/AnthropicProvider.tspackages/providers/src/LoadBalancingProvider.ts: guards post-yield failover for immediate classes such as 429, but not universally for ordinary retryable failures.packages/providers/src/loadBalancing/streamTimeout.ts: separate timeout/iterator cleanup.packages/providers/src/ProviderManager.tspackages/providers/src/**packages/core/src/utils/retry.tspackages/providers/src/RetryOrchestrator*.test.tspackages/providers/src/LoadBalancingProvider*.test.tspackages/providers/src/anthropic/**Anthropic can return HTTP 200 and later send SSE
event: error, includingoverloaded_error. This remains retryable before any observable event, but never after metadata, text, thinking, or a tool call escapes.Known gaps:
streamWithTimeout()loses normal post-yield marking after the first chunk.Required architecture
Represent at least:
Track aggregate attempts, deadline, total wait, visited credentials/targets, Retry-After, and an irreversible
committedflag set before every outward event.Mandatory policy:
Required characterization tests
Acceptance criteria
Verification
Run
npm run format,npm run lint,npm run typecheck,npm run test,npm run build, andbun scripts/start.ts --profile-load ollamakimi "write me a haiku and nothing else", plus focused retry/Anthropic/OAuth/bucket/load-balancer/cancellation/noninteractive tests.Appreciable outcome
LLxprt still recovers from failures that motivated its retry system—including Anthropic's non-HTTP overloads—but each request has a predictable budget, no leaked timeout request, no duplicate/mixed output after exposure, and one maintainable recovery model.