From f1a56c5e87054151a9d78117577f376e55feb400 Mon Sep 17 00:00:00 2001 From: Devansh Jain <31609257+devanshrj@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:56:26 -0800 Subject: [PATCH] fix: Default agent creation on first bootup (#704) --- src/agent/defaults.ts | 51 ++++++--------------------------- src/index.ts | 65 ++++--------------------------------------- 2 files changed, 14 insertions(+), 102 deletions(-) diff --git a/src/agent/defaults.ts b/src/agent/defaults.ts index b23df65..d124d77 100644 --- a/src/agent/defaults.ts +++ b/src/agent/defaults.ts @@ -47,21 +47,6 @@ export const DEFAULT_AGENT_CONFIGS: Record = { }, }; -/** - * Check if a default agent exists by its tag. - */ -async function findDefaultAgent( - client: Letta, - tag: string, -): Promise { - try { - const result = await client.agents.list({ tags: [tag], limit: 1 }); - return result.items[0] ?? null; - } catch { - return null; - } -} - /** * Add a tag to an existing agent. */ @@ -86,7 +71,10 @@ async function addTagToAgent( } /** - * Ensure default agents exist. Creates missing ones and pins them globally. + * Create a fresh default Memo agent and pin it globally. + * Always creates a new agent — does NOT search by tag to avoid picking up + * agents created by other users on shared Letta Cloud orgs. + * * Respects `createDefaultAgents` setting (defaults to true). * * @returns The Memo agent (or null if creation disabled/failed). @@ -98,38 +86,15 @@ export async function ensureDefaultAgents( return null; } - let memoAgent: AgentState | null = null; - try { - // Check/create Memo - const existingMemo = await findDefaultAgent(client, MEMO_TAG); - if (existingMemo) { - memoAgent = existingMemo; - // Ensure it's pinned (might not be if settings were cleared or new machine) - settingsManager.pinGlobal(existingMemo.id); - } else { - const { agent } = await createAgent(DEFAULT_AGENT_CONFIGS.memo); - await addTagToAgent(client, agent.id, MEMO_TAG); - memoAgent = agent; - settingsManager.pinGlobal(agent.id); - } - - // NOTE: Incognito agent creation disabled for now - can be re-enabled later - // const existingIncognito = await findDefaultAgent(client, INCOGNITO_TAG); - // if (existingIncognito) { - // // Ensure it's pinned (might not be if settings were cleared or new machine) - // settingsManager.pinGlobal(existingIncognito.id); - // } else { - // const { agent } = await createAgent(DEFAULT_AGENT_CONFIGS.incognito); - // await addTagToAgent(client, agent.id, INCOGNITO_TAG); - // settingsManager.pinGlobal(agent.id); - // } + const { agent } = await createAgent(DEFAULT_AGENT_CONFIGS.memo); + await addTagToAgent(client, agent.id, MEMO_TAG); + settingsManager.pinGlobal(agent.id); + return agent; } catch (err) { // Re-throw so caller can handle/exit appropriately throw new Error( `Failed to create default agents: ${err instanceof Error ? err.message : String(err)}`, ); } - - return memoAgent; } diff --git a/src/index.ts b/src/index.ts index 095212e..7fad22b 100755 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ import { setConversationId as setContextConversationId, } from "./agent/context"; import type { AgentProvenance } from "./agent/create"; -import { INCOGNITO_TAG, MEMO_TAG } from "./agent/defaults"; + import { ensureSkillsBlocks, ISOLATED_BLOCK_LABELS } from "./agent/memory"; import { LETTA_CLOUD_API_URL } from "./auth/oauth"; import { ConversationSelector } from "./cli/components/ConversationSelector"; @@ -29,37 +29,6 @@ import { markMilestone } from "./utils/timing"; const EMPTY_APPROVAL_ARRAY: ApprovalRequest[] = []; const EMPTY_MESSAGE_ARRAY: Message[] = []; -/** - * Check if pinned agents consist only of default agents (Memo + Incognito). - * Used to auto-select Memo for fresh users without showing a selector. - */ -async function hasOnlyDefaultAgents( - pinnedIds: string[], -): Promise<{ onlyDefaults: boolean; memoId: string | null }> { - if (pinnedIds.length === 0) return { onlyDefaults: true, memoId: null }; - if (pinnedIds.length > 2) return { onlyDefaults: false, memoId: null }; - - const client = await getClient(); - let memoId: string | null = null; - - for (const id of pinnedIds) { - try { - const agent = await client.agents.retrieve(id); - const tags = agent.tags || []; - if (tags.includes(MEMO_TAG)) { - memoId = agent.id; - } else if (!tags.includes(INCOGNITO_TAG)) { - // Found a non-default agent - return { onlyDefaults: false, memoId: null }; - } - } catch { - // Agent doesn't exist, skip it - } - } - - return { onlyDefaults: true, memoId }; -} - function printHelp() { // Keep this plaintext (no colors) so output pipes cleanly const usage = ` @@ -1295,18 +1264,13 @@ async function main(): Promise { const wouldShowSelector = !localSettings.lastAgent && !forceNew && !agentIdArg && !fromAfFile; - // Ensure default agents (Memo/Incognito) exist for all users - const { ensureDefaultAgents } = await import("./agent/defaults"); - if (wouldShowSelector && globalPinned.length === 0) { - // New user with no agents - create defaults first, then trigger init - // NOTE: Don't set loadingState to "assembling" until we have the agent ID, - // otherwise init will run before we've set selectedGlobalAgentId + // New user with no pinned agents - create a fresh Memo agent + // NOTE: Always creates a new agent (no server-side tag lookup) to avoid + // picking up agents created by other users on shared orgs. + const { ensureDefaultAgents } = await import("./agent/defaults"); try { const memoAgent = await ensureDefaultAgents(client); - // Refresh pinned list after defaults created - globalPinned = settingsManager.getGlobalPinnedAgents(); - // Auto-select Memo for fresh users if (memoAgent) { setSelectedGlobalAgentId(memoAgent.id); setLoadingState("assembling"); @@ -1319,11 +1283,6 @@ async function main(): Promise { ); process.exit(1); } - } else { - // Existing user - fire and forget, don't block startup - ensureDefaultAgents(client).catch(() => { - // Silently ignore - defaults may already exist - }); } // If there's a local LRU, use it directly @@ -1340,20 +1299,8 @@ async function main(): Promise { } } - // Check if we should show selector or auto-select Memo + // Show selector if there are pinned agents to choose from if (wouldShowSelector && globalPinned.length > 0) { - // Check if only default agents are pinned - const { onlyDefaults, memoId } = - await hasOnlyDefaultAgents(globalPinned); - - if (onlyDefaults && memoId) { - // Only defaults pinned - auto-select Memo - setSelectedGlobalAgentId(memoId); - setLoadingState("assembling"); - return; - } - - // Has custom agents - show selector setLoadingState("selecting_global"); return; }