Skip to content
KONIGI

AI Assistants / Input and invocation / Mode switch

5 of 7

Mode switch

The same question wants a fast answer some days and a researched one others.

Updated September 12, 2026

Problem

“What’s the capital of Peru” and “compare these four vendors and tell me which to pick” arrive through the same box. One wants an answer in a second. The other wants ten minutes of searching and reading, and getting it in a second is a failure disguised as speed.

Solution

Offer a small set of behaviours next to the composer: answer now, search the web first, think for longer, run a full research pass. Each changes what the system does rather than which model does it, and that distinction is the one thing the control has to get across.

The confusion with the model picker is the central design failure of this pattern. Both live in the composer, both present a short list, and both change the answer. The difference that matters to a viewer is that a model is a capability ceiling and a mode is an amount of effort. Products that merge them into one menu produce a list where some entries are nouns and some are verbs, and nobody can predict what any of them will do. Keeping them as separate controls, with the mode expressed as a verb, is worth the extra pixel.

Every mode carries three costs the viewer should be able to see before committing: time, money, and the chance of a worse answer. A deep research pass that takes nine minutes and burns a large share of a monthly quota is a different kind of decision than toggling web search, and presenting them as peers in one row understates it. Time is the cost most worth stating up front, because the viewer is choosing whether to wait.

HAX guideline 3 asks for services timed to context, and the honest reading here is that the system should mostly pick for itself. Most people never touch these controls, so routing by question complexity determines the experience for the majority. That moves the design problem from choosing to disclosing: when the system escalated to a slower mode, say so on the turn, and let the viewer force the fast path when they would rather have a quick wrong answer than a slow right one.

Persistence is the last decision and the one that bites. A mode that stays on until turned off will be left on, and the viewer will spend a week’s quota without noticing. A mode that resets every turn makes a genuinely research-shaped session tedious. Per-conversation persistence with a visible indicator is the usual compromise.

Use when

The product genuinely has distinct operating modes with different costs, and the viewer can tell in advance which one their question wants.

Don’t use when

The difference between modes is a few per cent of quality. A toggle implies a real fork, and offering one where none exists teaches people to fiddle with settings instead of writing better questions.

Trade-offs

Modes give control and demand a decision before the viewer has finished thinking about their question, which is the worst moment to ask. Automatic routing removes that and takes the agency with it, and it fails visibly the first time a hard question gets the cheap treatment. Persistent modes are efficient and quietly expensive. Each new mode multiplies the state a viewer has to reason about when an answer is surprising. A poor result now has a model, a mode and a prompt to blame, with no way to tell which.

Checklist

  • Is the mode control visually distinct from the model control?
  • Are the options verbs rather than nouns?
  • Is the time cost of the slowest mode stated before it runs?
  • Does the viewer learn what a mode costs against their quota?
  • Does the mode persist, and for how long, and is that visible?
  • If routing is automatic, is the escalation disclosed on the turn?
  • Can the viewer force the fast path?
  • What happens to a mode when the model is changed?
  • Is the active mode legible without opening a menu?
  • Can a long research mode be interrupted, and what survives?

Compare

ChatGPT separates search and extended reasoning as explicit toggles beside the composer, so effort is chosen independently of the model. Claude binds extended thinking to a budget and streams a summary of the work, so the slow mode is legible while it runs instead of only at the end. Perplexity builds the whole product around the mode, with focus and source-set controls that change where it searches rather than how hard it thinks. Gemini leans further toward routing the choice automatically. That suits a consumer audience, and it turns escalation into something to disclose rather than something to select.

Model picker is the adjacent control this is constantly confused with. Reasoning disclosure is what a longer-thinking mode produces and has to show. Source list is what a search mode produces. Usage meter is where an expensive mode’s cost appears. Composer holds the control and pays for it in width.

Mode switch anatomy A row of modes expressed as verbs beside the composer, each carrying its time and quota cost, kept visually separate from the model control, with an automatic escalation disclosed on the turn and a way to force the fast path. Verbs, not nouns, and separate from the model answer now 2s search first 15s · 1 credit think longer 90s · 4 credits research 9 min · 40 credits model Careful a ceiling, not an amount of effort escalated to think longer for this question answer fast instead a mode left on quietly spends a week of quota 1 2 3 4 1 MODES ARE VERBS A menu mixing nouns and verbs leaves nobody able to predict what any row does. 2 TIME AND COST UP FRONT Nine minutes and forty credits is a different decision than a toggle. 3 KEEP IT OFF THE MODEL A model is a capability ceiling. A mode is an amount of effort. Two controls. 4 DISCLOSE THE ESCALATION Most people never touch these, so routing decides the experience. Say what it chose. Each mode adds state to blame when an answer is bad, with no way to tell which was at fault.
Wireframe — the pattern's anatomy, not any one product's version of it

