feat: add --conv flag to listen subcommand (#1070)

This commit is contained in:
Kian Jones
2026-02-20 16:37:00 -08:00
committed by GitHub
parent a16acfddeb
commit 539ce175e5
3 changed files with 28 additions and 6 deletions

View File

@@ -5,6 +5,7 @@ import { useEffect, useState } from "react";
interface ListenerStatusUIProps {
agentId: string;
connectionId: string;
conversationId?: string;
onReady: (callbacks: {
updateStatus: (status: "idle" | "receiving" | "processing") => void;
updateRetryStatus: (attempt: number, nextRetryIn: number) => void;
@@ -13,7 +14,7 @@ interface ListenerStatusUIProps {
}
export function ListenerStatusUI(props: ListenerStatusUIProps) {
const { agentId, connectionId, onReady } = props;
const { agentId, connectionId, conversationId, onReady } = props;
const [status, setStatus] = useState<"idle" | "receiving" | "processing">(
"idle",
);
@@ -34,7 +35,7 @@ export function ListenerStatusUI(props: ListenerStatusUIProps) {
});
}, [onReady]);
const adeUrl = `https://app.letta.com/agents/${agentId}?deviceId=${connectionId}`;
const adeUrl = `https://app.letta.com/agents/${agentId}?deviceId=${connectionId}${conversationId ? `&conversationId=${conversationId}` : ""}`;
const statusText = retryInfo
? `Reconnecting (attempt ${retryInfo.attempt}, retry in ${Math.round(retryInfo.nextRetryIn / 1000)}s)`

View File

@@ -10,12 +10,18 @@ import { settingsManager } from "../../settings-manager";
import { ListenerStatusUI } from "../components/ListenerStatusUI";
export async function runListenSubcommand(argv: string[]): Promise<number> {
// Preprocess args to support --conv as alias for --conversation
const processedArgv = argv.map((arg) =>
arg === "--conv" ? "--conversation" : arg,
);
// Parse arguments
const { values } = parseArgs({
args: argv,
args: processedArgv,
options: {
name: { type: "string" },
agent: { type: "string" },
conversation: { type: "string", short: "C" },
help: { type: "boolean", short: "h" },
},
allowPositionals: false,
@@ -24,7 +30,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
// Show help
if (values.help) {
console.log(
"Usage: letta listen --name <connection-name> [--agent <agent-id>]\n",
"Usage: letta listen --name <connection-name> [--agent <agent-id>] [--conversation <id>]\n",
);
console.log(
"Register this letta-code instance to receive messages from Letta Cloud.\n",
@@ -36,10 +42,17 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
console.log(
" --agent <id> Bind connection to specific agent (required for CLI usage)",
);
console.log(" --conversation <id>, --conv <id>, -C <id>");
console.log(
" Route messages to a specific conversation",
);
console.log(" -h, --help Show this help message\n");
console.log("Examples:");
console.log(' letta listen --name "george" --agent agent-abc123');
console.log(' letta listen --name "laptop-work" --agent agent-xyz789\n');
console.log(' letta listen --name "laptop-work" --agent agent-xyz789');
console.log(
' letta listen --name "daily-cron" --agent agent-abc123 --conv conv-xyz789\n',
);
console.log(
"Once connected, this instance will listen for incoming messages from cloud agents.",
);
@@ -51,6 +64,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
const connectionName = values.name;
const agentId = values.agent;
const conversationId = values.conversation as string | undefined;
if (!connectionName) {
console.error("Error: --name is required\n");
@@ -102,6 +116,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
deviceId,
connectionName,
agentId,
...(conversationId && { conversationId }),
}),
});
@@ -131,6 +146,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
<ListenerStatusUI
agentId={agentId}
connectionId={connectionId}
conversationId={conversationId}
onReady={(callbacks) => {
updateStatusCallback = callbacks.updateStatus;
updateRetryStatusCallback = callbacks.updateRetryStatus;
@@ -150,6 +166,7 @@ export async function runListenSubcommand(argv: string[]): Promise<number> {
deviceId,
connectionName,
agentId,
defaultConversationId: conversationId,
onStatusChange: (status) => {
clearRetryStatusCallback?.();
updateStatusCallback?.(status);

View File

@@ -34,6 +34,7 @@ interface StartListenerOptions {
deviceId: string;
connectionName: string;
agentId?: string;
defaultConversationId?: string;
onConnected: () => void;
onDisconnected: () => void;
onError: (error: Error) => void;
@@ -438,6 +439,7 @@ async function connectWithRetry(
socket,
opts.onStatusChange,
opts.connectionId,
opts.defaultConversationId,
);
opts.onStatusChange?.("idle", opts.connectionId);
})
@@ -502,6 +504,7 @@ async function handleIncomingMessage(
connectionId: string,
) => void,
connectionId?: string,
defaultConversationId?: string,
): Promise<void> {
try {
const agentId = msg.agentId;
@@ -512,7 +515,8 @@ async function handleIncomingMessage(
const requestedConversationId = msg.conversationId || undefined;
// For sendMessageStream: "default" means use agent endpoint, else use conversations endpoint
const conversationId = requestedConversationId ?? "default";
const conversationId =
requestedConversationId ?? defaultConversationId ?? "default";
if (!agentId) {
return;