CL-6568: tell people before they type, and don't lie when it fails - #280
Merged
Conversation
Covers a tenant whose model_provider row has no credential, the failed-turn strip surfacing the server's cause-aware notice text instead of a generic guess, and Retry recovering the original request text so it isn't lost.
A tenant's model_provider row seeds with no credential attached, so "a provider row exists" was standing in for "a model can run" - the gap this fixes on three fronts: - hasUsableModel (@corbits/inference-settings) checks the same resolved catalog resolveModelSources acts on at launch, so it's false whenever no offering actually resolves, provider row or not. - The chat composer now shows NoUsableModelBanner and leads into Settings -> AI providers before a person invests a message in a reply that was never coming - the composer stays live throughout. - The failed-turn strip renders postUndeliveredNotice's own cause-aware text (already distinguishing a missing credential from a generic dispatch failure server-side) instead of a fixed "may be unavailable" guess, and Retry now hands the original request text back to the composer via findRetryText instead of doing nothing.
This was referenced Aug 22, 2026
TheGreatAxios
added a commit
that referenced
this pull request
Aug 22, 2026
A hub-owned ANTHROPIC_API_KEY has never been the only valid seed source in spirit — it was just the only one anything ever triggered from. Connecting a provider through Settings (packages/connections) persisted the credential and seeded its catalog, but nothing ever told the durable pending-seed drain (bench-provisioning.ts) about it, so a self-serve tenant whose only provider is one it connected itself never got Myra or the default workflow set, and /api/onboarding/ provisioning-status polled 200 forever with no way to converge. The connect route now asks the same resolved-catalog question launch itself asks (hasUsableModel, @corbits/inference-settings, PR #280) once a credential is durably stored, and — only when that tenant now has a model with a real offering, never merely because a credential row exists — hands the connecting provider's own key to the same pendingSeedStore + benchProvisioner the onboarding credential step already feeds. That drain is idempotent and restart-safe already, so routing a Settings connect through it needed no new seeding logic, only a new trigger. Also threads a `baseURLOverride` through the pending-seed row end to end (pending-seed.ts, bench-provisioning.ts) so a url-kind connector (Ollama) deploys against the instance a person actually pointed at rather than falling back to a curated default — fixing the same latent gap in onboarding's own credential-step trigger along the way.
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
CL-6568: https://linear.app/abklabs/issue/CL-6568
A tenant's
model_providerrow seeds with no credential attached, so"a provider row exists" was standing in for "a model can run." Fixed on
three fronts, in the reported priority order:
hasUsableModel(@corbits/inference-settings) readsthe same resolved catalog
resolveModelSourcesacts on at launch —true only once some model actually resolves an offering, never mere
row presence. The composer now shows
NoUsableModelBanneraboveitself (never disabling it) leading into Settings → AI providers
whenever this tenant has none, for any workbench with an agent
participant.
postUndeliveredNotice) alreadywrites cause-aware text distinguishing a missing credential from a
generic dispatch failure, but the client's
FailedTurnStripdiscardedit for a fixed "may be unavailable" guess. It now renders the
notice's own text.
onRetryFailedTurnwas wired nowhere —clicking Retry did nothing.
findRetryTextrecovers the originalrequest text and Retry now hands it back into the composer.
Test plan
bun testgreen in@corbits/chat-ui(668 pass) and@corbits/inference-settings(39 pass)tsc --noEmitclean in@corbits/chat-ui,@corbits/inference-settings,@workbench/webbun run check:browser-safe-subpaths,check:licenses,check:tool-package-pinsall passbunx prettier --write+eslintclean on every changed file(not run — no browser session in this environment)