Implementation

Modes written as verbs and priced in time and quota, kept visually apart from the model control. The model is a ceiling; the mode is how much effort gets spent under it, and one left on quietly spends a week of quota.

shadcn
npx shadcn@latest add toggle-group button
Tokens
--card--card-foreground--muted--muted-foreground--accent--accent-foreground--border--chart-1
model
escalated to think longer for this question

ModeSwitch.tsxA closed set of verbs, each priced from its seconds and credits, the model on its own row, and the escalation disclosed on the turn.

import { Button } from "@/components/ui/button";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";

/**
 * A closed set, each one a verb. A mode is an amount of effort, and a menu
 * that mixes these with model names leaves nobody able to predict a row.
 * Time and credits are on every entry because the viewer is choosing whether
 * to wait and what to spend, and a toggle with no price understates both.
 */
export const MODES = {
  answer:   { verb: "answer now",   seconds: 2,   credits: 0 },
  search:   { verb: "search first", seconds: 15,  credits: 1 },
  think:    { verb: "think longer", seconds: 90,  credits: 4 },
  research: { verb: "research",     seconds: 540, credits: 40 },
} as const;
export type Mode = keyof typeof MODES;

const time = (s: number) => (s >= 120 ? `${Math.round(s / 60)} min` : `${s}s`);
const credits = (n: number) => (n === 0 ? "" : n === 1 ? " · 1 credit" : ` · ${n} credits`);
/** "9 min · 40 credits", computed rather than typed, so it cannot drift. */
export const price = (m: Mode) => `${time(MODES[m].seconds)}${credits(MODES[m].credits)}`;

type Props = {
  value: Mode;
  onChange: (mode: Mode) => void;
  /** The model is a separate control on purpose. It is a capability ceiling,
   *  and it sits on its own row so it cannot be mistaken for an effort level. */
  model: string;
  onPickModel: () => void;
  /** Where routing escalated the current turn past the chosen mode. Most
   *  people never touch the row above, so this is the part they see. */
  escalatedTo?: Mode;
  onForceFast: () => void;
};

export function ModeSwitch({ value, onChange, model, onPickModel, escalatedTo, onForceFast }: Props) {
  return (
    <div className="rounded-lg border bg-card p-4 text-card-foreground">
      <ToggleGroup
        type="single"
        value={value}
        onValueChange={(v) => v && onChange(v as Mode)}
        aria-label="How much effort to spend"
        className="grid grid-cols-2 gap-3 sm:grid-cols-4"
      >
        {(Object.keys(MODES) as Mode[]).map((m) => (
          <ToggleGroupItem
            key={m}
            value={m}
            className="h-auto flex-col items-start gap-1 rounded-md border px-3 py-2 data-[state=on]:border-chart-1 data-[state=on]:bg-chart-1/10 data-[state=on]:text-chart-1"
          >
            <span className="text-xs">{MODES[m].verb}</span>
            <span className="text-xs font-normal tabular-nums text-muted-foreground">{price(m)}</span>
          </ToggleGroupItem>
        ))}
      </ToggleGroup>

      <div className="mt-4 flex items-center gap-3 border-t border-dashed pt-3 text-xs">
        <span className="text-muted-foreground">model</span>
        <Button variant="outline" size="sm" className="h-6 px-2.5 text-xs" onClick={onPickModel}>{model}</Button>
      </div>

      {escalatedTo && escalatedTo !== value && (
        <div className="mt-4 flex items-center gap-3 rounded-lg border bg-muted px-3 py-2 text-xs">
          <span>escalated to {MODES[escalatedTo].verb} for this question</span>
          <button type="button" onClick={onForceFast} className="ml-auto text-muted-foreground underline underline-offset-2">
            answer fast instead
          </button>
        </div>
      )}
    </div>
  );
}

demo.tsxHow it is called: answer now chosen, routing escalated this question to think longer, fast path one click away.

import { useState } from "react";
import { ModeSwitch, type Mode } from "./ModeSwitch";

/**
 * Answer now is the chosen mode, and routing escalated this one question to
 * think longer. Forcing the fast path clears the escalation; picking a mode
 * changes what every turn from here does.
 */
export default function Demo() {
  const [mode, setMode] = useState<Mode>("answer");
  const [escalatedTo, setEscalatedTo] = useState<Mode | undefined>("think");

  return (
    <ModeSwitch
      value={mode}
      onChange={setMode}
      model="Careful"
      onPickModel={() => {}}
      escalatedTo={escalatedTo}
      onForceFast={() => setEscalatedTo(undefined)}
    />
  );
}
What it renders. Identical markup in both panes, with only the token values changing.

Examples

No captures reference this pattern yet. Captures arrive product by product; see Products for what's in the gallery so far.