Skip to content

Add streamer mode to hide custom models from model lists - #2107

Merged
SawyerHood merged 3 commits into
mainfrom
bb/add-streamer-privacy-mode-thr_mnhu66t8wm
Aug 21, 2026
Merged

Add streamer mode to hide custom models from model lists#2107
SawyerHood merged 3 commits into
mainfrom
bb/add-streamer-privacy-mode-thr_mnhu66t8wm

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

What was wrong

bb had no way to hide the customModels entries from ~/.bb/config.json. A user with a private or early-access model id showed it in every model picker during a screen share or stream.

What changed

  • packages/domain/src/app-settings.ts: new streamerMode general setting, default false. The key/value settings table needs no migration, and bb settings general streamerMode <true|false> works with no CLI change.
  • apps/server/src/services/system/execution-options.ts: new listVisibleCustomModels(deps) returns [] when streamer mode is on. All three appendCustomModels call sites use it, so the web and mobile pickers, plugin pickers, bb provider models, and sdk.providers.models all hide the entries. The filter runs after the memoized daemon probe, so a toggle does not re-probe the host. An explicit thread model request bypasses the catalog, so a hidden model still runs when a caller names it.
  • apps/app/src/views/SettingsView.tsx: "Streamer mode" switch in Settings → General, plus story wiring.
  • apps/app/src/hooks/cache-owners/system-cache-effects.ts: a General settings write now also invalidates the execution options queries, so open pickers refetch at once.
  • apps/mobile/src/screens/settings/GeneralSettingsScreen.tsx: the same switch in a Privacy section.
  • Docs: docs/configuration.md, the bb guide customization template, and the bb-cli skill and its settings reference.

No HOST_DAEMON_PROTOCOL_VERSION bump. Nothing on the server ↔ daemon wire changed.

How you verified

  • New server test in apps/server/test/system/execution-options.test.ts: the catalog shows the custom model, streamer mode on hides it, streamer mode off restores it, and the daemon receives one provider.list_models call. With the filter removed it fails with expected [ 'claude-opus-5', …(1) ] to deeply equal [ 'claude-opus-5' ].
  • apps/app/src/hooks/mutations/settings-mutations.test.tsx now also asserts the execution options query is invalidated.
  • pnpm exec turbo run typecheck --filter=@bb/domain --filter=@bb/db --filter=@bb/server --filter=@bb/app --filter=@bb/mobile passes.
  • pnpm exec turbo run test for the settings, migration, CLI, SettingsView, and execution-options test files passes.
  • Manual end-to-end check in the dev app: see the follow-up comment.

Fixes #

AGENT GENERATED: by Claude Opus 5

Streamer mode is a new Settings → General preference. When it is on, the
server omits every config.json customModels entry from the execution
options catalog, so the web and mobile pickers, plugin pickers,
bb provider models, and sdk.providers.models all hide them.

Co-Authored-By: Claude <noreply@anthropic.com>
@SawyerHood
SawyerHood marked this pull request as ready for review August 20, 2026 23:46
@bb-slop-cop

bb-slop-cop Bot commented Aug 20, 2026

Copy link
Copy Markdown

🚨 SLOP COP 🚨 · review

I am the SlopCop. I am reviewing this pull request for security, code quality, performance, architecture, and the user path.

I will post one final review after the parallel checks finish.

