Skip to content

feat(tui): cross-field search in model + provider pickers (#4141)#4218

Merged
Hmbown merged 1 commit into
mainfrom
codex/v0868-fix-4141
Jul 8, 2026
Merged

feat(tui): cross-field search in model + provider pickers (#4141)#4218
Hmbown merged 1 commit into
mainfrom
codex/v0868-fix-4141

Conversation

@Hmbown

@Hmbown Hmbown commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Fixes #4141

Summary

Completes cross-field search across provider name, display model name, and wire model id in both the model picker and the provider picker, so the two pickers behave consistently.

What now matches

  • Model picker (model_row_matches_query): already matched the provider key, the provider display name, and row.id — which in the model picker is both the displayed model name and the id sent to the provider (its wire id). Made case handling consistent with the provider picker by lowercasing the provider key before comparing (everything else was already to_ascii_lowercase() + substring).
  • Provider picker (ProviderDashboardRow::matches_query): now also searches the default route's display model name (logical_model) and wire model id (wire_model), in addition to the existing provider name / id / kind / base URL / provider key. This means a model name or wire id now surfaces the provider that serves it — aligning the code with its own doc comment ("the compact hint fields") and with the model picker.

Consistency

Both matchers use identical semantics: trim, to_ascii_lowercase(), case-insensitive substring across the relevant fields. A query that matches a provider name / model name / wire id in one picker matches the analogous field in the other.

Acceptance criteria

  • Search matches provider name, display model name, and wire model id.
  • Search behavior is consistent between the provider and model pickers.
  • Disclosure stays trimmed/readable in dense/narrow layouts — only the matching logic changed; rendering/truncation is untouched (existing narrow_picker_rows_hide_hint_before_clipping_model_id stays green).

Tests

  • model_row_query_matches_provider_name — matches by provider key and display name.
  • model_row_query_matches_display_model_name — matches by the displayed model name.
  • model_row_query_matches_wire_model_id — matches by the full wire id.
  • model_row_query_no_field_match_returns_false + picker_query_by_wire_id_surfaces_cross_provider_row_and_hides_others — a non-matching query returns no rows; a model-name query surfaces the serving provider's route.
  • provider_row_query_matches_default_route_model_and_wire_id — the provider picker now matches its route model/wire id (consistency lock).

Verification

cargo build -p codewhale-tui --locked, cargo test -p codewhale-tui --all-features --locked, cargo fmt --all -- --check, cargo clippy --workspace --all-features --locked -- -D warnings ..., cargo test --workspace --all-features --locked, and cargo build --release all pass. The only failing test is the known pre-existing skill_hotbar_action_* env/skill-cache flake.

Guards respected: no module/struct/fn renames, no DEEPSEEK* env changes, no provider/model inference, no provider privileging, no crates/config edits — TUI-only.

Generated with Claude Code

…4141)

Complete cross-field search across provider name, display model name, and
wire model id in both the model and provider pickers so they behave
consistently (Fixes #4141).

- model_picker: model_row_matches_query already matched the provider key,
  provider display name, and the model id (which is both the displayed name
  and the wire id). Made case handling consistent with the provider picker
  by lowercasing the provider key before matching.
- provider_picker: matches_query now also searches the default route's
  display model name (logical_model) and wire model id (wire_model), so a
  model name or wire id surfaces the provider that serves it. This aligns
  the code with its existing doc comment and with the model picker.

Rendering/truncation is untouched, so dense/narrow disclosure stays trimmed.

Tests: focused cases proving the model picker matches by provider name,
display model name, and wire model id, and that a non-matching query returns
no rows; plus a provider-picker test proving route model/wire-id matching.

Implemented with agent assistance.
Copilot AI review requested due to automatic review settings July 8, 2026 08:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown

Claude finished @Hmbown's task in 2m 30s —— View job


Reviewing PR #4218

  • Gather context (diff, files)
  • Review model_picker.rs changes
  • Review provider_picker.rs changes
  • Check provider/model/route safety invariant
  • Check tests
  • Post final review

Summary

Reviewed the diff (git show HEAD vs the single-commit parent, equivalent to origin/main at branch point — 105/+1 in model_picker.rs, 45/+2 in provider_picker.rs, matching the stated 150/3). This is a clean, focused change with no correctness issues found.

Correctness

  • model_row_matches_query (crates/tui/src/tui/model_picker.rs:685-705): the only functional change is provider.as_str().to_ascii_lowercase() — a defensive no-op today (provider keys are already lowercase) that guards against future non-lowercase provider keys and matches the provider picker's semantics. No logic errors, no panics — plain &str/String comparisons, no unwrap/expect introduced.
  • ProviderDashboardRow::matches_query (crates/tui/src/tui/provider_picker.rs:604-624): adds default_route.logical_model / default_route.wire_model to the existing OR-chain. default_route is a plain (non-Option) field on every ProviderDashboardRow, so there's no new panic surface, and placeholder values like "unresolved"/"invalid" (used when a route can't be resolved) are already shown in the UI elsewhere, so surfacing them via search isn't a new information leak — just a minor cosmetic edge case (e.g. typing "invalid" could match a broken route), not worth blocking on.
  • Both matchers agree on semantics (trim → to_ascii_lowercase() → substring), so behavior between the two pickers is now genuinely consistent, as claimed.

Provider/model/route safety (v0.8.65 EPIC #2608 invariant)

  • No violation. This only changes what rows are visible in the picker UI based on a case-insensitive substring match; it does not infer or auto-select a provider/model from a wire-id prefix or free text. Selection still requires the explicit user action of choosing a row.

Reuse/simplification

  • Minor, non-blocking: the trim/lowercase/substring pattern is now duplicated across model_row_matches_query and ProviderDashboardRow::matches_query. This mirrors the pre-existing structure (the two row types are different, and the PR explicitly aims for parallel-but-independent implementations), so not flagging it as a required change.

Tests

  • Good coverage: provider-name, display-model-name, wire-model-id, and negative-match cases for the model picker, plus a cross-provider surfacing test (picker_query_by_wire_id_surfaces_cross_provider_row_and_hides_others) and a consistency-lock test for the provider picker. Verified the test helpers used (create_test_app, type_model_query, visible_model_rows, update_query) and the ProvidersConfig/ProviderConfig construction pattern in the new test all already exist and match existing usage elsewhere in the file.

Security

  • No secret handling, shell/exec, or input-validation concerns — pure string search over already-rendered UI fields.

Note on verification: I was unable to run cargo test/cargo build/cargo clippy in this sandbox — cargo/git fetch invocations required approval that wasn't available in this session. Verification here is based on static reading of the diff, cross-referencing struct/field definitions, and the PR's own reported command outputs. If you'd like actual CI-run confirmation, the existing GitHub Actions run is the authoritative source.

No blocking issues found. Nice work keeping the two pickers' search semantics aligned.

@Hmbown Hmbown merged commit a9703fb into main Jul 8, 2026
19 checks passed
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.

v0.8.68 3.3: add cross-field search to both provider and model pickers

2 participants