Skip to content

feat(tui): scoped-models allowlist for Ctrl+P / cycle_model (#26)#200

Merged
quangdang46 merged 1 commit into
masterfrom
feat/scoped-models-allowlist
May 22, 2026
Merged

feat(tui): scoped-models allowlist for Ctrl+P / cycle_model (#26)#200
quangdang46 merged 1 commit into
masterfrom
feat/scoped-models-allowlist

Conversation

@quangdang46
Copy link
Copy Markdown
Owner

What

Adds the user-defined scoped-models allowlist requested in issue #26. Users can now restrict model cycling to a curated list (sonnet:highgpt-5-codex, etc.) instead of cycling through every available model.

Resolution order

  1. --models <pat,pat,pat> CLI flag → JCODE_SCOPED_MODELS env
  2. provider.scoped_models config (~/.jcode/config.toml)
  3. Empty → falls back to provider.available_models_for_switching() (existing behavior, bit-for-bit preserved)

Patterns match by case-insensitive substring or by shell-style glob (* and ?). Filter output preserves the allowlist's order so flips are deterministic across cycles.

When the allowlist matches zero available models, cycle_model surfaces a clear error mentioning the configured patterns instead of silently falling back to the unscoped list.

Changes

  • src/scoped_models.rs (new): resolve_allowlist + filter_by_allowlist + tiny iterative-DP glob matcher. Avoids pulling a glob crate.
  • src/lib.rs: register the new pub mod.
  • crates/jcode-config-types: provider.scoped_models: Vec<String> with default [].
  • src/cli/args.rs: --models <patterns> with value_delimiter = ','.
  • src/cli/startup.rs: parse_and_prepare_args translates the flag into JCODE_SCOPED_MODELS so deep code paths read it without arg threading.
  • src/tui/app/model_context.rs: cycle_model applies the allowlist filter before computing next_index; empty-after-filter prints a helpful error instead of falling back.

Tests

$ cargo test -p jcode --lib scoped_models
test result: ok. 7 passed; 0 failed

Notes / scope deviation from issue text

The Ctrl+P / Shift+Ctrl+P keybinding rebind from auto-poke (the issue's recommendation) is intentionally NOT applied here — that is a keybinding-policy decision worth its own PR. cycle_model itself is already callable from any binding, so this PR is fully usable today via /model-cycle (existing) plus --models.

Closes #26

Adds the user-defined scoped-models allowlist requested in issue #26.

Resolution order:
  1. --models <pat,pat,pat> CLI flag => JCODE_SCOPED_MODELS env
  2. provider.scoped_models config (~/.jcode/config.toml)
  3. Empty -> falls back to provider.available_models_for_switching()
     (existing behavior, bit-for-bit preserved)

Patterns match by case-insensitive substring or by shell-style glob
(* and ?). The first non-empty match anywhere in the model id counts.
Filter output preserves the allowlist's order so flips are deterministic
across cycles.

When the allowlist matches zero available models, cycle_model surfaces
a clear error mentioning the configured patterns instead of silently
falling back to the unscoped list (which would be confusing).

Implementation:

- src/scoped_models.rs (new): resolve_allowlist + filter_by_allowlist
  + tiny iterative-DP glob matcher. Avoids pulling a glob crate.
- src/lib.rs: register the new pub mod.
- crates/jcode-config-types: provider.scoped_models: Vec<String>
  with default [].
- src/cli/args.rs: --models <patterns> with value_delimiter = ','.
- src/cli/startup.rs: parse_and_prepare_args translates the flag into
  JCODE_SCOPED_MODELS so deep code paths read it without arg threading.
- src/tui/app/model_context.rs: cycle_model applies the allowlist
  filter before computing next_index; empty-after-filter prints a
  helpful error instead of falling back.

7 unit tests in src/scoped_models.rs:
- empty_allowlist_returns_input_unchanged
- substring_pattern_matches_case_insensitively
- glob_pattern_matches
- dedup_preserves_first_pattern_match_order
- unmatched_patterns_are_silently_dropped
- parse_pattern_list_trims_and_drops_empty
- glob_match_question_mark_is_single_char

Note: the Ctrl+P / Shift+Ctrl+P keybinding rebind from auto-poke (the
issue's recommendation) is intentionally NOT applied here — that is a
keybinding-policy decision worth its own PR. cycle_model itself is
already callable from any binding, so this PR is fully usable today
via /model-cycle (existing) plus --models.

Closes #26
@quangdang46 quangdang46 merged commit f364db9 into master May 22, 2026
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.

/scoped-models + Ctrl+P / Shift+Ctrl+P: cycle models within a user-defined allowlist

1 participant