diff --git a/packages/tui/src/component/altimate-modes.ts b/packages/tui/src/component/altimate-modes.ts new file mode 100644 index 0000000000..3d420bb872 --- /dev/null +++ b/packages/tui/src/component/altimate-modes.ts @@ -0,0 +1,35 @@ +// Auto Mode tier metadata for the altimate-backend provider. Kept in an altimate-owned file so the +// upstream-derived picker and prompt only need thin hooks. +export const ALTIMATE_MODE_PROVIDER = "altimate-backend" + +export const ALTIMATE_MODES: Record = { + "altimate-auto": { label: "Auto", description: "Balanced default", order: 0 }, + "altimate-fast": { label: "Fast", description: "Fastest, lowest cost", order: 1 }, + "altimate-max": { label: "Max", description: "Most capable", order: 2 }, +} + +export function altimateMode(providerID: string, modelID: string) { + return providerID === ALTIMATE_MODE_PROVIDER ? ALTIMATE_MODES[modelID] : undefined +} + +type PickerRow = { value: unknown; title: string; description?: string; category?: string } + +function rowModelID(row: PickerRow) { + const v = row.value as { providerID?: string; modelID?: string } | string + if (typeof v === "string") return undefined + return altimateMode(v.providerID ?? "", v.modelID ?? "") ? v.modelID : undefined +} + +/** Split tier rows out of the READY rows into an ordered "AUTO MODE" section. */ +export function splitModeRows(rows: T[]): { modes: T[]; rest: T[] } { + const modes = rows.filter((r) => rowModelID(r)) + const rest = rows.filter((r) => !rowModelID(r)) + modes.sort((a, b) => ALTIMATE_MODES[rowModelID(a)!].order - ALTIMATE_MODES[rowModelID(b)!].order) + return { + modes: modes.map((r) => { + const meta = ALTIMATE_MODES[rowModelID(r)!] + return { ...r, title: meta.label, description: meta.description, category: "AUTO MODE" } + }), + rest, + } +} diff --git a/packages/tui/src/component/dialog-model.tsx b/packages/tui/src/component/dialog-model.tsx index 546b1c0543..2a58be9d6b 100644 --- a/packages/tui/src/component/dialog-model.tsx +++ b/packages/tui/src/component/dialog-model.tsx @@ -17,6 +17,8 @@ import { CUSTOM_PROVIDER_OPTION_VALUE, } from "./dialog-provider" // altimate_change end +// altimate_change — Auto Mode tier section helper +import { splitModeRows } from "./altimate-modes" import { DialogVariant } from "./dialog-variant" import * as fuzzysort from "fuzzysort" import { useConnected } from "./use-connected" @@ -223,14 +225,20 @@ export function DialogModel(props: { return list })() + // Auto Mode tiers get their own section (not when drilling into one provider). + const { modes: modeOptions, rest: readyRest } = props.providerID + ? { modes: [], rest: readyOptions } + : splitModeRows(readyOptions) + if (needle) { return [ - ...fuzzysort.go(needle, readyOptions, { keys: ["title", "description"] }).map((x) => x.obj), + ...fuzzysort.go(needle, modeOptions, { keys: ["title", "description"] }).map((x) => x.obj), + ...fuzzysort.go(needle, readyRest, { keys: ["title", "description"] }).map((x) => x.obj), ...fuzzysort.go(needle, setupOptions, { keys: ["title", "description"] }).map((x) => x.obj), ] } - return [...readyOptions, ...setupOptions] + return [...modeOptions, ...readyRest, ...setupOptions] }) const provider = createMemo(() => diff --git a/packages/tui/src/component/prompt/index.tsx b/packages/tui/src/component/prompt/index.tsx index defb14f13a..cdb4e595e5 100644 --- a/packages/tui/src/component/prompt/index.tsx +++ b/packages/tui/src/component/prompt/index.tsx @@ -48,7 +48,9 @@ import { useDialog } from "../../ui/dialog" import { DialogProvider as DialogProviderConnect, WARNLIST } from "../dialog-provider" // altimate_change — first-run submit gate: open the curated welcome picker instead // of erroring when no model is ready yet (see altimate-onboarding.tsx). -import { DialogModelWelcome, markFirstRunActive, useReady, useReadyPending } from "../altimate-onboarding" +// altimate_change — Auto Mode tier lookup for the prompt chip +import { altimateMode } from "../altimate-modes" +import { DialogModelWelcome,markFirstRunActive, useReady, useReadyPending } from "../altimate-onboarding" import { DialogAlert } from "../../ui/dialog-alert" import { useToast } from "../../ui/toast" import { useKV } from "../../context/kv" @@ -275,6 +277,11 @@ export function Prompt(props: PromptProps) { // separate accessor rather than folded into `ready` itself. const readyPending = useReadyPending() const unreliableModel = createMemo(() => Boolean(WARNLIST[local.model.parsed().model])) + // altimate_change — active Auto Mode tier (undefined for non-altimate models) + const activeMode = createMemo(() => { + const m = local.model.current() + return m ? altimateMode(m.providerID, m.modelID) : undefined + }) // altimate_change end function promptModelWarning() { @@ -1684,6 +1691,16 @@ export function Prompt(props: PromptProps) { + {/* altimate_change — Auto Mode tier chip */} + + {(mode) => ( + + + {`[${mode().label}]`} + + + )} + {/* altimate_change — persistent chip for models on WARNLIST (known-bad tool-callers) */}