Skip to content

[multi-team P3c] Move LLMPreferences off its flat catalog onto Team/Workspace - #15567

Merged
tylerlam-warp merged 17 commits into
masterfrom
factory/multi-team-pr3c-move-llm-preferences
Aug 27, 2026
Merged

[multi-team P3c] Move LLMPreferences off its flat catalog onto Team/Workspace#15567
tylerlam-warp merged 17 commits into
masterfrom
factory/multi-team-pr3c-move-llm-preferences

Conversation

@warp-agent-staging

Copy link
Copy Markdown
Contributor

Description

Stacked on #15565 (PR 2), which is stacked on #15463 (PR 1). This is the third and final PR of the stack: it deletes LLMPreferences's flat, non-team-aware models_by_feature field and its MODELS_BY_FEATURE_CACHE_KEY read/write, and the old WorkspacesMetadataResponse.feature_model_choices field PR 1 deliberately left alone. Every accessor now reads through UserWorkspaces instead, resolved against a caller-supplied TeamScope (or a raw team uid).

  • UserWorkspaces gains feature_model_choice_for_scope/_for_team_uid (reads, via the same scoped_or_workspace_setting pattern every other team-scoped setting uses; the absent/no-workspace-at-all case falls back to the resolved-teamless pre_login_models_by_feature seeded by PR 1/PR 2's migration or a pre-login fetch) and set_feature_model_choice_for_team_uid (the narrow one-off authed-refresh write path).
  • get_llm_info/_for_team_uid/_for_scope, get_active_base_model, and the various choice/default getters gained an app/ctx parameter and a TeamScope parameter accordingly, with the ~85 call sites across the app updated: terminal/, settings_view/, ai/blocklist/, ai/agent_sdk/, pane_group/, search/, workspace/, and crates/warp_tui/.
  • Preserves the earlier review-round behavioral fixes carried since PR 1's first draft: teamless eager fetch for agent_mode_evals builds, refresh-through-workspace-metadata (not the unscoped get_feature_model_choices) for blocklist triggers, cross-team get_llm_info display lookups, and stale-bucket eviction (implied by the wholesale Team/Workspace replacement on every response).

This is the bulk of the three-PR stack by line count, but every design decision here — the storage shape, the legacy-cache conversion — was already reviewed in PR 1 and PR 2; this should read as fan-out from those two, not new design.

Note on ancestry

This branch's only ancestors beyond master are PR 1's and PR 2's commits — verified with git merge-base --is-ancestor in both directions before pushing, since a three-deep stack is easy to get backwards.

Testing

Since this branch is stacked on a non-default base, it does not get a real CI matrix in this repo (only PR 1 does); all of the below was run locally on this exact branch tip:

  • cargo check --workspace --all-targets — clean.
  • cargo clippy -p warp --lib --tests -- -D warnings — clean.
  • ./script/format — clean (2 files needed reformatting, included).
  • ./script/bundle --channel oss --nouniversal --check-only — clean.
  • cargo clippy --locked --target wasm32-unknown-unknown --profile release-wasm-debug_assertions -- -D warnings — clean (no dead-code-on-wasm surprises from the call-site fan-out).
  • cargo nextest run -p warp -E 'test(llms) or test(execution_profile) or test(update_manager) or test(gql_convert) or test(user_workspaces) or test(profile_model_selector) or test(agent_profiles_page) or test(legacy_cache)' — 262 passed.
  • cargo nextest run --workspace -E 'package(warp_tui) and (test(terminal_session_view) or test(model_menu))' — 187 passed.
  • No UI surface changed; this is a data-layer change, so no screenshots.

Linked Issue

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

Adds Team.feature_model_choice and Workspace.feature_model_choice,
sourced from the server's per-team/workspace Team.featureModelChoice
(new teams[].featureModelChoice query field, schema mirror line) and
the existing Workspace.featureModelChoice, via gql_convert's new
feature_model_choice_from_gql. Persisted through new
feature_model_choice_json sqlite columns (migration included) so the
warm-start cache round-trips it too.

Nothing reads this yet -- LLMPreferences keeps master's flat
models_by_feature and behaves exactly as today. This PR is inert by
design: dead data plus a conversion test
(team_feature_model_choices_conversion_keeps_each_teams_choice_distinct)
proving each team keeps its own payload through the fold.
Seeds Team/Workspace.feature_model_choice from the legacy,
pre-team-keyed MODELS_BY_FEATURE_CACHE_KEY cache as a one-release
migration in UserWorkspaces::new: a Workspace restored from the
SQLite cache predates the feature_model_choice column (or the app
hasn't fetched since upgrading), so its catalog is still the bare
default, and this seeds it from the last-known model list instead so
an offline launch right after upgrading isn't stuck on just the auto
default for the rest of the offline session.

migrate_legacy_feature_model_choices_cache understands both real
shapes an older client could have written: the (more recent) single
ModelsByFeature, and (older still) a bare AvailableLLMs, which
becomes the agent_mode field.

Still nothing reads Team/Workspace.feature_model_choice for model
selection -- LLMPreferences keeps master's flat models_by_feature.
legacy_cache_migration_yields_a_usable_teamless_catalog proves the
older bare-AvailableLLMs shape migrates to a catalog whose agent_mode
bucket resolves the cached model.
Deletes LLMPreferences's flat, non-team-aware models_by_feature field
and its MODELS_BY_FEATURE_CACHE_KEY read/write, and the old
WorkspacesMetadataResponse.feature_model_choices field PR 1 left
alone. Every accessor now reads through UserWorkspaces instead,
resolved against a caller-supplied TeamScope (or a raw team uid):

- UserWorkspaces gains feature_model_choice_for_scope/_for_team_uid
  (reads, via the same scoped_or_workspace_setting pattern every
  other team-scoped setting uses; the absent/no-workspace-at-all case
  falls back to the resolved-teamless `pre_login_models_by_feature`
  seeded by PR 1/PR 2's migration or a pre-login fetch) and
  set_feature_model_choice_for_team_uid (the narrow one-off
  authed-refresh write path).
- get_llm_info/_for_team_uid/_for_scope, get_active_base_model, and
  the various choice/default getters gained an app/ctx parameter and
  a TeamScope parameter accordingly, with the ~85 call sites across
  the app updated: terminal/, settings_view/, ai/blocklist/,
  ai/agent_sdk/, pane_group/, search/, workspace/, and
  crates/warp_tui/.
- Preserves the earlier review-round behavioral fixes carried since
  PR 1's first draft: teamless eager fetch for agent_mode_evals
  builds, refresh-through-workspace-metadata (not the unscoped
  get_feature_model_choices) for blocklist triggers, cross-team
  get_llm_info display lookups, and stale-bucket eviction (implied by
  the wholesale Team/Workspace replacement on every response).

This is the bulk of the three-PR stack, but every design decision
here -- the storage shape, the legacy-cache conversion -- was already
reviewed in PR 1 (#15463) and PR 2 (#15565); this should read as fan-out
from those two, not new design.
oz-agent and others added 2 commits August 26, 2026 11:51
… home (#15565)

## Description
Stacked on #15463 (PR 1 of the three-PR stack — "Parse and store the
team catalog into UserWorkspaces"). PR 1 added
`Team`/`Workspace.feature_model_choice` but nothing populates it for a
user restored from a pre-upgrade SQLite cache. PR 3 (to follow, stacked
on this branch) moves `LLMPreferences` off its flat catalog onto these
fields; this PR makes sure a warm-started, pre-upgrade cache has
something real to read once that happens.

Seeds `Team`/`Workspace.feature_model_choice` from the legacy,
pre-team-keyed `MODELS_BY_FEATURE_CACHE_KEY` cache as a one-release
migration in `UserWorkspaces::new`: a `Workspace` restored from the
SQLite cache predates the `feature_model_choice` column (or the app
hasn't fetched since upgrading), so its catalog is still the bare
default. This seeds it from the last-known model list instead, so an
offline launch right after upgrading isn't stuck on just the `auto`
default for the rest of the offline session.

`migrate_legacy_feature_model_choices_cache` understands both real
shapes an older client could have written: the (more recent) single
`ModelsByFeature`, and (older still) a bare `AvailableLLMs`, which
becomes the `agent_mode` field.

Still nothing reads `Team`/`Workspace.feature_model_choice` for model
selection — `LLMPreferences` keeps master's flat `models_by_feature`.
`legacy_cache_migration_yields_a_usable_teamless_catalog` proves the
older bare-`AvailableLLMs` shape migrates to a catalog whose
`agent_mode` bucket resolves the cached model.

## Testing
- `cargo check --workspace --all-targets` — clean.
- `cargo clippy -p warp --lib --tests -- -D warnings` — clean.
- `./script/format` — clean.
- `./script/bundle --channel oss --nouniversal --check-only` — clean.
- `cargo clippy --locked --target wasm32-unknown-unknown --profile
release-wasm-debug_assertions -- -D warnings` — clean.
- `cargo nextest run -p warp -E 'test(user_workspaces) or
test(legacy_cache) or test(gql_convert)'` — 107 passed.
- No UI surface changed; this is a data-layer change, so no screenshots.
- This branch is stacked on a non-default base, so it does not get a
real CI matrix in this repo; the above was run locally on this exact
branch tip.

## Linked Issue
- [x] N/A — stacked continuation of #15463.

## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode

---------

Co-authored-by: warp-agent-staging[bot] <240773466+warp-agent-staging[bot]@users.noreply.github.com>
Co-authored-by: Oz <oz-agent@warp.dev>
Base automatically changed from factory/multi-team-pr3b-legacy-cache-conversion to factory/multi-team-pr3a-catalog-team-scope August 26, 2026 16:38
…team-scope' into pr3-work

# Conflicts:
#	app/src/workspaces/gql_convert.rs
#	app/src/workspaces/user_workspaces/mod.rs
Base automatically changed from factory/multi-team-pr3a-catalog-team-scope to master August 26, 2026 17:17
# Conflicts:
#	app/src/workspaces/user_workspaces/mod.rs
#	app/src/workspaces/user_workspaces/user_workspaces_tests.rs
tylerlam-warp and others added 6 commits August 26, 2026 15:15
Strip the narration-style comments this PR introduced, restoring the
pre-existing doc text where a comment had merely been reworded.

Co-Authored-By: Warp <agent@warp.dev>
BlocklistAIContextModel and TuiAttachmentModel now resolve their team
scope through the existing UserWorkspaces::team_context_resolver rather
than a duplicated window-id resolver gadget.

Co-Authored-By: Warp <agent@warp.dev>
Drops the constructor generics on BlocklistAIContextModel::new and
TuiAttachmentModel::new; callers build the resolver where the concrete
view type is already known.

Co-Authored-By: Warp <agent@warp.dev>
The field holds the fallback model catalog whenever no current workspace
exists, which includes logged-in users whose only workspace is the
filtered-out server placeholder — not just the pre-login state.

Co-Authored-By: Warp <agent@warp.dev>
Team-scoped settings (including per-team model choices) were only as
fresh as the periodic metadata poll, so switching teams could show up
to ~10 minutes of stale data. Kick off an out-of-band metadata refresh
from the GUI team-switcher action and the TUI team menu switch path.

Co-Authored-By: Warp <agent@warp.dev>
…pr3c-move-llm-preferences

# Conflicts:
#	app/src/ai/llms_tests.rs
#	app/src/workspaces/user_workspaces/team_workspace_settings.rs
@tylerlam-warp
tylerlam-warp enabled auto-merge (squash) August 27, 2026 03:14
@tylerlam-warp
tylerlam-warp merged commit ba9bcd3 into master Aug 27, 2026
26 checks passed
@tylerlam-warp
tylerlam-warp deleted the factory/multi-team-pr3c-move-llm-preferences branch August 27, 2026 03:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants