Conversation
ymichael
force-pushed
the
bb/investigate-when-the-error-appears-thr_4pah43dksr
branch
2 times, most recently
from
September 22, 2026 18:54
1c87313 to
c14e02d
Compare
The model picker could only say "Could not load models for Codex." A host that was asleep and a Codex CLI that was never installed produced the identical sentence, because the server dropped the host daemon's errorMessage and both conditions collapsed into the generic `failed` code. The missing CLI could not reach `missing_executable` at all: the codex and claude-code bridges replace the spawn ENOENT with prose guidance, which defeats the daemon's message-pattern classification. Carry the underlying failure to the picker as a new nullable `detail` on SystemExecutionOptionsModelLoadError, filled at the server boundary from the ApiError message only (unknown errors stay null, matching errorToResponse). The catalog store records it beside each failure code and keeps the message from a host that dropped mid-refresh, which previously served a bare `failed`. Give the two lines separate jobs so neither repeats the other: the summary always says what failed, and the reason line says why in a short phrase -- "CLI not found", "Not signed in", "Timed out", "Provider plugin failed to load", or the host's own words for `failed`. The full host message stays on the tooltip, in `bb provider models`, and in the 503 details. Classify a missing provider CLI structurally instead of sniffing text: add BRIDGE_JSON_RPC_ERRORS.MISSING_EXECUTABLE and experimental_BridgeMissingExecutableError, emit them from the codex and claude-code catalog paths, and map the code in the daemon. The ACP bridge already rejects with the raw ENOENT and is unchanged. `bb provider models` previously ignored modelLoadError entirely and printed "No models available"; it now reports the provider, code, and detail on stderr while leaving stdout and --json unchanged. Refs #2646 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
experimental_BridgeMissingExecutableError is a new published surface, so a plugin that throws it needs a version to point engines.bbPluginSdk at. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ymichael
force-pushed
the
bb/investigate-when-the-error-appears-thr_4pah43dksr
branch
from
September 23, 2026 18:47
c14e02d to
4b90c1c
Compare
This branch has not been deployed
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.
Human comments
What was wrong
The model picker had one sentence for every way a catalog can fail. A machine that was asleep and a Codex CLI that was never installed both rendered exactly
Could not load models for Codex.— byte-identical panels for problems with opposite fixes. Two causes: the server threw away the host daemon'serrorMessagewhen recording a catalog failure, and a missing CLI never reached themissing_executablecode that already exists, because the codex and claude-code bridges replace the spawnENOENTwith prose guidance before rejecting, which defeats the daemon's/ENOENT/ + /spawn/message classification (apps/host-daemon/src/command-dispatch-support.ts). Everything landed in the catch-allfailed. #2646 is this in the wild: reporters had the Codex desktop app and no CLI, and a maintainer had to tell them so by hand.Where the panel appears also differs by provider — it only renders with an empty model list, so Claude Code's declared fallback catalog usually hides it while Codex, which declares none, always lands there.
What changed
Contract.
systemExecutionOptionsModelLoadErrorSchemagainsdetail: string | null(packages/server-contract/src/api/system.ts). No daemon wire change:errorMessagealready exists on the host RPC response, soHOST_DAEMON_PROTOCOL_VERSIONis unchanged.Server.
toProviderModelCatalogFailureDetailfills it fromApiError.body.messageonly — whitespace-collapsed, capped at 300 chars — and returnsnullfor anything else, matchingerrorToResponse's refusal to leak non-ApiErrormessages. The catalog store records the detail beside each failure code, includes it inpickerViewso a changed message still pushes, and retains the message from a host that dropped mid-refresh (that path records no sticky failure and previously served a barefailed).Copy. The two lines now have separate jobs. Line one always states what failed; line two states why, in a short phrase:
CLI not found,Not signed in,Timed out,Provider plugin failed to load, or the host's own words forfailed. The install URL moves onto the reason line. Full host text stays on the tooltip, inbb provider models, and in the503details.Bridge contract (new).
BRIDGE_JSON_RPC_ERRORS.MISSING_EXECUTABLE(-32004) andexperimental_BridgeMissingExecutableError, whichrunBridgeRequestmaps to that code; the daemon reports it asmissing_executablewithout reading the message. Emitted from the codex bridge'smodel/listand the claude-code catalog probe — scoped to catalog paths, since a turn failure wants the fuller sentence and a different code there would shift unrelated failure copy. The ACP bridge already rejects with the rawENOENTand is unchanged. Documented indocs/provider-bridge-protocol.md; audit entry indocs/api_to_audit.md(open question: whether this eventually folds intoBridgeRecoveryErroras anotInstalledkind — that audit deliberately deferred an installation kind, and this answers classification rather than runtime action).CLI.
bb provider modelsignoredmodelLoadErrorentirely and printedNo models available. It now reports provider, code, and detail on stderr; stdout and--jsonare unchanged. Guide and skill references updated.How you verified
pnpm exec turbo run typecheck— 101/101. Tests, serially, all green:@bb/app(5019),@bb/server(3087),@bb/host-daemon(742),@bb/cli(842),@get-bb/plugin-sdk(354),@bb/provider-bridge-protocol(284),bb-plugin-provider-codex(325),bb-plugin-provider-claude-code(365),@bb/templates(47). The workflows plugin is untouched and still passes (248): its localmodelLoadErrortype accepts the added field unchanged.Tests that fail before this change:
apps/host-daemon/src/command-dispatch-support.test.ts— -32004 classifies asmissing_executable, and the same message underBRIDGE_ERRORstill does not.plugins/provider-codex/src/bridge/bridge.model-list.test.ts—model/listrejects withMISSING_EXECUTABLEwhen the app-server binary is absent.plugins/provider-claude-code/src/bridge/missing-cli-error.test.ts— the catalog probe error is typed; the session-start path is deliberately left untyped.apps/app/src/components/pickers/ModelReasoningPicker.test.tsx—CLI not foundrenders as the install link with the prose suppressed; a genericfailedshows the host detail; tooltip carries both lines.apps/server/test/providers/provider-model-catalog-store.test.ts— detail survives a sticky failure, a host that drops mid-refresh reportsHost is not connected, and a long message is collapsed and truncated to 300 chars.Fourteen existing server assertions were updated, each now receiving a real diagnostic (
Host is suspended,Cursor agent is not authenticated.,Local host daemon is not initialized), which is the cross-provider evidence that this is not Codex-specific.Visual states are a committed Ladle harness,
apps/app/src/components/pickers/ModelLoadErrorStates.stories.tsx:pnpm exec turbo run storybook --filter=@bb/app, then pickers → Model Load Error States. End-to-end manual check for the missing CLI:BB_CODEX_BRIDGE_APP_SERVER_COMMAND=/nonexistent pnpm start:worktree, open the model picker on Codex.Two pre-existing conditions, unrelated and not touched:
packages/server-contract/test/payload-size.test.tsasserts exact gzip byte counts and fails locally by 1–4 bytes with identicaljsonBytes(confirmed failing on5eb11ffwith this change reverted — a local zlib difference), andapps/app/src/components/plugin/management/BrowsePluginsTab.test.tsxflakes on toast timing under load.Refs #2646 — this does not make Codex models load; it makes the reason visible and actionable in-product, which is what that thread needed a maintainer to supply by hand. Leaving the issue open for whoever wants the picker to offer installation directly.
🤖 Generated with Claude Code