feat: auto-enable memfs from server-side tag on new machines (#1063)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-02-20 12:57:40 -08:00
committed by GitHub
parent 4569382d20
commit a13fb37d87
4 changed files with 41 additions and 14 deletions

View File

@@ -143,6 +143,11 @@ export interface ApplyMemfsFlagsResult {
pullSummary?: string;
}
export interface ApplyMemfsFlagsOptions {
pullOnExistingRepo?: boolean;
agentTags?: string[];
}
/**
* Apply --memfs / --no-memfs CLI flags (or /memfs enable) to an agent.
*
@@ -162,7 +167,7 @@ export async function applyMemfsFlags(
agentId: string,
memfsFlag: boolean | undefined,
noMemfsFlag: boolean | undefined,
options?: { pullOnExistingRepo?: boolean },
options?: ApplyMemfsFlagsOptions,
): Promise<ApplyMemfsFlagsResult> {
const { getServerUrl } = await import("./client");
const { settingsManager } = await import("../settings-manager");
@@ -181,14 +186,22 @@ export async function applyMemfsFlags(
}
const hasExplicitToggle = Boolean(memfsFlag || noMemfsFlag);
const localMemfsEnabled = settingsManager.isMemfsEnabled(agentId);
const { GIT_MEMORY_ENABLED_TAG } = await import("./memoryGit");
const shouldAutoEnableFromTag =
!hasExplicitToggle &&
!localMemfsEnabled &&
Boolean(options?.agentTags?.includes(GIT_MEMORY_ENABLED_TAG));
const targetEnabled = memfsFlag
? true
: noMemfsFlag
? false
: settingsManager.isMemfsEnabled(agentId);
: shouldAutoEnableFromTag
? true
: localMemfsEnabled;
// 2. Reconcile system prompt first, then persist local memfs setting.
if (hasExplicitToggle) {
if (hasExplicitToggle || shouldAutoEnableFromTag) {
const { updateAgentSystemPromptMemfs } = await import("./modify");
const promptUpdate = await updateAgentSystemPromptMemfs(
agentId,
@@ -200,16 +213,23 @@ export async function applyMemfsFlags(
settingsManager.setMemfsEnabled(agentId, targetEnabled);
}
const isEnabled = hasExplicitToggle
? targetEnabled
: settingsManager.isMemfsEnabled(agentId);
const isEnabled =
hasExplicitToggle || shouldAutoEnableFromTag
? targetEnabled
: settingsManager.isMemfsEnabled(agentId);
// 3. Detach old API-based memory tools when explicitly enabling.
if (isEnabled && memfsFlag) {
// 3. Detach old API-based memory tools when enabling.
if (isEnabled && (memfsFlag || shouldAutoEnableFromTag)) {
const { detachMemoryTools } = await import("../tools/toolset");
await detachMemoryTools(agentId);
}
// Keep server-side state aligned with explicit disable.
if (noMemfsFlag) {
const { removeGitMemoryTag } = await import("./memoryGit");
await removeGitMemoryTag(agentId);
}
// 4. Add git tag + clone/pull repo.
let pullSummary: string | undefined;
if (isEnabled) {
@@ -224,7 +244,12 @@ export async function applyMemfsFlags(
}
}
const action = memfsFlag ? "enabled" : noMemfsFlag ? "disabled" : "unchanged";
const action =
memfsFlag || shouldAutoEnableFromTag
? "enabled"
: noMemfsFlag
? "disabled"
: "unchanged";
return {
action,
memoryDir: isEnabled ? getMemoryFilesystemRoot(agentId) : undefined,

View File

@@ -26,7 +26,7 @@ import { getClient, getServerUrl } from "./client";
const execFile = promisify(execFileCb);
const GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
export const GIT_MEMORY_ENABLED_TAG = "git-memory-enabled";
/** Get the agent root directory (~/.letta/agents/{id}/) */
export function getAgentRootDir(agentId: string): string {

View File

@@ -916,14 +916,14 @@ export async function handleHeadlessCommand(
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
// Apply memfs flag if explicitly specified (memfs is opt-in via /memfs enable or --memfs)
// Apply memfs flags and auto-enable from server tag when local settings are missing.
try {
const { applyMemfsFlags } = await import("./agent/memoryFilesystem");
const memfsResult = await applyMemfsFlags(
agent.id,
memfsFlag,
noMemfsFlag,
{ pullOnExistingRepo: true },
{ pullOnExistingRepo: true, agentTags: agent.tags },
);
if (memfsResult.pullSummary?.includes("CONFLICT")) {
console.error(

View File

@@ -1767,11 +1767,13 @@ async function main(): Promise<void> {
// Set agent context for tools that need it (e.g., Skill tool)
setAgentContext(agent.id, skillsDirectory, resolvedSkillSources);
// Apply memfs flag if explicitly specified (memfs is opt-in via /memfs enable or --memfs)
// Apply memfs flags and auto-enable from server tag when local settings are missing.
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
try {
const { applyMemfsFlags } = await import("./agent/memoryFilesystem");
await applyMemfsFlags(agent.id, memfsFlag, noMemfsFlag);
await applyMemfsFlags(agent.id, memfsFlag, noMemfsFlag, {
agentTags: agent.tags,
});
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);