Skip to content

fix(tui_rpc): stop a typed model id from keeping the wrong provider pinned - #256

Merged
0xKT merged 1 commit into
mainfrom
fix/model_switch_bare_id_ambiguous
Jul 31, 2026
Merged

fix(tui_rpc): stop a typed model id from keeping the wrong provider pinned#256
0xKT merged 1 commit into
mainfrom
fix/model_switch_bare_id_ambiguous

Conversation

@0xKT

@0xKT 0xKT commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Selecting anything from the model picker pins its provider, so by the time someone
types /model <name> there is almost always one pinned. A bare id matching no
provider's keywords is what a vendor Raven holds no spec for looks like, and the
pin was kept for it -- sending that provider's key to a different vendor, the
mis-routing the prefix rules exist to prevent. The prefixed form of the same id was
already handed back to auto-detection for exactly this reason; the bare form fell
through.

Refusing every such id would break the two cases where the pin was right: a user
who configured a spec-less vendor and typed one of its model names, and a local
deployment, whose server names whatever models it likes and holds no key to
mis-route. So the pin is asked to justify itself instead. Its own curated list
counts as evidence -- that is where a hand-added id sits, unprefixed -- and so does
the catalogue; prefixes are stripped before comparing, which covers every spelling
the sources use. With no evidence either way the switch is refused, naming the
qualified form to type, rather than a vendor being picked on the user's behalf.

An explicit provider is never second-guessed, so the picker's own path is
untouched.

Type

  • Fix
  • Feature
  • Docs
  • CI / tooling
  • Refactor
  • Other

Verification

uv run --all-extras pytest tests/ -q -p no:randomly
  5127 passed, 30 skipped, 13 deselected

uv run ruff check raven/ tests/    All checks passed
bash .claude/scripts/preflight_ci.sh   exit 0

Behaviour, driven through config.set end to end:

Typed Pinned Result
mistral-large-latest openai refused, config untouched
mistral-large-latest mistral pin kept (the catalogue lists it)
some-private-tune mistral, listed in its models pin kept
some-local-build ollama_chat pin kept
mistral/mistral-large-latest openai auto, unchanged
gpt-4o mistral openai, unchanged
any, with provider sent openai the sent provider, gate not reached

Each test was checked by breaking the code it covers and confirming it fails. One of
those runs found that the evidence check had two branches where one sufficed --
stripping the prefix already covers the spelling the second compared exactly -- so
the redundant branch is deleted rather than pinned.

  • Relevant tests pass locally
  • Relevant lint / type checks pass locally
  • User-facing docs or screenshots are updated when needed

Risk

/model <bare name> can now be refused where it previously switched. It is refused
only when nothing indicates the pinned provider serves that model, which is the
case where the switch silently used the wrong credentials; the message names the
qualified form to type instead. Typing a prefixed id, or picking from the picker,
behaves as before.

Rollback is the revert of this branch.

  • Security impact considered
  • Backward compatibility considered
  • Rollback path is clear for risky changes

Related Issues

N/A

…der pinned

Selecting anything from the model picker pins its provider, so by the time someone
types `/model <name>` there is almost always one. A bare id matching no provider's
keywords is what a vendor Raven holds no spec for looks like, and the pin was kept
for it -- sending that provider's key to a different vendor, the mis-routing the
prefix rules exist to prevent. The prefixed form of the same id was already handed
back to auto-detection for exactly this reason; the bare form was not.

Refusing every such id would have broken the two cases where the pin was right: a
user who configured a spec-less vendor and typed one of its model names, and a
local deployment, whose server names whatever models it likes and holds no key to
mis-route. So the pin is asked to justify itself instead. Its own curated list
counts as evidence -- that is where a hand-added id sits, unprefixed -- and so does
the catalogue. Prefixes are stripped before comparing, which covers every spelling
the sources use. With no evidence either way the switch is refused with the
qualified form to type, rather than a vendor picked on the user's behalf.

An explicit provider is never second-guessed, so the picker's own path is
untouched.

Co-authored-by: Claude (claude-opus-5[1m]) <noreply@anthropic.com>
@0xKT
0xKT requested a review from arelchan July 31, 2026 16:31
@0xKT
0xKT merged commit 13267f7 into main Jul 31, 2026
9 checks passed
@0xKT
0xKT deleted the fix/model_switch_bare_id_ambiguous branch July 31, 2026 16:39
@0xKT 0xKT mentioned this pull request Jul 31, 2026
12 tasks
0xKT added a commit that referenced this pull request Jul 31, 2026
## Summary

Bump the package version from 0.1.9 to 0.1.10 (patch release). 22 PRs
merged since v0.1.9, no breaking changes.

Features:

- #260 feat(tui): list the providers that work, and the rest one level
down
- #252 feat(*): offer every supported provider in the onboarding picker
- #251 feat(tools): read images with read_file, and fix four silent
type-check bugs
- #239 feat: add shell command approval flow
- #217 feat: rework the TUI transcript into collapsible episodes
- #220 feat(cli): nudge raven upgrade in the tui status bar when behind
- #209 feat(providers): add MiniMax Global and CN OAuth

Refactors:

- #259 refactor(*): one answer to which credentials a provider needs
- #249 refactor(providers): unify provider management on litellm

The remaining PRs are fixes (#255, #256, #258, #253, #238, #226), test
work (#236, #230, #224), docs (#250, #215, #200), and benchmark tooling
(#207).

## Type

- [ ] Fix
- [ ] Feature
- [ ] Docs
- [ ] CI / tooling
- [ ] Refactor
- [x] Other

## Verification

- [x] Relevant tests pass locally
- [x] Relevant lint / type checks pass locally
- [ ] User-facing docs or screenshots are updated when needed

Bump is limited to `pyproject.toml` and `uv.lock` (`uv lock` sync).
Local preflight covers the branch CI checks (commit lint, PR title and
body lint, ruff, large-file gate).

## Risk

- [x] Security impact considered
- [x] Backward compatibility considered
- [x] Rollback path is clear for risky changes

Version-only change; no code or behavior change. Rollback is a revert of
this commit.

## Related Issues

N/A

Co-authored-by: Claude (claude-opus-5[1m]) <noreply@anthropic.com>
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.

2 participants