fix: Fixed status line and updated welcome screen (#156)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
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 { getVersion } from "../../version";
|
||||
import { useTerminalWidth } from "../hooks/useTerminalWidth";
|
||||
import { asciiLogo } from "./AsciiArt";
|
||||
@@ -15,15 +16,92 @@ type LoadingState =
|
||||
| "checking"
|
||||
| "ready";
|
||||
|
||||
/**
|
||||
* Generate status hints based on session type and block provenance.
|
||||
* Pure function - no React dependencies.
|
||||
*/
|
||||
export function getAgentStatusHints(
|
||||
continueSession: boolean,
|
||||
agentState?: Letta.AgentState | null,
|
||||
agentProvenance?: AgentProvenance | null,
|
||||
): string[] {
|
||||
const hints: string[] = [];
|
||||
|
||||
// For resumed agents, show memory blocks and --new hint
|
||||
if (continueSession) {
|
||||
if (agentState?.memory?.blocks) {
|
||||
const blocks = agentState.memory.blocks;
|
||||
const count = blocks.length;
|
||||
const labels = blocks
|
||||
.map((b) => b.label)
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
if (labels) {
|
||||
hints.push(
|
||||
`→ Attached ${count} memory block${count !== 1 ? "s" : ""}: ${labels}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
hints.push("→ To create a new agent, use --new");
|
||||
return hints;
|
||||
}
|
||||
|
||||
// For new agents with provenance, show block sources
|
||||
if (agentProvenance) {
|
||||
// Blocks reused from existing storage
|
||||
const reusedGlobalBlocks = agentProvenance.blocks
|
||||
.filter((b) => b.source === "global")
|
||||
.map((b) => b.label);
|
||||
const reusedProjectBlocks = agentProvenance.blocks
|
||||
.filter((b) => b.source === "project")
|
||||
.map((b) => b.label);
|
||||
|
||||
// New blocks - categorize by where they'll be stored
|
||||
// (project/skills → .letta/, others → ~/.letta/)
|
||||
const newBlocks = agentProvenance.blocks.filter((b) => b.source === "new");
|
||||
const newGlobalBlocks = newBlocks
|
||||
.filter((b) => b.label !== "project" && b.label !== "skills")
|
||||
.map((b) => b.label);
|
||||
const newProjectBlocks = newBlocks
|
||||
.filter((b) => b.label === "project" || b.label === "skills")
|
||||
.map((b) => b.label);
|
||||
|
||||
if (reusedGlobalBlocks.length > 0) {
|
||||
hints.push(
|
||||
`→ Reusing from global (~/.letta/): ${reusedGlobalBlocks.join(", ")}`,
|
||||
);
|
||||
}
|
||||
if (newGlobalBlocks.length > 0) {
|
||||
hints.push(
|
||||
`→ Created in global (~/.letta/): ${newGlobalBlocks.join(", ")}`,
|
||||
);
|
||||
}
|
||||
if (reusedProjectBlocks.length > 0) {
|
||||
hints.push(
|
||||
`→ Reusing from project (.letta/): ${reusedProjectBlocks.join(", ")}`,
|
||||
);
|
||||
}
|
||||
if (newProjectBlocks.length > 0) {
|
||||
hints.push(
|
||||
`→ Created in project (.letta/): ${newProjectBlocks.join(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return hints;
|
||||
}
|
||||
|
||||
export function WelcomeScreen({
|
||||
loadingState,
|
||||
continueSession,
|
||||
agentState,
|
||||
agentProvenance,
|
||||
terminalWidth: frozenWidth,
|
||||
}: {
|
||||
loadingState: LoadingState;
|
||||
continueSession?: boolean;
|
||||
agentState?: Letta.AgentState | null;
|
||||
agentProvenance?: AgentProvenance | null;
|
||||
terminalWidth?: number;
|
||||
}) {
|
||||
const currentWidth = useTerminalWidth();
|
||||
@@ -32,94 +110,20 @@ export function WelcomeScreen({
|
||||
const version = getVersion();
|
||||
const agentId = agentState?.id;
|
||||
|
||||
// Split logo into lines for side-by-side rendering
|
||||
const logoLines = asciiLogo.trim().split("\n");
|
||||
|
||||
// Determine verbosity level based on terminal width
|
||||
const isWide = terminalWidth >= 120;
|
||||
const isMedium = terminalWidth >= 80;
|
||||
|
||||
const getMemoryBlocksText = () => {
|
||||
if (!agentState?.memory?.blocks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const blocks = agentState.memory.blocks;
|
||||
const count = blocks.length;
|
||||
const labels = blocks
|
||||
.map((b) => b.label)
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
|
||||
if (isWide && labels) {
|
||||
return `attached ${count} memory block${count !== 1 ? "s" : ""} (${labels})`;
|
||||
}
|
||||
if (isMedium) {
|
||||
return `attached ${count} memory block${count !== 1 ? "s" : ""}`;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const getAgentMessage = () => {
|
||||
if (loadingState === "ready") {
|
||||
const memoryText = getMemoryBlocksText();
|
||||
const baseText =
|
||||
continueSession && agentId
|
||||
? "Resumed agent"
|
||||
: agentId
|
||||
? "Created a new agent"
|
||||
: "Ready to go!";
|
||||
|
||||
if (memoryText) {
|
||||
return `${baseText}, ${memoryText}`;
|
||||
}
|
||||
return baseText;
|
||||
}
|
||||
if (loadingState === "initializing") {
|
||||
return continueSession ? "Resuming agent..." : "Creating agent...";
|
||||
}
|
||||
if (loadingState === "assembling") {
|
||||
return "Assembling tools...";
|
||||
}
|
||||
if (loadingState === "upserting") {
|
||||
return "Upserting tools...";
|
||||
}
|
||||
if (loadingState === "linking") {
|
||||
return "Attaching Letta Code tools...";
|
||||
}
|
||||
if (loadingState === "unlinking") {
|
||||
return "Removing Letta Code tools...";
|
||||
}
|
||||
if (loadingState === "checking") {
|
||||
return "Checking for pending approvals...";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const getPathLine = () => {
|
||||
if (isMedium) {
|
||||
return `Running in ${cwd}`;
|
||||
}
|
||||
return cwd;
|
||||
};
|
||||
|
||||
const getAgentLink = () => {
|
||||
if (loadingState === "ready" && agentId) {
|
||||
const url = `https://app.letta.com/agents/${agentId}`;
|
||||
if (isWide) {
|
||||
return { text: url, url };
|
||||
}
|
||||
if (isMedium) {
|
||||
return { text: agentId, url };
|
||||
}
|
||||
return { text: "Click to view in ADE", url };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const agentMessage = getAgentMessage();
|
||||
const pathLine = getPathLine();
|
||||
const agentLink = getAgentLink();
|
||||
const statusMessage = getStatusMessage(
|
||||
loadingState,
|
||||
!!continueSession,
|
||||
agentId,
|
||||
);
|
||||
const pathLine = isMedium ? `Running in ${cwd}` : cwd;
|
||||
const agentUrl = agentId ? `https://app.letta.com/agents/${agentId}` : null;
|
||||
const hints =
|
||||
loadingState === "ready"
|
||||
? getAgentStatusHints(!!continueSession, agentState, agentProvenance)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Box flexDirection="row" marginTop={1}>
|
||||
@@ -139,13 +143,55 @@ export function WelcomeScreen({
|
||||
Letta Code v{version}
|
||||
</Text>
|
||||
<Text dimColor>{pathLine}</Text>
|
||||
{agentMessage && <Text dimColor>{agentMessage}</Text>}
|
||||
{agentLink && (
|
||||
<Link url={agentLink.url}>
|
||||
<Text dimColor>{agentLink.text}</Text>
|
||||
</Link>
|
||||
{statusMessage && (
|
||||
<Text dimColor>
|
||||
{statusMessage}
|
||||
{loadingState === "ready" && agentUrl && (
|
||||
<>
|
||||
{": "}
|
||||
<Link url={agentUrl}>
|
||||
<Text dimColor>{agentUrl}</Text>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
{hints.map((hint, idx) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Hint lines are static and never reorder
|
||||
<Text key={idx} dimColor>
|
||||
{hint}
|
||||
</Text>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function getStatusMessage(
|
||||
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":
|
||||
return "Assembling tools...";
|
||||
case "upserting":
|
||||
return "Upserting tools...";
|
||||
case "linking":
|
||||
return "Attaching Letta Code tools...";
|
||||
case "unlinking":
|
||||
return "Removing Letta Code tools...";
|
||||
case "checking":
|
||||
return "Checking for pending approvals...";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user