diff --git a/src/cli/App.tsx b/src/cli/App.tsx index 1494fa5..d8276cb 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -58,7 +58,7 @@ import { SystemPromptSelector } from "./components/SystemPromptSelector"; import { ToolCallMessage } from "./components/ToolCallMessageRich"; import { ToolsetSelector } from "./components/ToolsetSelector"; import { UserMessage } from "./components/UserMessageRich"; -import { WelcomeScreen } from "./components/WelcomeScreen"; +import { getAgentStatusHints, WelcomeScreen } from "./components/WelcomeScreen"; import { type Buffers, createBuffers, @@ -563,17 +563,15 @@ export default function App({ backfillBuffers(buffersRef.current, messageHistory); // Inject "showing N messages" status at the START of backfilled history + // Add status line showing resumed agent info const backfillStatusId = `status-backfill-${Date.now().toString(36)}`; - const messageCount = messageHistory.length; const agentUrl = agentState?.id ? `https://app.letta.com/agents/${agentState.id}` : null; const backfillLines = [ - `Showing ${messageCount} most recent message${messageCount !== 1 ? "s" : ""}`, - agentUrl - ? ` → View full history in ADE: ${agentUrl}` - : " → View full history in ADE", - ]; + "Resumed agent", + agentUrl ? `→ ${agentUrl}` : "", + ].filter(Boolean); buffersRef.current.byId.set(backfillStatusId, { kind: "status", id: backfillStatusId, @@ -3438,6 +3436,30 @@ Plan file path: ${planFilePath}`; }, }, ]); + + // Add status line showing agent info + const agentUrl = agentState?.id + ? `https://app.letta.com/agents/${agentState.id}` + : null; + const statusId = `status-agent-${Date.now().toString(36)}`; + const hints = getAgentStatusHints( + !!continueSession, + agentState, + agentProvenance, + ); + const statusLines = [ + continueSession ? "Resumed agent" : "Created new agent", + agentUrl ? `→ ${agentUrl}` : "", + ...hints, + ].filter(Boolean); + + buffersRef.current.byId.set(statusId, { + kind: "status", + id: statusId, + lines: statusLines, + }); + buffersRef.current.order.push(statusId); + refreshDerived(); } }, [ loadingState, @@ -3446,6 +3468,7 @@ Plan file path: ${planFilePath}`; columns, agentProvenance, agentState, + refreshDerived, ]); return ( diff --git a/src/cli/components/WelcomeScreen.tsx b/src/cli/components/WelcomeScreen.tsx index 380fd4a..fadc840 100644 --- a/src/cli/components/WelcomeScreen.tsx +++ b/src/cli/components/WelcomeScreen.tsx @@ -1,12 +1,49 @@ +import { homedir } from "node:os"; import type { Letta } from "@letta-ai/letta-client"; import { Box, Text } from "ink"; -import Link from "ink-link"; + import type { AgentProvenance } from "../../agent/create"; +import { settingsManager } from "../../settings-manager"; import { getVersion } from "../../version"; import { useTerminalWidth } from "../hooks/useTerminalWidth"; import { asciiLogo } from "./AsciiArt"; import { colors } from "./colors"; +/** + * Convert absolute path to use ~ for home directory + */ +function toTildePath(absolutePath: string): string { + const home = homedir(); + if (absolutePath.startsWith(home)) { + return `~${absolutePath.slice(home.length)}`; + } + return absolutePath; +} + +/** + * Determine the auth method used + */ +function getAuthMethod(): "url" | "api-key" | "oauth" { + // Check if custom URL is being used + if (process.env.LETTA_BASE_URL) { + return "url"; + } + // Check if API key from env + if (process.env.LETTA_API_KEY) { + return "api-key"; + } + // Check settings for refresh token (OAuth) + const settings = settingsManager.getSettings(); + if (settings.refreshToken) { + return "oauth"; + } + // Check if API key stored in settings + if (settings.env?.LETTA_API_KEY) { + return "api-key"; + } + return "oauth"; // default +} + type LoadingState = | "assembling" | "upserting" @@ -96,35 +133,33 @@ export function WelcomeScreen({ loadingState, continueSession, agentState, - agentProvenance, - terminalWidth: frozenWidth, + agentProvenance: _agentProvenance, }: { loadingState: LoadingState; continueSession?: boolean; agentState?: Letta.AgentState | null; agentProvenance?: AgentProvenance | null; - terminalWidth?: number; }) { - const currentWidth = useTerminalWidth(); - const terminalWidth = frozenWidth ?? currentWidth; + // Keep hook call for potential future responsive behavior + useTerminalWidth(); const cwd = process.cwd(); const version = getVersion(); - const agentId = agentState?.id; const logoLines = asciiLogo.trim().split("\n"); - const isMedium = terminalWidth >= 80; + const tildePath = toTildePath(cwd); - const statusMessage = getStatusMessage( - loadingState, - !!continueSession, - agentId, - ); - const pathLine = isMedium ? `${cwd}` : cwd; - const agentUrl = agentId ? `https://app.letta.com/agents/${agentId}` : null; - const hints = - loadingState === "ready" - ? getAgentStatusHints(!!continueSession, agentState, agentProvenance) - : []; + // Get model from agent state - just the last part (after last /) + const fullModel = agentState?.model || agentState?.llm_config?.model; + const model = fullModel?.split("/").pop(); + + // Get auth method + const authMethod = getAuthMethod(); + const authDisplay = + authMethod === "url" + ? process.env.LETTA_BASE_URL || "Custom URL" + : authMethod === "api-key" + ? "API key auth" + : "OAuth"; return ( @@ -140,46 +175,31 @@ export function WelcomeScreen({ {/* Right column: Text info */} - - Letta Code v{version} + {/* Row 1: Letta Code + version */} + + Letta Code + v{version} + + {/* Row 2: model · auth (or just auth while loading) */} + + {model ? `${model} · ${authDisplay}` : authDisplay} + + {/* Row 3: loading status, then path once ready */} + + {loadingState === "ready" + ? tildePath + : getLoadingMessage(loadingState, !!continueSession)} - {pathLine} - {statusMessage && ( - - {statusMessage} - {loadingState === "ready" && agentUrl && ( - <> - {": "} - - {agentUrl} - - - )} - - )} - {hints.map((hint, idx) => ( - // biome-ignore lint/suspicious/noArrayIndexKey: Hint lines are static and never reorder - - {hint} - - ))} ); } -function getStatusMessage( +function getLoadingMessage( loadingState: LoadingState, continueSession: boolean, - agentId?: string, ): string { switch (loadingState) { - case "ready": - return continueSession && agentId - ? "Resumed agent" - : agentId - ? "Created a new agent" - : "Ready to go!"; case "initializing": return continueSession ? "Resuming agent..." : "Creating agent..."; case "assembling": @@ -187,14 +207,14 @@ function getStatusMessage( case "upserting": return "Upserting tools..."; case "linking": - return "Attaching Letta Code tools..."; + return "Attaching tools..."; case "unlinking": - return "Removing Letta Code tools..."; + return "Removing tools..."; case "importing": - return "Importing agent from template..."; + return "Importing agent..."; case "checking": return "Checking for pending approvals..."; default: - return ""; + return "Loading..."; } }