Originally created by: sosidudku1
Cloud failures were thrown as plain Error, so the classifier filed every one of them under category tool: a provider 429 read as Turn failed [tool], indistinguishable from a bug in our tool layer, and the client's own timeout surfaced as cancelled, as if the user had pressed Esc. The llama path retries transient failures three times; the cloud path retried nothing.
OpenAiHttpError mirrors LlamaServerError: status (null for network failures), url, a timedOut flag for our own timeout controller, and retryAfterMs parsed from a retry-after header. Caller aborts are rethrown untouched, so cancellation stays cancellation.
The classifier maps it to TransportError for every status: a provider-boundary failure is transport, not our tool, whatever the code. Retry policy is decoupled from the category and lives in the client, matching the llama split:
retry-after honored up to a 5s cap, so a server-side cooldown cannot stall an interactive turnThe typed fields also feed a human sentence in chat instead of the raw transport line. Wording is provider + condition + remedy:
Can't reach "openrouter" — no response from api.example.com. Tried 3 times. Check the provider URL or your connection."openrouter" rejected the API key (401). Check the key in the Providers panel."openrouter" is rate-limiting this key (429). Tried 3 times — wait a minute and retry."openrouter" answered 404 (not found). The model id or the base URL is likely wrong."openrouter" is having server trouble (500). Tried 3 times — this is on the provider, not your setup.A retry count is only claimed for classes the client actually retries. The raw technical string stays on the error's cause chain for logs.
No new failure categories and no new config keys. Whether auth deserves its own signal is an open design question, and the retry constants can grow knobs once it settles where cloud provider settings live. Both are deliberate: this PR fixes the misclassification and honors the existing TransportError contract ("by the time it propagates, the bounded budget is exhausted") with the smallest surface.
openai-http.test.ts: typed fields, retry-vs-fail-fast per status, retry-after, network wrap, own-timeout flag, caller-abort passthrough, stream-open retry, humanized wording per class, classification table (every cloud status maps to transport, never tool).tsc clean; src/llm/ + src/agent/ suites pass (399 tests).Turn failed [transport] after three fast attempts.Foundation for the fallback-chain design in [#70]; worth shipping on its own for the classification fix.
Ticket changed by: Ooooze