Every run page asked for the provider catalog, though only a failed or
dead run's banner uses it. useProviders takes an enabled flag, and the
id-to-display-name map settings-models built by hand is now
providerNamesById, shared with the run page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The banner stripped a trailing @1 by hand, a second copy of the
sidebar's visit-suffix rule. Use formatStageLabel so the banner and the
Stages sidebar label a looped step the same way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The output block was capped at max-h-48 but the verbatim message wasn't,
so a long stack trace or cause chain could push the tabs out of view in
the full-height sandbox and terminal layouts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server records a failure's category as deterministic or canceled, so
checking only the transient_infra category never fired. Check the
transient_infra reason as well, the way budget exhaustion already is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stop step was the latest step to start, and only if it failed, so a
sibling branch starting a few milliseconds after the failed one hid it.
Name the latest failed step that no later step went on from, where a
concurrent sibling branch or the step's own branches don't count as
going on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A configuration, model-selection, network, middleware or resource-limit
error names a provider but never got an answer from it, yet the banner
said the provider rejected the request. Give these kinds wording that
points at Fabro's catalog, the network, or Fabro's own limits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every 403 was reported as a rejected API key, so a user whose key works
but whose account isn't allowed the model or region would rotate a good
key. Only lithos-llm's authentication kind or a 401 gets the API-key
wording; access_denied and other 403s say access was denied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A spent quota can come back as HTTP 429, which the banner showed as a
temporary rate limit and told the user to retry. lithos-llm marks it
quota_exceeded, which backoff never clears, so give it the billing
wording.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server never fills conclusion.failure.detail.exec_output_tail, so the
Output section never appeared. Fall back to the output the stopped stage
recorded in the run state, skipping offloaded blob references and model
request failures, whose step output is the agent's text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dead run's projection never gets conclusion.failure, so the banner
never showed. Fall back to the run summary's lifecycle.error, where the
server keeps a dead run's reason, and to a generic headline when that is
empty too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The status popover shows the reason code ("Workflow error") and
lifecycle.error, which is empty when the failure lives in the run's
state, so a run stopped by the provider's billing refusal showed no
reason anywhere. The message is in conclusion.failure.detail, which the
run page already loads.
Show a quiet banner on failed and dead runs: the step the run stopped
at, a headline and the next thing to do, with the verbatim message and
the tail of a failed command's output in a closed <details>. The advice
comes from the failure's reason and category first (approval denied,
budget, publish, launch), then from the structured model request
message the server records (provider, kind, status, code), then from a
command's exit status. Command output is never searched for provider
or billing words. Provider names come from /providers, cancelled runs
get no banner, and a step that failed earlier but was recovered from
isn't named as the stop.