diff --git a/src/agent/defaults.ts b/src/agent/defaults.ts index f0e9534..24536cc 100644 --- a/src/agent/defaults.ts +++ b/src/agent/defaults.ts @@ -87,12 +87,20 @@ export async function ensureDefaultAgents( } try { - const { agent } = await createAgent(DEFAULT_AGENT_CONFIGS.memo); + // Pre-determine memfs mode so the agent is created with the correct prompt. + const { isLettaCloud, enableMemfsIfCloud } = await import( + "./memoryFilesystem" + ); + const willAutoEnableMemfs = await isLettaCloud(); + + const { agent } = await createAgent({ + ...DEFAULT_AGENT_CONFIGS.memo, + memoryPromptMode: willAutoEnableMemfs ? "memfs" : undefined, + }); await addTagToAgent(client, agent.id, MEMO_TAG); settingsManager.pinGlobal(agent.id); - // Enable memfs by default on Letta Cloud - const { enableMemfsIfCloud } = await import("./memoryFilesystem"); + // Enable memfs on Letta Cloud (tags, repo clone, tool detach). await enableMemfsIfCloud(agent.id); return agent; diff --git a/src/agent/memoryFilesystem.ts b/src/agent/memoryFilesystem.ts index 164ea65..fc6267a 100644 --- a/src/agent/memoryFilesystem.ts +++ b/src/agent/memoryFilesystem.ts @@ -146,6 +146,8 @@ export interface ApplyMemfsFlagsResult { export interface ApplyMemfsFlagsOptions { pullOnExistingRepo?: boolean; agentTags?: string[]; + /** Skip the system prompt update (when the agent was created with the correct mode). */ + skipPromptUpdate?: boolean; } /** @@ -169,20 +171,13 @@ export async function applyMemfsFlags( noMemfsFlag: boolean | undefined, options?: ApplyMemfsFlagsOptions, ): Promise { - const { getServerUrl } = await import("./client"); const { settingsManager } = await import("../settings-manager"); // Validate explicit enable on supported backend. - if (memfsFlag) { - const serverUrl = getServerUrl(); - if ( - !serverUrl.includes("api.letta.com") && - process.env.LETTA_MEMFS_LOCAL !== "1" - ) { - throw new Error( - "--memfs is only available on Letta Cloud (api.letta.com).", - ); - } + if (memfsFlag && !(await isLettaCloud())) { + throw new Error( + "--memfs is only available on Letta Cloud (api.letta.com).", + ); } const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag); @@ -202,13 +197,15 @@ export async function applyMemfsFlags( // 2. Reconcile system prompt first, then persist local memfs setting. if (hasExplicitToggle || shouldAutoEnableFromTag) { - const { updateAgentSystemPromptMemfs } = await import("./modify"); - const promptUpdate = await updateAgentSystemPromptMemfs( - agentId, - targetEnabled, - ); - if (!promptUpdate.success) { - throw new Error(promptUpdate.message); + if (!options?.skipPromptUpdate) { + const { updateAgentSystemPromptMemfs } = await import("./modify"); + const promptUpdate = await updateAgentSystemPromptMemfs( + agentId, + targetEnabled, + ); + if (!promptUpdate.success) { + throw new Error(promptUpdate.message); + } } settingsManager.setMemfsEnabled(agentId, targetEnabled); } @@ -281,20 +278,30 @@ export async function applyMemfsFlags( } /** - * Enable memfs for a newly created agent if on Letta Cloud. - * Non-fatal: logs a warning on failure. Skips on self-hosted. + * Whether the current server is Letta Cloud (or local memfs testing is enabled). */ -export async function enableMemfsIfCloud(agentId: string): Promise { +export async function isLettaCloud(): Promise { const { getServerUrl } = await import("./client"); const serverUrl = getServerUrl(); - if ( - !serverUrl.includes("api.letta.com") && - process.env.LETTA_MEMFS_LOCAL !== "1" - ) - return; + return ( + serverUrl.includes("api.letta.com") || process.env.LETTA_MEMFS_LOCAL === "1" + ); +} + +/** + * Enable memfs for a newly created agent if on Letta Cloud. + * Non-fatal: logs a warning on failure. Skips on self-hosted. + * + * Skips the system prompt update since callers are expected to create + * the agent with the correct memory mode upfront. + */ +export async function enableMemfsIfCloud(agentId: string): Promise { + if (!(await isLettaCloud())) return; try { - await applyMemfsFlags(agentId, true, undefined); + await applyMemfsFlags(agentId, true, undefined, { + skipPromptUpdate: true, + }); } catch (error) { console.warn( `Warning: Could not enable memfs for new agent: ${error instanceof Error ? error.message : String(error)}`, diff --git a/src/cli/App.tsx b/src/cli/App.tsx index 501dc00..a385d7e 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -6328,13 +6328,19 @@ export default function App({ const cmd = commandRunner.start(inputCmd, `Creating agent "${name}"...`); try { - // Create the new agent - const { agent } = await createAgent(name); - - // Enable memfs by default on Letta Cloud for new agents - const { enableMemfsIfCloud } = await import( + // Pre-determine memfs mode so the agent is created with the correct prompt. + const { isLettaCloud, enableMemfsIfCloud } = await import( "../agent/memoryFilesystem" ); + const willAutoEnableMemfs = await isLettaCloud(); + + // Create the new agent + const { agent } = await createAgent({ + name, + memoryPromptMode: willAutoEnableMemfs ? "memfs" : undefined, + }); + + // Enable memfs on Letta Cloud (tags, repo clone, tool detach). await enableMemfsIfCloud(agent.id); // Queue auto-init for first message if memfs is enabled diff --git a/src/headless.ts b/src/headless.ts index ad9d588..dd6b6eb 100644 --- a/src/headless.ts +++ b/src/headless.ts @@ -801,6 +801,15 @@ export async function handleHeadlessCommand( // Priority 3: Check if --new flag was passed (skip all resume logic) if (!agent && forceNew) { const updateArgs = getModelUpdateArgs(model); + // Pre-determine memfs mode so the agent is created with the correct prompt. + const { isLettaCloud, enableMemfsIfCloud } = await import( + "./agent/memoryFilesystem" + ); + const willAutoEnableMemfs = + shouldAutoEnableMemfsForNewAgent && (await isLettaCloud()); + const effectiveMemoryMode = + requestedMemoryPromptMode ?? (willAutoEnableMemfs ? "memfs" : undefined); + const createOptions = { model, embeddingModel, @@ -809,7 +818,7 @@ export async function handleHeadlessCommand( parallelToolCalls: true, systemPromptPreset, systemPromptCustom: systemCustom, - memoryPromptMode: requestedMemoryPromptMode, + memoryPromptMode: effectiveMemoryMode, initBlocks, baseTools, memoryBlocks, @@ -819,9 +828,8 @@ export async function handleHeadlessCommand( const result = await createAgent(createOptions); agent = result.agent; - // Enable memfs by default on Letta Cloud for new agents when no explicit memfs flags are provided. - if (shouldAutoEnableMemfsForNewAgent) { - const { enableMemfsIfCloud } = await import("./agent/memoryFilesystem"); + // Enable memfs on Letta Cloud (tags, repo clone, tool detach). + if (willAutoEnableMemfs) { await enableMemfsIfCloud(agent.id); } } diff --git a/src/index.ts b/src/index.ts index 7ca17c2..e7376a3 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1609,6 +1609,14 @@ async function main(): Promise { effectiveModel = getDefaultModelForTier(billingTier); } + // Pre-determine memfs mode so the agent is created with the correct prompt. + const { isLettaCloud } = await import("./agent/memoryFilesystem"); + const willAutoEnableMemfs = + shouldAutoEnableMemfsForNewAgent && (await isLettaCloud()); + const effectiveMemoryMode = + requestedMemoryPromptMode ?? + (willAutoEnableMemfs ? "memfs" : undefined); + const updateArgs = getModelUpdateArgs(effectiveModel); const result = await createAgent({ model: effectiveModel, @@ -1616,15 +1624,15 @@ async function main(): Promise { skillsDirectory, parallelToolCalls: true, systemPromptPreset, - memoryPromptMode: requestedMemoryPromptMode, + memoryPromptMode: effectiveMemoryMode, initBlocks, baseTools, }); agent = result.agent; setAgentProvenance(result.provenance); - // Enable memfs by default on Letta Cloud for new agents when no explicit memfs flags are provided. - if (shouldAutoEnableMemfsForNewAgent) { + // Enable memfs on Letta Cloud (tags, repo clone, tool detach). + if (willAutoEnableMemfs) { const { enableMemfsIfCloud } = await import( "./agent/memoryFilesystem" );