fix: improve UI (#403)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2025-12-27 01:55:13 -08:00
committed by GitHub
parent aa4071c721
commit 424e4980ac
8 changed files with 124 additions and 73 deletions

View File

@@ -24,6 +24,7 @@ import { getClient } from "../agent/client";
import { getCurrentAgentId, setCurrentAgentId } from "../agent/context";
import { type AgentProvenance, createAgent } from "../agent/create";
import { sendMessageStream } from "../agent/message";
import { getModelDisplayName, getModelInfo } from "../agent/model";
import { SessionStats } from "../agent/stats";
import type { ApprovalContext } from "../permissions/analyzer";
import { type PermissionMode, permissionMode } from "../permissions/mode";
@@ -527,7 +528,10 @@ export default function App({
llmConfig?.model_endpoint_type && llmConfig?.model
? `${llmConfig.model_endpoint_type}/${llmConfig.model}`
: (llmConfig?.model ?? null);
const currentModelDisplay = currentModelLabel?.split("/").pop() ?? null;
const currentModelDisplay = currentModelLabel
? (getModelDisplayName(currentModelLabel) ??
currentModelLabel.split("/").pop())
: null;
const currentModelProvider = llmConfig?.provider_name ?? null;
// Token streaming preference (can be toggled at runtime)
@@ -885,6 +889,18 @@ export default function App({
.last_run_completion;
setAgentLastRunAt(lastRunCompletion ?? null);
// Derive model ID from llm_config for ModelSelector
const agentModelHandle =
agent.llm_config.model_endpoint_type && agent.llm_config.model
? `${agent.llm_config.model_endpoint_type}/${agent.llm_config.model}`
: agent.llm_config.model;
const modelInfo = getModelInfo(agentModelHandle || "");
if (modelInfo) {
setCurrentModelId(modelInfo.id);
} else {
setCurrentModelId(agentModelHandle || null);
}
// Detect current toolset from attached tools
const { detectToolsetFromAgent } = await import("../tools/toolset");
const detected = await detectToolsetFromAgent(client, agentId);

View File

@@ -68,7 +68,7 @@ export const commands: Record<string, Command> = {
},
},
"/clear": {
desc: "Clear conversation history",
desc: "Clear conversation history (keep memory)",
order: 17,
handler: () => {
// Handled specially in App.tsx to access client and agent ID

View File

@@ -15,7 +15,6 @@ import type { PermissionMode } from "../../permissions/mode";
import { permissionMode } from "../../permissions/mode";
import { ANTHROPIC_PROVIDER_NAME } from "../../providers/anthropic-provider";
import { settingsManager } from "../../settings-manager";
import { getVersion } from "../../version";
import { charsToTokens, formatCompact } from "../helpers/format";
import { useTerminalWidth } from "../hooks/useTerminalWidth";
import { colors } from "./colors";
@@ -26,7 +25,6 @@ import { ShimmerText } from "./ShimmerText";
// Type assertion for ink-spinner compatibility
const Spinner = SpinnerLib as ComponentType<{ type?: string }>;
const appVersion = getVersion();
// Window for double-escape to clear input
const ESC_CLEAR_WINDOW_MS = 2500;
@@ -708,11 +706,22 @@ export function Input({
</Text>
</Text>
) : (
<Text dimColor>Press / for commands or @ for files</Text>
<Text dimColor>Press / for commands</Text>
)}
<Text dimColor>
{`Letta Code v${appVersion} `}
{`[${currentModel ?? "unknown"}${currentModelProvider === ANTHROPIC_PROVIDER_NAME ? ` ${chalk.rgb(255, 199, 135)("claude pro/max")}` : ""}]`}
<Text>
<Text color={colors.footer.agentName}>
{agentName || "Unnamed"}
</Text>
<Text
dimColor={currentModelProvider !== ANTHROPIC_PROVIDER_NAME}
color={
currentModelProvider === ANTHROPIC_PROVIDER_NAME
? "#FFC787"
: undefined
}
>
{` [${currentModel ?? "unknown"}]`}
</Text>
</Text>
</Box>
</Box>

View File

@@ -104,10 +104,16 @@ export function ModelSelector({
);
// Supported models: models.json entries that are available
// Featured models first, then non-featured, preserving JSON order within each group
const supportedModels = useMemo(() => {
if (availableHandles === undefined) return [];
if (availableHandles === null) return typedModels; // fallback
return typedModels.filter((m) => availableHandles.has(m.handle));
const available =
availableHandles === null
? typedModels // fallback
: typedModels.filter((m) => availableHandles.has(m.handle));
const featured = available.filter((m) => m.isFeatured);
const nonFeatured = available.filter((m) => !m.isFeatured);
return [...featured, ...nonFeatured];
}, [typedModels, availableHandles]);
// All other models: API handles not in models.json
@@ -258,7 +264,7 @@ export function ModelSelector({
);
const getCategoryLabel = (cat: ModelCategory) => {
if (cat === "supported") return `Supported (${supportedModels.length})`;
if (cat === "supported") return `Recommended (${supportedModels.length})`;
return `All Available Models (${otherModelHandles.length})`;
};
@@ -277,6 +283,7 @@ export function ModelSelector({
{i > 0 && <Text dimColor> · </Text>}
<Text
bold={cat === category}
dimColor={cat !== category}
color={
cat === category
? colors.selector.itemHighlighted
@@ -349,13 +356,15 @@ export function ModelSelector({
<Text
bold={isSelected}
color={
isSelected ? colors.selector.itemHighlighted : undefined
isSelected
? colors.selector.itemHighlighted
: isCurrent
? colors.selector.itemCurrent
: undefined
}
>
{model.label}
{isCurrent && (
<Text color={colors.selector.itemCurrent}> (current)</Text>
)}
{isCurrent && <Text> (current)</Text>}
</Text>
{model.description && (
<Text dimColor> {model.description}</Text>

View File

@@ -2,6 +2,7 @@ import { Text } from "ink";
import Link from "ink-link";
import { useEffect, useMemo, useState } from "react";
import { settingsManager } from "../../settings-manager";
import { getVersion } from "../../version";
import { commands } from "../commands/registry";
import { useAutocompleteNavigation } from "../hooks/useAutocompleteNavigation";
import { AutocompleteBox, AutocompleteItem } from "./Autocomplete";
@@ -209,6 +210,7 @@ export function SlashCommandAutocomplete({
<Text color={colors.link.text}>join our Discord </Text>
</Link>
</Text>
<Text dimColor>Version: Letta Code v{getVersion()}</Text>
</AutocompleteBox>
);
}

View File

@@ -163,4 +163,9 @@ export const colors = {
dim: "gray",
bold: "white",
},
// Footer bar
footer: {
agentName: brandColors.primaryAccent,
},
} as const;