The console's Models & APIs tab regrouped onto the ledger's eight groups —
speech · fp · tool · kit · persona ·
photo · room · app — in the Usage & cost tab's order
and colours, so a figure on Usage ▸ By function and the knob that moves it are one hop apart.
Every leaf of the vocabulary gets a row, including the eleven that have no knob today.
main, not yet on the box.
The console's Models & APIs tab is this page's §2, for real: lib/admin.html
loadModels() renders the eight groups off U_GROUPS, the fixed seats come
from GET /api/admin/models → fixed, and Usage ▸ By function ⇄ Models hop
both ways on a tab/group hash. §2 stays as the design specimen (its radios are paint);
§3 is the leaf map; §5 is what shipped beyond the mock — the owner's build rules.
v2 (owner's review of v1): one row format for everything — a radio row, the console's own —
the stored kind as every card's key, no explanatory text, an explicit Inherit row where inherit is
the default, and a single checked radio where there is no choice. v3: every row marks
thinking on / off explicitly (a switch where it is a choice, a word where it is not); an
Inherit row shows the model it resolves to; the kind key and the group name wear the group's
colour; sans for all — no mono anywhere in the tab; room.title is Flash only.A reader of the console holds two different groupings of the same money. Usage
stacks spend by the ledger's call kind — the closed group.leaf vocabulary of
usage-dashboard §3, eight coloured groups. Models
lays the knobs out by which part of the product they sit in — six uncoloured surfaces.
So「kit cost $3.10 this week」sends the reader to Models to find… no kit.
The eleven missing leaves — kit.* ×5, persona.* ×4,
photo.* ×3 less the eyes' price row, room.translate,
speech.interrogate, tool.promised — are not missing by accident: their
model is a constant in code, so there was never a knob to draw. But the page is read as an
inventory (「every model & search API, by role」 is its own subtitle), and an inventory
that omits a third of the ledger is a page that cannot answer「what runs persona.dream?」.
U_GROUPS — the usage
tab's own list, in the same file. A group rail under the tab title is the usage chart's
legend made a navigation: one chip per group, the chart's colour, the leaf count; click to jump,
and it follows the scroll.room.translate), then the name (Translate on divergence); the rows are the
console's radio rows. Where a setting exists the rows are the choices you have today, untouched.
Where the model is a constant in code the card has one row, one radio, checked — the fact,
in the same format as a choice. Where inherit is the default, the Inherit row is written
out, followed by the model it resolves to. Every row marks thinking — thinking off
/ thinking on as a word, with the switch beside it where it is a choice — so a call that
cannot think says so instead of saying nothing. No descriptive text anywhere; the server reports
the constants, the page never names a model itself.Markup and classes lifted from lib/admin.html, set in sans; the rail, the group
header, the kind-as-key card header and the thinking mark are the new pieces; every row is the console's .mrow.
Every model & search API, by function — the same eight as Usage ▸ By function.
Everything on this page saves on change — no Save button.
| model | input | cache write 5m | cache write 1h | cache read | output |
|---|---|---|---|---|---|
| Opus 4.8Anthropic | |||||
| Sonnet 5Anthropic | |||||
| Haiku 4.5Anthropic | |||||
| DeepSeek V4 ProDeepSeekoff-peak | |||||
| DeepSeek V4 FlashDeepSeekoff-peak | |||||
| Gemini 3.7 FlashGoogle | |||||
| Gemini 3.5 FlashGoogle | |||||
| Gemini EmbeddingGoogle |
The build follows this table: 28 stored kinds, where each sits today, and what its card holds. choice = an existing setting, moved as-is · one radio = a constant in code, one checked row · inherit = an Inherit row, checked.
| group | leaf | today | card | the model (today's constant) |
|---|---|---|---|---|
| speech | speech | Chats ▸ Panel | choice | the user's switcher · default pre-selected |
| speech.interrogate | — | one radio | PROBE_MIND_MODEL = deepseek-v4-pro · thinking ON (the one fixed call that thinks) | |
| speech.empty | — | inherit | the panel's model, retried | |
| fp | fp | Chats ▸ Floor producer ×2 | choice | Off / Mechanical · V4 Pro · V4 Flash · ± reasoning |
| tool | tool.prop | The toolbox ▸ prop master | choice — Off · Pro · Flash (the switch folds into Off) | PROP_GATE_MODEL · env MAD_PROP_GATE_MODEL |
| tool.act | The toolbox ▸ act call | choice + inherit | inherit · V4 Pro · V4 Flash | |
| tool.promised | — | one radio | ACT_GATE_MODEL = deepseek-v4-flash · env MAD_ACT_GATE_MODEL | |
| kit | kit.interpreter | — | one radio | deepseek-v4-flash (inline) |
| kit.ruling | — | one radio | deepseek-v4-flash (inline) | |
| kit.voice | — | one radio | deepseek-v4-flash (inline) | |
| kit.route | — | one radio | PROBE_ROUTE_MODEL = deepseek-v4-flash | |
| kit.authoring | — | choice + inherit | authoring_model: "" (inherit) · deepseek-v4-pro | |
| persona | persona.memory | — | one radio | MEMORY_MODEL = deepseek-v4-flash |
| persona.dream | — | one radio | MEMORY_MODEL = deepseek-v4-flash | |
| persona.growth | — | one radio ×2 | RECENT_MODEL = deepseek-v4-flash · the sweep + Serper, the search | |
| persona.embed | — | one radio | wordpick.EMBED_MODEL = gemini-embedding-001 | |
| photo | photo.shadow | — (price row only) | one radio ×2 — every photo · dense pictures | PHOTO_MODEL = deepseek-v4-flash-vision-exp · PHOTO_DENSE_EYES = gemini-3.7-flash |
| photo.gate | — | one radio | PHOTO_GATE_MODEL = deepseek-v4-flash | |
| photo.look | — | shares the eyes card | the same eyes as the shadow | |
| room | room.translate | — | one radio | TRANSLATE_MODEL = deepseek-v4-flash |
| room.title | The toolbox ▸ auto-title | one radio | V4 Flash only — the Pro row is dropped (v3) | |
| room.dispatch | Chats ▸ Dispatch | choice | Claude native (Haiku 4.5) · SERP + V4 Flash | |
| app | app.convene | Chats ▸ Panel curator | choice | V4 Pro · V4 Flash · ± reasoning |
| app.seen | Notes ▸ Seen | choice ×3 | rank · writer · hero image | |
| app.vibes | Vibes | choice | engine model · news chain | |
| app.studio | Persona Studio | choice ×7 | the step matrix | |
| app.stt | API prices ▸ STT | one radio | iFlytek · the price stays under prices | |
| prices | — | API prices | as today | LLM · image · search · STT — one surface |
loadModels() emits the groups in
U_GROUPS order with the new .fgrp header; every card, every POST
endpoint and every change handler is the same code — a card moves, it does not change.GET /api/admin/models grows a
fixed block — {leaf: {model}}, or {inherit: true} — read from
the constants themselves (MEMORY_MODEL, PHOTO_MODEL, PHOTO_DENSE_EYES,
ACT_GATE_MODEL, …). The renderer draws it as the same .mrow it draws a choice
with — one radio, checked, no handler. The page never hard-codes a model name, so a constant that
moves in code moves on the page the same commit.Off · V4 Pro · V4 Flash — one radio group; Off posts
prop-gate on=false, a model posts on=true + the model. Same two endpoints
as today, one control instead of two.db.KIND_ALIAS values + the §3 table) appears as a .kind
key in the Models render — a new leaf with no row fails the gate, the way a new kind with no
colour already does.--s1…8 already live in
theme.css for the usage tab; the rail, the group name and the kind key all wear them
(a --fc per group section). No new hue anywhere.var(--sans); the tab title keeps the console's serif.
「reasoning」becomes「thinking」on the switch label, and the state is written out beside it.room.title offers Flash only (the Pro row is removed, the
setting collapses to a single checked radio); the prop master's switch folds into its list.usage-dashboard §3
gains a one-line pointer here; the console-redesign Models section gets a「superseded by」note.fp is split in the ledger — fp.open (the opening staging,
_open_stage) · fp.mid (the per-turn director, _f_engine + the two
drain sites). staging aliases to fp.mid; a row booked as plain fp
before the split stays fp — open or mid was never recorded, so it is never guessed.
The mid-chat lead row reads Code, not Mechanical.claude-sonnet-5; better and cheaper on
the intro price). MODEL_RETIRED + model_now() read a room saved on 4.6 onto the
Sonnet 5 seat at resume and at switch, so a Sonnet chat stays a Sonnet chat. ⚠ On Sonnet 5 an
omitted thinking runs adaptive thinking (4.6 ran none) — the panel call now sends
thinking: disabled explicitly, so the row's「thinking off」is true.builder.MODELS, the default
audit_b, the moderation fallback); a saved step matrix naming 3.5 reads onto 3.7
(builder.MODEL_RETIRED).cost.PRICES now) · Gemini 3.7 Flash · Gemini Embedding. Opus and Haiku
are off the table — cost.py still prices them, so the Claude web-search dispatch (Haiku)
bills from the built-in sheet, uneditable here. Every figure shows as 1.0000; STT keeps
six decimals because $0.000361 at four would read $0.0004.speech.empty ·
tool.act · kit.authoring) re-resolve the moment the Panel card's default radio
moves, before the save round-trips.room.title is Flash only — the endpoint offers one option; one checked radio.kit.authoring became a setting (owner, after the build): Inherit the chat's panel
model (default, unchanged behaviour) or V4 Pro — authoring_model,
POST /api/admin/settings/authoring-model, DeepSeek only like the act call; the call
bills and tallies under the model it actually ran.KIT_CLERK_MODEL was hoisted out
of three inline literals for it, and the wake-door check now follows ACT_GATE_MODEL
(env-movable) like the quick act gate it is.#usage/<group> and
flashes that By-function row (or the table, when the window holds no spend for the group); a
By-function row's function cell opens #models/<group> and flashes the section.#sec-models; the usage tab keeps its mono.