fix: Default agent creation on first bootup (#704)

This commit is contained in:
Devansh Jain
2026-01-27 13:56:26 -08:00
committed by GitHub
parent 2ce65ee99b
commit f1a56c5e87
2 changed files with 14 additions and 102 deletions

View File

@@ -47,21 +47,6 @@ export const DEFAULT_AGENT_CONFIGS: Record<string, CreateAgentOptions> = {
},
};
/**
* Check if a default agent exists by its tag.
*/
async function findDefaultAgent(
client: Letta,
tag: string,
): Promise<AgentState | null> {
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;
}

View File

@@ -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<void> {
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<void> {
);
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<void> {
}
}
// 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;
}