From 2c243151c61be9ea5caa294f21a86a2558d0ec21 Mon Sep 17 00:00:00 2001 From: Devansh Jain <31609257+devanshrj@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:15:15 -0800 Subject: [PATCH] refactor: remove parseArgs value casts in subcommands (#1157) --- src/cli/subcommands/agents.ts | 36 ++++++++------ src/cli/subcommands/blocks.ts | 46 ++++++++++-------- src/cli/subcommands/memfs.ts | 43 +++++++++-------- src/cli/subcommands/messages.ts | 85 ++++++++++++++++++++------------- 4 files changed, 122 insertions(+), 88 deletions(-) diff --git a/src/cli/subcommands/agents.ts b/src/cli/subcommands/agents.ts index bfcfd0a..b137ec9 100644 --- a/src/cli/subcommands/agents.ts +++ b/src/cli/subcommands/agents.ts @@ -38,23 +38,29 @@ function parseTags(value: unknown): string[] | undefined { return tags.length > 0 ? tags : undefined; } +const AGENTS_OPTIONS = { + help: { type: "boolean", short: "h" }, + name: { type: "string" }, + query: { type: "string" }, + tags: { type: "string" }, + "match-all-tags": { type: "boolean" }, + "include-blocks": { type: "boolean" }, + limit: { type: "string" }, +} as const; + +function parseAgentsArgs(argv: string[]) { + return parseArgs({ + args: argv, + options: AGENTS_OPTIONS, + strict: true, + allowPositionals: true, + }); +} + export async function runAgentsSubcommand(argv: string[]): Promise { - let parsed: ReturnType; + let parsed: ReturnType; try { - parsed = parseArgs({ - args: argv, - options: { - help: { type: "boolean", short: "h" }, - name: { type: "string" }, - query: { type: "string" }, - tags: { type: "string" }, - "match-all-tags": { type: "boolean" }, - "include-blocks": { type: "boolean" }, - limit: { type: "string" }, - }, - strict: true, - allowPositionals: true, - }); + parsed = parseAgentsArgs(argv); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.error(`Error: ${message}`); diff --git a/src/cli/subcommands/blocks.ts b/src/cli/subcommands/blocks.ts index 41e2a09..6a03631 100644 --- a/src/cli/subcommands/blocks.ts +++ b/src/cli/subcommands/blocks.ts @@ -27,6 +27,26 @@ function getAgentId(agentFromArgs?: string, agentIdFromArgs?: string): string { return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || ""; } +const BLOCKS_OPTIONS = { + help: { type: "boolean", short: "h" }, + agent: { type: "string" }, + "agent-id": { type: "string" }, + limit: { type: "string" }, + "block-id": { type: "string" }, + label: { type: "string" }, + override: { type: "boolean" }, + "read-only": { type: "boolean" }, +} as const; + +function parseBlocksArgs(argv: string[]) { + return parseArgs({ + args: argv, + options: BLOCKS_OPTIONS, + strict: true, + allowPositionals: true, + }); +} + type CopyBlockResult = { sourceBlock: Awaited< ReturnType>["blocks"]["retrieve"]> @@ -253,23 +273,9 @@ async function attachBlock( } export async function runBlocksSubcommand(argv: string[]): Promise { - let parsed: ReturnType; + let parsed: ReturnType; try { - parsed = parseArgs({ - args: argv, - options: { - help: { type: "boolean", short: "h" }, - agent: { type: "string" }, - "agent-id": { type: "string" }, - limit: { type: "string" }, - "block-id": { type: "string" }, - label: { type: "string" }, - override: { type: "boolean" }, - "read-only": { type: "boolean" }, - }, - strict: true, - allowPositionals: true, - }); + parsed = parseBlocksArgs(argv); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.error(`Error: ${message}`); @@ -306,8 +312,8 @@ export async function runBlocksSubcommand(argv: string[]): Promise { return 1; } const agentId = getAgentId( - parsed.values.agent as string | undefined, - parsed.values["agent-id"] as string | undefined, + parsed.values.agent, + parsed.values["agent-id"], ); const result = await copyBlock(client, blockId, { labelOverride: @@ -328,8 +334,8 @@ export async function runBlocksSubcommand(argv: string[]): Promise { return 1; } const agentId = getAgentId( - parsed.values.agent as string | undefined, - parsed.values["agent-id"] as string | undefined, + parsed.values.agent, + parsed.values["agent-id"], ); const result = await attachBlock(client, blockId, { readOnly: parsed.values["read-only"] === true, diff --git a/src/cli/subcommands/memfs.ts b/src/cli/subcommands/memfs.ts index 421a650..6c6032c 100644 --- a/src/cli/subcommands/memfs.ts +++ b/src/cli/subcommands/memfs.ts @@ -40,6 +40,24 @@ function getAgentId(agentFromArgs?: string, agentIdFromArgs?: string): string { return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || ""; } +const MEMFS_OPTIONS = { + help: { type: "boolean", short: "h" }, + agent: { type: "string" }, + "agent-id": { type: "string" }, + from: { type: "string" }, + force: { type: "boolean" }, + out: { type: "string" }, +} as const; + +function parseMemfsArgs(argv: string[]) { + return parseArgs({ + args: argv, + options: MEMFS_OPTIONS, + strict: true, + allowPositionals: true, + }); +} + function getMemoryRoot(agentId: string): string { return join(homedir(), ".letta", "agents", agentId, "memory"); } @@ -97,21 +115,9 @@ function resolveBackupPath(agentId: string, from: string): string { } export async function runMemfsSubcommand(argv: string[]): Promise { - let parsed: ReturnType; + let parsed: ReturnType; try { - parsed = parseArgs({ - args: argv, - options: { - help: { type: "boolean", short: "h" }, - agent: { type: "string" }, - "agent-id": { type: "string" }, - from: { type: "string" }, - force: { type: "boolean" }, - out: { type: "string" }, - }, - strict: true, - allowPositionals: true, - }); + parsed = parseMemfsArgs(argv); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.error(`Error: ${message}`); @@ -126,10 +132,7 @@ export async function runMemfsSubcommand(argv: string[]): Promise { return 0; } - const agentId = getAgentId( - parsed.values.agent as string | undefined, - parsed.values["agent-id"] as string | undefined, - ); + const agentId = getAgentId(parsed.values.agent, parsed.values["agent-id"]); if (!agentId) { console.error( @@ -204,7 +207,7 @@ export async function runMemfsSubcommand(argv: string[]): Promise { } if (action === "restore") { - const from = parsed.values.from as string | undefined; + const from = parsed.values.from; if (!from) { console.error("Missing --from ."); return 1; @@ -231,7 +234,7 @@ export async function runMemfsSubcommand(argv: string[]): Promise { } if (action === "export") { - const out = parsed.values.out as string | undefined; + const out = parsed.values.out; if (!out) { console.error("Missing --out ."); return 1; diff --git a/src/cli/subcommands/messages.ts b/src/cli/subcommands/messages.ts index d517914..748fc81 100644 --- a/src/cli/subcommands/messages.ts +++ b/src/cli/subcommands/messages.ts @@ -2,6 +2,7 @@ import { parseArgs } from "node:util"; import { getClient } from "../../agent/client"; type SearchMode = "vector" | "fts" | "hybrid"; +type ListOrder = "asc" | "desc"; function printUsage(): void { console.log( @@ -52,32 +53,45 @@ function parseMode(value: unknown): SearchMode | undefined { return undefined; } +function parseOrder(value: unknown): ListOrder | undefined { + if (typeof value === "string" && (value === "asc" || value === "desc")) { + return value; + } + return undefined; +} + function getAgentId(agentFromArgs?: string, agentIdFromArgs?: string): string { return agentFromArgs || agentIdFromArgs || process.env.LETTA_AGENT_ID || ""; } +const MESSAGES_OPTIONS = { + help: { type: "boolean", short: "h" }, + query: { type: "string" }, + mode: { type: "string" }, + "start-date": { type: "string" }, + "end-date": { type: "string" }, + limit: { type: "string" }, + "all-agents": { type: "boolean" }, + agent: { type: "string" }, + "agent-id": { type: "string" }, + after: { type: "string" }, + before: { type: "string" }, + order: { type: "string" }, +} as const; + +function parseMessagesArgs(argv: string[]) { + return parseArgs({ + args: argv, + options: MESSAGES_OPTIONS, + strict: true, + allowPositionals: true, + }); +} + export async function runMessagesSubcommand(argv: string[]): Promise { - let parsed: ReturnType; + let parsed: ReturnType; try { - parsed = parseArgs({ - args: argv, - options: { - help: { type: "boolean", short: "h" }, - query: { type: "string" }, - mode: { type: "string" }, - "start-date": { type: "string" }, - "end-date": { type: "string" }, - limit: { type: "string" }, - "all-agents": { type: "boolean" }, - agent: { type: "string" }, - "agent-id": { type: "string" }, - after: { type: "string" }, - before: { type: "string" }, - order: { type: "string" }, - }, - strict: true, - allowPositionals: true, - }); + parsed = parseMessagesArgs(argv); } catch (error) { const message = error instanceof Error ? error.message : String(error); console.error(`Error: ${message}`); @@ -103,8 +117,8 @@ export async function runMessagesSubcommand(argv: string[]): Promise { const allAgents = parsed.values["all-agents"] ?? false; const agentId = getAgentId( - parsed.values.agent as string | undefined, - parsed.values["agent-id"] as string | undefined, + parsed.values.agent, + parsed.values["agent-id"], ); if (!allAgents && !agentId) { console.error( @@ -117,8 +131,8 @@ export async function runMessagesSubcommand(argv: string[]): Promise { query, agent_id: allAgents ? undefined : agentId, search_mode: parseMode(parsed.values.mode) ?? "hybrid", - start_date: parsed.values["start-date"] as string | undefined, - end_date: parsed.values["end-date"] as string | undefined, + start_date: parsed.values["start-date"], + end_date: parsed.values["end-date"], limit: parseLimit(parsed.values.limit, 10), }); @@ -128,8 +142,8 @@ export async function runMessagesSubcommand(argv: string[]): Promise { if (action === "list") { const agentId = getAgentId( - parsed.values.agent as string | undefined, - parsed.values["agent-id"] as string | undefined, + parsed.values.agent, + parsed.values["agent-id"], ); if (!agentId) { console.error( @@ -138,11 +152,18 @@ export async function runMessagesSubcommand(argv: string[]): Promise { return 1; } + const orderRaw = parsed.values.order; + const order = parseOrder(orderRaw); + if (orderRaw !== undefined && !order) { + console.error(`Invalid --order "${orderRaw}". Use "asc" or "desc".`); + return 1; + } + const response = await client.agents.messages.list(agentId, { limit: parseLimit(parsed.values.limit, 20), - after: parsed.values.after as string | undefined, - before: parsed.values.before as string | undefined, - order: parsed.values.order as "asc" | "desc" | undefined, + after: parsed.values.after, + before: parsed.values.before, + order, }); const messages = response.items ?? []; @@ -151,11 +172,9 @@ export async function runMessagesSubcommand(argv: string[]): Promise { let filtered = messages; if (startDate || endDate) { - const startTime = startDate - ? new Date(startDate as string).getTime() - : 0; + const startTime = startDate ? new Date(startDate).getTime() : 0; const endTime = endDate - ? new Date(endDate as string).getTime() + ? new Date(endDate).getTime() : Number.POSITIVE_INFINITY; filtered = messages.filter((msg) => { if (!("date" in msg) || !msg.date) return true;