feat: show only featured models by default in model selector (#106) (#119)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2025-11-24 00:10:48 -08:00
committed by GitHub
parent 61ed93c6c6
commit 43813383ac
2 changed files with 64 additions and 14 deletions

View File

@@ -1,9 +1,19 @@
// Import useInput from vendored Ink for bracketed paste support
import { Box, Text, useInput } from "ink";
import { useState } from "react";
import { useMemo, useState } from "react";
import { models } from "../../agent/model";
import { colors } from "./colors";
type UiModel = {
id: string;
handle: string;
label: string;
description: string;
isDefault?: boolean;
isFeatured?: boolean;
updateArgs?: Record<string, unknown>;
};
interface ModelSelectorProps {
currentModel?: string;
onSelect: (modelId: string) => void;
@@ -15,17 +25,37 @@ export function ModelSelector({
onSelect,
onCancel,
}: ModelSelectorProps) {
const typedModels = models as UiModel[];
const [showAll, setShowAll] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);
const featuredModels = useMemo(
() => typedModels.filter((model) => model.isFeatured),
[typedModels],
);
const visibleModels = useMemo(() => {
if (showAll) return typedModels;
if (featuredModels.length > 0) return featuredModels;
return typedModels.slice(0, 5);
}, [featuredModels, showAll, typedModels]);
const totalItems = showAll ? visibleModels.length : visibleModels.length + 1;
useInput((_input, key) => {
if (key.upArrow) {
setSelectedIndex((prev) => Math.max(0, prev - 1));
} else if (key.downArrow) {
setSelectedIndex((prev) => Math.min(models.length - 1, prev + 1));
setSelectedIndex((prev) => Math.min(totalItems - 1, prev + 1));
} else if (key.return) {
const selectedModel = models[selectedIndex];
if (selectedModel) {
onSelect(selectedModel.id);
if (!showAll && selectedIndex === visibleModels.length) {
setShowAll(true);
setSelectedIndex(0);
} else {
const selectedModel = visibleModels[selectedIndex];
if (selectedModel) {
onSelect(selectedModel.id);
}
}
} else if (key.escape) {
onCancel();
@@ -41,7 +71,7 @@ export function ModelSelector({
</Box>
<Box flexDirection="column">
{models.map((model, index) => {
{visibleModels.map((model, index) => {
const isSelected = index === selectedIndex;
const isCurrent = model.handle === currentModel;
@@ -69,6 +99,20 @@ export function ModelSelector({
</Box>
);
})}
{!showAll && (
<Box flexDirection="row" gap={1}>
<Text
color={
selectedIndex === visibleModels.length
? colors.selector.itemHighlighted
: undefined
}
>
{selectedIndex === visibleModels.length ? "" : " "}
</Text>
<Text dimColor>Show all models</Text>
</Box>
)}
</Box>
</Box>
);

View File

@@ -5,6 +5,7 @@
"label": "Claude Sonnet 4.5 (default)",
"description": "The recommended default model (currently Sonnet 4.5)",
"isDefault": true,
"isFeatured": true,
"updateArgs": { "context_window": 180000 }
},
{
@@ -17,18 +18,12 @@
"context_window": 180000
}
},
{
"id": "gemini-3",
"handle": "google_ai/gemini-3-pro-preview",
"label": "Gemini 3 Pro",
"description": "Google's smartest model",
"updateArgs": { "context_window": 180000 }
},
{
"id": "opus",
"handle": "anthropic/claude-opus-4-1-20250805",
"label": "Claude Opus 4.1",
"description": "Anthropic's smartest (and slowest) model",
"description": "Anthropic's largest (and slowest) model",
"isFeatured": true,
"updateArgs": { "context_window": 180000 }
},
{
@@ -36,6 +31,7 @@
"handle": "anthropic/claude-haiku-4-5-20251001",
"label": "Claude Haiku 4.5",
"description": "Anthropic's fastest model",
"isFeatured": true,
"updateArgs": { "context_window": 180000 }
},
{
@@ -76,6 +72,7 @@
"handle": "openai/gpt-5.1",
"label": "GPT-5.1 (medium)",
"description": "OpenAI's latest model (using their recommended reasoning level)",
"isFeatured": true,
"updateArgs": {
"reasoning_effort": "medium",
"verbosity": "medium",
@@ -109,6 +106,7 @@
"handle": "openai/gpt-5.1-codex",
"label": "GPT-5.1-Codex (medium)",
"description": "GPT-5.1-Codex with recommended reasoning level",
"isFeatured": true,
"updateArgs": {
"reasoning_effort": "medium",
"verbosity": "medium",
@@ -228,6 +226,14 @@
"context_window": 128000
}
},
{
"id": "gemini-3",
"handle": "google_ai/gemini-3-pro-preview",
"label": "Gemini 3 Pro",
"description": "Google's smartest model",
"isFeatured": true,
"updateArgs": { "context_window": 180000 }
},
{
"id": "gemini-flash",
"handle": "google_ai/gemini-2.5-flash",