deps.providerRegistry,
{
customModels: deps.config.customModels,
customModels: listVisibleCustomModels(deps),

@bb-slop-cop bb-slop-cop Bot Aug 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 slopcop/review — Streamer mode changes execution policy, not only model-list presentation.

This catalog also drives thread default resolution and sticky-model recovery. When this filter removes a stored custom model, the web and mobile clients select a catalog default and mark it as explicit. The server can then persist that replacement. A provider whose only usable model comes from customModels can also get an empty internal catalog. Keep the complete catalog for execution policy. Redact only the public presentation result.

systemConfigQueryKey(),
allThreadTimelineQueryKeyPrefix(),
allThreadTimelineTurnSummaryDetailsQueryKeyPrefix(),
allSystemExecutionOptionsQueryKeyPrefix(),

@bb-slop-cop bb-slop-cop Bot Aug 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 slopcop/review — Query invalidation does not immediately remove the hidden model data.

The active query and the persistent model-catalog cache keep complete custom model records until a successful refresh replaces them. A slow or failed refresh can still show the private name in the picker. Clear or partition this cache when streamer mode changes. Also mask a raw stored model during the hidden state.

This local invalidation also duplicates the config-changed realtime invalidation. The source window can send two execution-options requests and repeat provider health checks.

@bb-slop-cop bb-slop-cop Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 SLOP COP 🚨 · review

Plain-English summary: This adds a Streamer mode switch. It hides configured custom models from desktop, mobile, CLI, and SDK model lists.

The setting keeps each custom model in config.json. It only removes the model from returned catalogs.

Findings:

  1. High: Streamer mode changes execution policy. The filtered catalog also controls thread defaults and sticky-model recovery.

    A stored custom model can become the provider default after the next send. A custom-only provider can also lose its only default.

  2. Medium: The web cache can keep the private model visible. Query invalidation does not clear active data or the persistent model catalog.

    A slow or failed refresh can leave the old name in the picker. The raw stored model can also become the fallback label.

  3. Low: The source window can refetch execution options twice. The local invalidation duplicates the server's config-changed event.

    The second request can repeat provider health checks. The model-list memo limits the larger model probe cost.

  4. Low: The provider guide still says custom models always appear in the CLI and picker. It does not mention Streamer mode.

Architecture:

  • Keep one complete internal catalog for execution and validation.
  • Return a separate redacted catalog for public model lists.
  • Mask hidden selected models in both clients.
  • Clear or partition the browser model cache when Streamer mode changes.

Security: I found no new authentication or authorization issue. The privacy control has the client-state gaps described above.

Verification:

  • Three parallel GPT-5.6 agents reviewed security, code quality, architecture, duplication, and performance.
  • A final GPT-5.6 review gate confirmed the high and medium findings.
  • Doobie changed the real Settings switch in the local app.
  • A temporary custom model disappeared from the API when enabled and returned when disabled.
  • Turbo type checks passed for the app, server, mobile, domain, and database packages.
  • Focused worker tests passed: 36 server tests, 23 app tests, and 8 mobile tests.
  • git diff --check origin/main...HEAD passed.

Please fix the high and medium issues before merge. I posted this as a comment-only review.

- resolveSystemProviderModels keeps the full custom model list, so a
  thread created without an explicit model resolves the same default
  with streamer mode on, and a custom-only provider can still start.
- A streamer mode flip clears the localStorage model catalog preload and
  resets the execution-options queries instead of invalidating them, so
  no stale list can still name a hidden model while the refetch runs.
- Other General settings writes no longer refetch model catalogs; the
  server's config-changed broadcast already covers that.
- Provider guide and skill reference the setting; docs state the
  composer fallback behavior for a hidden stored selection.

Co-Authored-By: Claude <noreply@anthropic.com>
@SawyerHood

Copy link
Copy Markdown
Collaborator Author

SlopCop follow-up (e2e1a55)

  1. High — execution policy. Fixed in part, and one part is a stated trade-off.
    • resolveSystemProviderModels (the thread-create default path) now keeps the full custom model list. A thread created without an explicit model resolves the same default with streamer mode on, and a provider whose only models are custom can still start. New test: "keeps custom models in the thread-create default catalog while streamer mode is on".
    • The composer fallback stays as is. When the stored selection is a hidden model, the client treats it as unavailable, selects the provider default, and the next send records that default. The alternative is to keep the hidden selection and mask its label in both clients, but the picker is the only surface that shows a model name, and a masked "Hidden model" row would still signal a secret on stream. Hiding the model and moving to the default is the leak-free choice. The docs and the skill reference now state this behavior and tell the user to re-select the model after they turn streamer mode off.
  2. Medium — stale client catalog. Fixed. A streamer mode flip now clears the localStorage model catalog preload and resets the execution-options queries instead of invalidating them, so open pickers drop the old list and refetch. Test: "drops cached model catalogs when streamer mode flips".
  3. Low — duplicate refetch. Reduced. Other General settings writes no longer touch model catalogs; the config-changed broadcast covers them. The streamer flip itself still resets locally and then receives the broadcast, the same pattern the existing settings writes use for /system/config. The server memoizes the model probe, so the second request is cheap.
  4. Low — provider guide. Fixed. The providers chapter and the bb-cli skill's customModels entry now point at streamerMode.

AGENT GENERATED: by Claude Opus 5

Mutation files must not import query keys; the boundary test enforces it.

Co-Authored-By: Claude <noreply@anthropic.com>
@SawyerHood
SawyerHood merged commit 65f9e0a into main Aug 21, 2026
13 checks passed
@SawyerHood
SawyerHood deleted the bb/add-streamer-privacy-mode-thr_mnhu66t8wm branch August 21, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant