refactor(llm): redesign error model as flat tagged union#36622
Open
rekram1-node wants to merge 1 commit into
Open
refactor(llm): redesign error model as flat tagged union#36622rekram1-node wants to merge 1 commit into
rekram1-node wants to merge 1 commit into
Conversation
- Replace LLMError { module, method, reason } wrapper with a flat tagged
union: BadRequest, Authentication, PermissionDenied, NotFound, RateLimit,
QuotaExceeded, ContentPolicy, ContextOverflow, ServerError, APIError,
ConnectionError, TimeoutError, MalformedResponse, NoRoute.
- Delete the provider-error LLMEvent: streams carry output only and every
failure exits through the typed error channel.
- Add one shared classifyApiFailure classifier used by the HTTP executor,
protocol stream errors, and the AI SDK adapter so all routes classify
identically (including OpenAI in-stream rate_limit_exceeded and
internal_error codes).
- Enforce a terminal contract in LLMClient.stream for every route: EOF
without finish and output after finish fail as MalformedResponse.
- Classify AI SDK failures properly in core/aisdk.ts instead of collapsing
to UnknownProvider; preserve status, headers, body, and retry-after.
- Simplify the session runner: drop held-back overflow events, key overflow
recovery off LLM.ContextOverflow, retry RateLimit | ServerError |
ConnectionError | TimeoutError.
- Map new tags in toSessionError (provider.context-overflow,
provider.timeout, provider.not-found).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Redesigns the
packages/llmfailure contract so streams carry output only and every failure exits through one typed error channel, classified identically across native protocol routes and the AI SDK route.Error model
LLMErroris now a flat tagged union (no{ module, method, reason }wrapper):BadRequest | Authentication | PermissionDenied | NotFound | RateLimit | QuotaExceeded | ContentPolicy | ContextOverflow | ServerError | APIError | ConnectionError | TimeoutError | MalformedResponse | NoRoute, with fields directly on the error and anisLLMErrorguard.ContextOverflow,QuotaExceeded, andContentPolicyare the only semantic upgrades, applied by one contained classifier.APIErroris the fallback for any other deliberate non-2xx rejection.provider-error event removed
provider-errorLLMEventis deleted. Anthropic SSEerrorevents, OpenAI Responsesresponse.failed/error, and Bedrock exception frames now fail the stream with a classifiedLLMError.classifyApiFailureis used by the HTTP executor, protocol stream errors, and the AI SDK adapter. Includes OpenAI's actual in-stream codes (rate_limit_exceeded→RateLimit,internal_error→ServerError).Terminal contract
LLMClient.streamenforces, for every route including the synthetic AI SDK route: exactly onefinishon success; EOF beforefinishfails asMalformedResponse(fixes silent truncation); output afterfinishfails.Core
core/aisdk.ts(previously collapsed toUnknownProvider), preserving status/headers/body/retry-after.LLM.ContextOverflow; retry policy =RateLimit | ServerError | ConnectionError | TimeoutError. Retry scheduling and the no-retry-after-output rule are unchanged.toSessionErroraddsprovider.context-overflow,provider.timeout,provider.not-found.Notes
packages/opencode(deadprovider-errorswitch case, one test stream) — schema change broke the V1 build; no V1 feature work.provider.*session error strings it may want a follow-up for the new types.Testing
packages/llm: typecheck clean, 309 pass / 0 failpackages/core: typecheck clean, 1270 pass / 0 failpackages/opencode,packages/server,packages/cli: typecheck clean (one pre-existingprocessor-effectfailure reproduces identically at HEAD)