Model mode menu
Lets people pick how much reasoning Sage uses, from Pro, Standard and Mini.
import { ModelModeMenu, SAGE_MODES, readSageMode, writeSageMode } from "@/ui";The model mode menu is the pill next to the send button on the home page and in the session composer. It opens a "Choose your mode" list built on the dropdown menu. Each mode has an icon, a name, a one-line description and an info icon with more detail on hover.
It is used in three places: the harness home page, the older home page and the session composer. Use it only where someone is about to send a prompt to Sage.
Usage
Start the state from readSageMode so the choice carries over between the home page and a session. The menu saves the new mode itself when someone picks one, then calls onChange.
const [mode, setMode] = useState(readSageMode);
<ModelModeMenu value={mode} onChange={setMode} placement="bottom" />Choosing a mode on this page saves it in this browser, so the app will open in that mode too.
Opening upwards
Use placement="top" when the menu sits at the bottom of the screen, as in the session composer. The panel aligns to the pill's right edge in both placements, so keep the pill on the right of its row.
<div className="composer-actions">
<ModelModeMenu value={mode} onChange={setMode} placement="top" />
<Button variant="primary" icon={ArrowUp} aria-label="Send" />
</div>Disabled
Disable it whenever the composer cannot send, as the session composer does. The pill drops to 60% opacity and does not open.
<ModelModeMenu value={mode} onChange={setMode} disabled={composerDisabled} />The modes
The list comes from SAGE_MODES. Each entry is { id, label, beta?, icon, description, tooltip }.
id | Label | Badge | Description |
|---|---|---|---|
pro | Pro | Beta | Deepest reasoning for complex work. About twice the credits of Standard. |
standard | Standard | The default for everyday analysis. Other modes are priced against it. | |
mini | Mini | Beta | For quick lookups and simple questions. Fewer credits than Standard. |
To add or change a mode, edit SAGE_MODES in ModelModeMenu.jsx. Every menu and both helper functions read from it.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
value | "pro" | "standard" | "mini" | "standard" | An unknown id shows "Standard" on the pill but no check in the list. |
onChange | (id) => void | Called only when the mode changes. The new mode is already saved when it runs. | |
placement | "bottom" | "top" | "bottom" | Which side of the pill the panel opens on. |
disabled | boolean | false | |
className | string | Goes on the wrapper <div class="mm">. For layout only. |
Helpers
| Export | Returns | Notes |
|---|---|---|
readSageMode() | "pro" | "standard" | "mini" | Reads petavue:sage-mode from localStorage. Returns "standard" if nothing valid is stored or storage is blocked. |
writeSageMode(id) | Saves id to the same key. It does not check that id is a known mode. The menu already calls it, so you only need it to set the mode from somewhere else. | |
SAGE_MODES | Array | The three modes, in display order. |
Look
| Part | Style |
|---|---|
| Pill | 34px high, 1px --color-neutral-200 border, --radius-md (8px) corners, white. On hover the border goes to --color-neutral-300 and the fill to --color-neutral-50. |
| Pill content | A 14px sparkle in --color-primary-500, the mode name in 13px semibold, and a 14px caret in --color-text-secondary. |
| Panel | 328px wide, from the product dropdown. 8px from the pill. Aligned to the pill's right edge. |
| Item | 16px icon, the name in 14px, the description in 12px --color-text-secondary. The chosen mode has a bold blue check on the right. |
| Info tip | Dark --color-neutral-900 box, 224px wide, opens above the info icon on hover or focus. |
A few things here do not follow the rest of the system yet. The icons come from lucide-react instead of Phosphor. The Beta badge uses --color-tag-violet and --color-accent-400 (#643BCF), a purple outside the product palette. The pill name is 13px, the badge 10.5px and the tip 11px, off the 12px and 14px scale. The pill is 34px high while a medium Button is 32px. ModelModeMenu.css also still has rules for the menu it used before moving to the product dropdown (.mm__menu, .mm__item, .mm__check, .mm__item-label), which no longer apply.
Accessibility
- The pill is a native
<button>named "Model mode: Standard" (or the current mode), witharia-haspopup="menu"andaria-expanded. - Enter, Space or the down arrow opens the list on the first mode. The arrow keys, Home and End move through modes, Enter chooses one, and Escape closes the list. In both cases focus returns to the pill.
- The chosen mode is shown with a drawn check, not
aria-checked. Screen readers hear the current mode from the pill's name, not from the list. - Each mode's accessible name includes the full tooltip text, because the info icon carries it as an
aria-label. That makes each option long to listen to. - The info icons have
tabIndex={0}, so Tab moves into them instead of closing the list as it does in every other menu. Clicking an info icon does not choose the mode.
Do and don't
- Do start state from
readSageModeso the choice follows people between pages. - Do disable the menu together with the composer it sits in.
- Don't call
writeSageModein youronChange. The menu has already saved it. - Don't use this component for other choices. Its list is fixed to
SAGE_MODES. For a general choice under the composer, use the dropdown menu with a Button trigger.