Repository navigation
Commit d46f36a
feat(ui-web): split model providers from model settings, one picker (#565)
## Summary
The settings dialog's Model page answered two questions at once -- which
accounts this install holds, and which model each job runs on -- and it
listed the connected providers only, so the fifty-odd vendors Raven
supports were reachable through a dropdown inside an "add" form and
nowhere else. This splits the page in two, gives every model a kind, and
merges the two model pickers into one.
**Model providers** is a two-column page. The left column is every
provider `model.options` returns (fifty-five on a stock registry,
`hosted_vllm` and `custom` among them) with a search box and six filters
-- connected, direct vendors, aggregators, browser sign-in, local --
connected rows first and each carrying its vendor mark. The right column
is that provider's connection, beside the list rather than paged into.
**Model settings** keeps the roles card alone, and each of its eleven
slots offers its own kind: the embedding slot lists embedding models,
image lists image models, and a chat model appears in neither.
**Adding a model** is a popover under its button. It fetches the
vendor's list, groups a gateway's ids by vendor, counts the kinds
present over the current search result and filters to the one pressed,
and writes one model per click rather than collecting ticks for a
confirming press. An id the vendor does not list is typed into the same
box with a chip saying what kind it is.
**One picker.** `components/ModelPicker` (164 lines, the roles card's)
is deleted; the roles card opens the composer's. What an opening lists
is now an `Offer`: a kind, the providers the caller allows, a title, the
pair it marks, and what a pick means.
### Two decisions worth reading
**The kind narrows each provider's column, never the provider list.** A
tester reported that a provider with a working key but no model list
built vanished from the composer's picker, and the model the chip named
-- set by onboarding, never "added" -- was in no column to be marked. So
a provider with nothing of the offered kind is listed with a count of
zero and a column that says so plus a row to type an id into; and the
model a slot or the conversation currently holds is listed in its
provider's column even when that column does not carry it. Verified on a
real host: with `agents.defaults.model` set to an id absent from
`providers.deepseek.models`, the picker opens on DeepSeek and lists it
first, marked, and writes nothing.
**One classifier, in Python.** `registry_data.kind_of` files a model by
what it writes, and `ModelLabel.kind` carries that answer to the page;
nothing in TypeScript derives a kind from capabilities or modalities.
The one exception is the chip on a typed id, which guesses from the name
-- a translation of `inferred_tags`, with a nine-row table asserted on
both sides so the copy cannot drift.
### Backend
Two read-only, additive fields on `model.options`: `ModelLabel.kind` and
`ModelOptionProvider.gateway` (the registry's `is_gateway`, which no
client can derive from a slug). No new method, no new config key.
Contract first: `openrpc.json`, then pydantic, then the handlers, then
`npm run gen`.
### Not in this change
The three navigation entries the prototype also adds (channels, cron,
memory); the prototype's OAuth pane, which tells the reader to run a CLI
command -- the browser device flow stays; backend enforcement of kinds,
which remains a filter the page applies; the onboarding wizard, which
keeps rendering `providers/Providers.tsx` untouched; the TUI.
## Type
- [ ] Fix
- [x] Feature
- [ ] Docs
- [ ] CI / tooling
- [ ] Refactor
- [ ] Other
## Verification
Rebased onto `refactor/ui_web_architecture` at 6062b36 and re-run
after the rebase.
```
uv run pytest tests/test_rpc_model.py tests/test_provider_registry_data.py tests/test_rpc_schema_match.py -q
630 passed in 12.44s
(cd ui-web && npx vitest run)
Test Files 186 passed (186)
Tests 2552 passed (2552)
(cd ui-web && npx tsc --noEmit && npm run gen:check && npm run build && python3 build.py)
generated.ts matches the contract (189 methods)
boot-snapshot: OK (250 nodes match golden)
boot-snapshot: OK (251 nodes match golden)
make check-source-language; make check-large-files; npm run lint:i18n --prefix ui-tui
i18n: generated catalogue is up to date
uv run ruff check raven tests
All checks passed!
```
Mutation checks on the two new backend fields: commenting out the
`"gateway"` line fails `test_options_rows_carry_the_gateway_flag` on
`KeyError: 'gateway'`; commenting out the `"kind"` key fails
`test_model_labels_carry_a_kind` on `KeyError: 'kind'`. Restored, `git
diff` clean.
Driven on a real host (`raven serve` on its own home and port 18899,
real keys for DeepSeek / OpenRouter / Gemini, a real browser):
- Model providers draws 55 rows in two columns of 286px and 462px, the
three connected ones first with a status dot, DeepSeek carrying the
default badge, 54 vendor marks and one lettered tile (`custom`).
- The embedding slot's picker lists all three connected providers with
counts 1 / 0 / 0 and exactly one model. It is at the body, not inside
the dialog, at z-index 46 over the veil's 40.
- The add-model popover against OpenRouter's live catalogue: 534 models,
kind tabs reading all 534 / text 445 / image 52 / embedding 33 / audio
4, five vendor groups, the four seeded models checked. Typing
`my-team/bge-custom` offers it with an "embedding" chip, which is what
`inferred_tags` answers for that name.
- The composer's chip lists the same three providers with OpenRouter
counted 1: its embedding, reranker and image models are not offered for
chat.
- [x] Relevant tests pass locally
- [x] Relevant lint / type checks pass locally
- [ ] User-facing docs or screenshots are updated when needed
## Risk
Composer users see two changes: embedding and reranker models leave the
model chip's picker, and typing an id there now adds it to the provider
before switching. Settings users learn two navigation entries where
there was one; `settingsTab.id` values written elsewhere still land on a
model page, since the roles page keeps the id `model`.
A model the registry classifies wrongly -- an embedding model with no
`embedding` tag whose name the two patterns miss -- is invisible to the
embedding slot until an overlay states its kind. The add-model popover's
chip is the way to state it.
Rollback: the two wire fields are additive and optional on the reader's
side; the section split is a data change in `SECTIONS`; the deleted
picker is one `git revert` away.
One gate pin moved: `fixture-shape`'s `UNSENT` list loses its six
`model_labels` entries, because the offline fixtures now send them (a
page that filters by kind needs a kind offline too). The gate's own
message asks for exactly this.
- [x] Security impact considered
- [x] Backward compatibility considered
- [x] Rollback path is clear for risky changes
## Related Issues
N/A
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent 333e689 commit d46f36a
51 files changed
Lines changed: 3729 additions & 385 deletions
File tree
- docs
- plans
- specs
- i18n
- raven/rpc
- methods
- rpc-schema
- tests
- ui-tui/src
- i18n
- rpc
- ui-web
- scripts/gates
- src
- components
- features
- model
- __snapshots__
- settings
- pages
- providers
- lib
- rpc
- fixtures
- styles
- test
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3355 | 3355 | | |
3356 | 3356 | | |
3357 | 3357 | | |
| 3358 | + | |
| 3359 | + | |
| 3360 | + | |
| 3361 | + | |
3358 | 3362 | | |
3359 | 3363 | | |
3360 | 3364 | | |
| |||
6420 | 6424 | | |
6421 | 6425 | | |
6422 | 6426 | | |
6423 | | - | |
6424 | | - | |
| 6427 | + | |
| 6428 | + | |
| 6429 | + | |
| 6430 | + | |
| 6431 | + | |
| 6432 | + | |
6425 | 6433 | | |
6426 | 6434 | | |
6427 | 6435 | | |
| |||
6723 | 6731 | | |
6724 | 6732 | | |
6725 | 6733 | | |
| 6734 | + | |
| 6735 | + | |
| 6736 | + | |
| 6737 | + | |
6726 | 6738 | | |
6727 | 6739 | | |
6728 | 6740 | | |
| |||
6759 | 6771 | | |
6760 | 6772 | | |
6761 | 6773 | | |
| 6774 | + | |
| 6775 | + | |
| 6776 | + | |
| 6777 | + | |
| 6778 | + | |
| 6779 | + | |
| 6780 | + | |
| 6781 | + | |
| 6782 | + | |
| 6783 | + | |
| 6784 | + | |
| 6785 | + | |
6762 | 6786 | | |
6763 | 6787 | | |
6764 | 6788 | | |
| |||
6815 | 6839 | | |
6816 | 6840 | | |
6817 | 6841 | | |
| 6842 | + | |
| 6843 | + | |
| 6844 | + | |
| 6845 | + | |
| 6846 | + | |
| 6847 | + | |
| 6848 | + | |
| 6849 | + | |
6818 | 6850 | | |
6819 | 6851 | | |
6820 | 6852 | | |
6821 | 6853 | | |
| 6854 | + | |
| 6855 | + | |
| 6856 | + | |
| 6857 | + | |
| 6858 | + | |
| 6859 | + | |
| 6860 | + | |
| 6861 | + | |
| 6862 | + | |
| 6863 | + | |
| 6864 | + | |
| 6865 | + | |
6822 | 6866 | | |
6823 | 6867 | | |
6824 | 6868 | | |
| |||
7319 | 7363 | | |
7320 | 7364 | | |
7321 | 7365 | | |
| 7366 | + | |
| 7367 | + | |
| 7368 | + | |
| 7369 | + | |
7322 | 7370 | | |
7323 | 7371 | | |
7324 | 7372 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
| 246 | + | |
246 | 247 | | |
247 | 248 | | |
248 | 249 | | |
| |||
251 | 252 | | |
252 | 253 | | |
253 | 254 | | |
254 | | - | |
| 255 | + | |
255 | 256 | | |
256 | 257 | | |
257 | 258 | | |
| |||
397 | 398 | | |
398 | 399 | | |
399 | 400 | | |
| 401 | + | |
400 | 402 | | |
401 | 403 | | |
402 | 404 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1574 | 1574 | | |
1575 | 1575 | | |
1576 | 1576 | | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
1577 | 1580 | | |
1578 | 1581 | | |
1579 | 1582 | | |
| |||
1629 | 1632 | | |
1630 | 1633 | | |
1631 | 1634 | | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
1632 | 1639 | | |
1633 | 1640 | | |
1634 | 1641 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10875 | 10875 | | |
10876 | 10876 | | |
10877 | 10877 | | |
| 10878 | + | |
| 10879 | + | |
| 10880 | + | |
| 10881 | + | |
10878 | 10882 | | |
10879 | 10883 | | |
10880 | 10884 | | |
| |||
10968 | 10972 | | |
10969 | 10973 | | |
10970 | 10974 | | |
10971 | | - | |
| 10975 | + | |
| 10976 | + | |
10972 | 10977 | | |
10973 | 10978 | | |
10974 | 10979 | | |
| |||
10998 | 11003 | | |
10999 | 11004 | | |
11000 | 11005 | | |
| 11006 | + | |
| 11007 | + | |
| 11008 | + | |
| 11009 | + | |
| 11010 | + | |
| 11011 | + | |
| 11012 | + | |
| 11013 | + | |
| 11014 | + | |
| 11015 | + | |
| 11016 | + | |
| 11017 | + | |
11001 | 11018 | | |
11002 | 11019 | | |
11003 | 11020 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
17 | 25 | | |
18 | 26 | | |
19 | 27 | | |
| |||
430 | 438 | | |
431 | 439 | | |
432 | 440 | | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
141 | 141 | | |
142 | 142 | | |
143 | 143 | | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
144 | 168 | | |
145 | 169 | | |
146 | 170 | | |
| |||
1351 | 1375 | | |
1352 | 1376 | | |
1353 | 1377 | | |
1354 | | - | |
| 1378 | + | |
1355 | 1379 | | |
1356 | 1380 | | |
1357 | 1381 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
381 | 385 | | |
382 | 386 | | |
383 | 387 | | |
384 | 388 | | |
385 | 389 | | |
386 | 390 | | |
387 | 391 | | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
388 | 395 | | |
389 | 396 | | |
390 | 397 | | |
| |||
0 commit comments