diff --git a/src/cli/App.tsx b/src/cli/App.tsx index be8451d..6549fa6 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -224,11 +224,9 @@ import { import { formatCompact } from "./helpers/format"; import { parsePatchOperations } from "./helpers/formatArgsDisplay"; import { - buildLegacyInitMessage, - buildMemoryInitRuntimePrompt, + buildInitMessage, fireAutoInit, gatherGitContext, - hasActiveInitSubagent, } from "./helpers/initCommand"; import { getReflectionSettings, @@ -1711,27 +1709,12 @@ export default function App({ const [showExitStats, setShowExitStats] = useState(false); const sharedReminderStateRef = useRef(createSharedReminderState()); - // Per-agent init progression — survives agent/conversation switches unlike SharedReminderState. - const initProgressByAgentRef = useRef( - new Map(), - ); const systemPromptRecompileByConversationRef = useRef( new Map>(), ); const queuedSystemPromptRecompileByConversationRef = useRef( new Set(), ); - const updateInitProgress = ( - forAgentId: string, - update: Partial<{ shallowCompleted: boolean; deepFired: boolean }>, - ) => { - const progress = initProgressByAgentRef.current.get(forAgentId) ?? { - shallowCompleted: false, - deepFired: false, - }; - Object.assign(progress, update); - initProgressByAgentRef.current.set(forAgentId, progress); - }; // Track if we've set the conversation summary for this new conversation // Initialized to true for resumed conversations (they already have context) @@ -9261,7 +9244,6 @@ export default function App({ if (trimmed === "/init") { const cmd = commandRunner.start(msg, "Gathering project context..."); - // Check for pending approvals before either path const approvalCheck = await checkPendingApprovalsForSlashCommand(); if (approvalCheck.blocked) { cmd.fail( @@ -9270,112 +9252,38 @@ export default function App({ return { submitted: false }; } - const gitContext = gatherGitContext(); + // Interactive init: the primary agent conducts the flow, + // asks the user questions, and runs the initializing-memory skill. + autoInitPendingAgentIdsRef.current.delete(agentId); + setCommandRunning(true); + try { + cmd.finish( + "Building your memory palace... Start a new conversation with `letta --new` to work in parallel.", + true, + ); - if (settingsManager.isMemfsEnabled(agentId)) { - // MemFS path: background subagent - if (hasActiveInitSubagent()) { - cmd.fail( - "Memory initialization is already running in the background.", - ); - return { submitted: true }; - } + const gitContext = gatherGitContext(); + const memoryDir = settingsManager.isMemfsEnabled(agentId) + ? getMemoryFilesystemRoot(agentId) + : undefined; - try { - const initPrompt = buildMemoryInitRuntimePrompt({ - agentId, - workingDirectory: process.cwd(), - memoryDir: getMemoryFilesystemRoot(agentId), - gitContext, - depth: "deep", - }); + const initMessage = buildInitMessage({ + gitContext, + memoryDir, + }); - const { spawnBackgroundSubagentTask } = await import( - "../tools/impl/Task" - ); - spawnBackgroundSubagentTask({ - subagentType: "init", - prompt: initPrompt, - description: "Initializing memory", - silentCompletion: true, - onComplete: async ({ success, error }) => { - const msg = await handleMemorySubagentCompletion( - { - agentId, - conversationId: conversationIdRef.current, - subagentType: "init", - initDepth: "deep", - success, - error, - }, - { - recompileByConversation: - systemPromptRecompileByConversationRef.current, - recompileQueuedByConversation: - queuedSystemPromptRecompileByConversationRef.current, - updateInitProgress, - logRecompileFailure: (message) => - debugWarn("memory", message), - }, - ); - appendTaskNotificationEvents([msg]); - }, - }); - - // Clear pending auto-init only after spawn succeeded - autoInitPendingAgentIdsRef.current.delete(agentId); - - cmd.finish( - "Learning about you and your codebase in the background. You'll be notified when ready.", - true, - ); - - // TODO: Remove this hack once commandRunner supports a - // "silent" finish that skips the reminder callback. - // Currently cmd.finish() always enqueues a command-IO - // reminder, which leaks the /init context into the - // primary agent's next turn and causes it to invoke the - // initializing-memory skill itself. - const reminders = - sharedReminderStateRef.current.pendingCommandIoReminders; - const idx = reminders.findIndex((r) => r.input === "/init"); - if (idx !== -1) { - reminders.splice(idx, 1); - } - } catch (error) { - const errorDetails = formatErrorDetails(error, agentId); - cmd.fail( - `Failed to start memory initialization: ${errorDetails}`, - ); - } - } else { - // Legacy path: primary agent processConversation - autoInitPendingAgentIdsRef.current.delete(agentId); - setCommandRunning(true); - try { - cmd.finish( - "Assimilating project context and defragmenting memories...", - true, - ); - - const initMessage = buildLegacyInitMessage({ - gitContext, - memfsSection: "", - }); - - await processConversation([ - { - type: "message", - role: "user", - content: buildTextParts(initMessage), - }, - ]); - } catch (error) { - const errorDetails = formatErrorDetails(error, agentId); - cmd.fail(`Failed: ${errorDetails}`); - } finally { - setCommandRunning(false); - } + await processConversation([ + { + type: "message", + role: "user", + content: buildTextParts(initMessage), + }, + ]); + } catch (error) { + const errorDetails = formatErrorDetails(error, agentId); + cmd.fail(`Failed: ${errorDetails}`); + } finally { + setCommandRunning(false); } return { submitted: true }; } @@ -9493,7 +9401,6 @@ export default function App({ agentId, conversationId: conversationIdRef.current, subagentType: "init", - initDepth: "shallow", success, error, }, @@ -9502,7 +9409,6 @@ export default function App({ systemPromptRecompileByConversationRef.current, recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current, - updateInitProgress, logRecompileFailure: (message) => debugWarn("memory", message), }, @@ -9632,7 +9538,6 @@ ${SYSTEM_REMINDER_CLOSE} systemPromptRecompileByConversationRef.current, recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current, - updateInitProgress, logRecompileFailure: (message) => debugWarn("memory", message), }, @@ -9655,72 +9560,10 @@ ${SYSTEM_REMINDER_CLOSE} return false; } }; - const maybeLaunchDeepInitSubagent = async () => { - if (!memfsEnabledForAgent) return false; - if (hasActiveInitSubagent()) return false; - try { - const gitContext = gatherGitContext(); - const initPrompt = buildMemoryInitRuntimePrompt({ - agentId, - workingDirectory: process.cwd(), - memoryDir: getMemoryFilesystemRoot(agentId), - gitContext, - depth: "deep", - }); - const { spawnBackgroundSubagentTask } = await import( - "../tools/impl/Task" - ); - spawnBackgroundSubagentTask({ - subagentType: "init", - prompt: initPrompt, - description: "Deep memory initialization", - silentCompletion: true, - onComplete: async ({ success, error }) => { - const msg = await handleMemorySubagentCompletion( - { - agentId, - conversationId: conversationIdRef.current, - subagentType: "init", - initDepth: "deep", - success, - error, - }, - { - recompileByConversation: - systemPromptRecompileByConversationRef.current, - recompileQueuedByConversation: - queuedSystemPromptRecompileByConversationRef.current, - updateInitProgress, - logRecompileFailure: (message) => - debugWarn("memory", message), - }, - ); - appendTaskNotificationEvents([msg]); - }, - }); - debugLog("memory", "Auto-launched deep init subagent"); - return true; - } catch (error) { - debugWarn( - "memory", - `Failed to auto-launch deep init subagent: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - return false; - } - }; syncReminderStateFromContextTracker( sharedReminderStateRef.current, contextTrackerRef.current, ); - // Hydrate init progression from the per-agent map into the shared state - // so the deep-init provider sees the correct flags for the current agent. - const initProgress = initProgressByAgentRef.current.get(agentId); - sharedReminderStateRef.current.shallowInitCompleted = - initProgress?.shallowCompleted ?? false; - sharedReminderStateRef.current.deepInitFired = - initProgress?.deepFired ?? false; const { getSkillSources } = await import("../agent/context"); const { parts: sharedReminderParts } = await buildSharedReminderParts({ mode: "interactive", @@ -9736,7 +9579,6 @@ ${SYSTEM_REMINDER_CLOSE} skillSources: getSkillSources(), resolvePlanModeReminder: getPlanModeReminder, maybeLaunchReflectionSubagent, - maybeLaunchDeepInitSubagent, }); for (const part of sharedReminderParts) { reminderParts.push(part); diff --git a/src/cli/helpers/initCommand.ts b/src/cli/helpers/initCommand.ts index b840d35..c2b6a40 100644 --- a/src/cli/helpers/initCommand.ts +++ b/src/cli/helpers/initCommand.ts @@ -76,7 +76,7 @@ ${recentCommits} } } -// ── Depth instructions ──────────────────────────────────── +// ── Shallow init (background subagent) ─────────────────── const SHALLOW_INSTRUCTIONS = ` Shallow init — fast project basics only (~5 tool calls max): @@ -87,25 +87,13 @@ Shallow init — fast project basics only (~5 tool calls max): - Skip: deep directory exploration, architecture mapping, config analysis, historical sessions, persona files, reflection/checkpoint phase `.trim(); -const DEEP_INSTRUCTIONS = ` -Deep init — full exploration (follow the initializing-memory skill fully): -- Read all existing memory files first — do NOT recreate what already exists -- Then follow the full initializing-memory skill as your operating guide -- Expand and deepen existing shallow files, add new ones to reach 15-25 target -- If shallow init already ran, build on its output rather than starting over -`.trim(); - -// ── Prompt builders ──────────────────────────────────────── - -/** Prompt for the background init subagent (MemFS path). */ -export function buildMemoryInitRuntimePrompt(args: { +/** Prompt for the background shallow-init subagent. */ +export function buildShallowInitPrompt(args: { agentId: string; workingDirectory: string; memoryDir: string; gitContext: string; - depth?: "shallow" | "deep"; }): string { - const depth = args.depth ?? "deep"; return ` The user ran /init for the current project. @@ -113,7 +101,7 @@ Runtime context: - parent_agent_id: ${args.agentId} - working_directory: ${args.workingDirectory} - memory_dir: ${args.memoryDir} -- research_depth: ${depth} +- research_depth: shallow Git/project context: ${args.gitContext} @@ -121,7 +109,7 @@ ${args.gitContext} Task: Initialize or reorganize the parent agent's filesystem-backed memory for this project. -${depth === "shallow" ? SHALLOW_INSTRUCTIONS : DEEP_INSTRUCTIONS} +${SHALLOW_INSTRUCTIONS} Instructions: - Use the pre-loaded initializing-memory skill as your operating guide @@ -148,12 +136,11 @@ export async function fireAutoInit( if (!settingsManager.isMemfsEnabled(agentId)) return false; const gitContext = gatherGitContext(); - const initPrompt = buildMemoryInitRuntimePrompt({ + const initPrompt = buildShallowInitPrompt({ agentId, workingDirectory: process.cwd(), memoryDir: getMemoryFilesystemRoot(agentId), gitContext, - depth: "shallow", }); const { spawnBackgroundSubagentTask } = await import("../../tools/impl/Task"); @@ -168,14 +155,20 @@ export async function fireAutoInit( return true; } -/** Message for the primary agent via processConversation (legacy non-MemFS path). */ -export function buildLegacyInitMessage(args: { +// ── Interactive init (primary agent) ───────────────────── + +/** Message for the primary agent via processConversation when user runs /init. */ +export function buildInitMessage(args: { gitContext: string; - memfsSection: string; + memoryDir?: string; }): string { + const memfsSection = args.memoryDir + ? `\n## Memory filesystem\n\nMemory filesystem is enabled. Memory directory: \`${args.memoryDir}\`\n` + : ""; + return `${SYSTEM_REMINDER_OPEN} The user has requested memory initialization via /init. -${args.memfsSection} +${memfsSection} ## 1. Invoke the initializing-memory skill Use the \`Skill\` tool with \`skill: "initializing-memory"\` to load the comprehensive instructions for memory initialization. diff --git a/src/cli/helpers/memorySubagentCompletion.ts b/src/cli/helpers/memorySubagentCompletion.ts index 0aa42ef..740e0de 100644 --- a/src/cli/helpers/memorySubagentCompletion.ts +++ b/src/cli/helpers/memorySubagentCompletion.ts @@ -4,71 +4,41 @@ import { } from "../../agent/modify"; export type MemorySubagentType = "init" | "reflection"; -export type MemoryInitDepth = "shallow" | "deep"; - -export interface MemoryInitProgressUpdate { - shallowCompleted: boolean; - deepFired: boolean; -} type RecompileAgentSystemPromptFn = ( conversationId: string, options?: RecompileAgentSystemPromptOptions, ) => Promise; -export type MemorySubagentCompletionArgs = - | { - agentId: string; - conversationId: string; - subagentType: "init"; - initDepth: MemoryInitDepth; - success: boolean; - error?: string; - } - | { - agentId: string; - conversationId: string; - subagentType: "reflection"; - initDepth?: never; - success: boolean; - error?: string; - }; +export interface MemorySubagentCompletionArgs { + agentId: string; + conversationId: string; + subagentType: MemorySubagentType; + success: boolean; + error?: string; +} export interface MemorySubagentCompletionDeps { recompileByConversation: Map>; recompileQueuedByConversation: Set; - updateInitProgress: ( - agentId: string, - update: Partial, - ) => void; logRecompileFailure?: (message: string) => void; recompileAgentSystemPromptImpl?: RecompileAgentSystemPromptFn; } /** - * Finalize a memory-writing subagent by updating init progress, recompiling the - * parent agent's system prompt, and returning the user-facing completion text. + * Finalize a memory-writing subagent by recompiling the parent agent's + * system prompt and returning the user-facing completion text. */ export async function handleMemorySubagentCompletion( args: MemorySubagentCompletionArgs, deps: MemorySubagentCompletionDeps, ): Promise { - const { agentId, conversationId, subagentType, initDepth, success, error } = - args; + const { agentId, conversationId, subagentType, success, error } = args; const recompileAgentSystemPromptFn = deps.recompileAgentSystemPromptImpl ?? recompileAgentSystemPrompt; let recompileError: string | null = null; if (success) { - if (subagentType === "init") { - deps.updateInitProgress( - agentId, - initDepth === "shallow" - ? { shallowCompleted: true } - : { deepFired: true }, - ); - } - try { let inFlight = deps.recompileByConversation.get(conversationId); @@ -106,9 +76,7 @@ export async function handleMemorySubagentCompletion( if (subagentType === "reflection") { return `Tried to reflect, but got lost in the palace: ${normalizedError}`; } - return initDepth === "deep" - ? `Deep memory initialization failed: ${normalizedError}` - : `Memory initialization failed: ${normalizedError}`; + return `Memory initialization failed: ${normalizedError}`; } const baseMessage = diff --git a/src/reminders/catalog.ts b/src/reminders/catalog.ts index 7905240..7032788 100644 --- a/src/reminders/catalog.ts +++ b/src/reminders/catalog.ts @@ -12,7 +12,6 @@ export type SharedReminderId = | "plan-mode" | "reflection-step-count" | "reflection-compaction" - | "deep-init" | "command-io" | "toolset-change" | "auto-init"; @@ -71,12 +70,6 @@ export const SHARED_REMINDER_CATALOG: ReadonlyArray = "Compaction-triggered reflection reminder/auto-launch behavior", modes: ["interactive", "headless-one-shot", "headless-bidirectional"], }, - { - id: "deep-init", - description: - "Auto-launch deep memory init after shallow init + turn gate", - modes: ["interactive"], - }, { id: "command-io", description: "Recent slash command input/output context", diff --git a/src/reminders/engine.ts b/src/reminders/engine.ts index 8dd3dfa..c8612f7 100644 --- a/src/reminders/engine.ts +++ b/src/reminders/engine.ts @@ -39,7 +39,6 @@ export interface SharedReminderContext { maybeLaunchReflectionSubagent?: ( triggerSource: ReflectionTriggerSource, ) => Promise; - maybeLaunchDeepInitSubagent?: () => Promise; } export type ReminderTextPart = { type: "text"; text: string }; @@ -213,29 +212,6 @@ async function buildAutoInitReminder( return AUTO_INIT_REMINDER; } -// Disabled: deep init at turn 8 + reflection at turn 10 is too chaotic. -// Re-enable once both subagent prompts are tuned to coexist. -const DEEP_INIT_AUTO_LAUNCH_ENABLED = false; - -async function maybeLaunchDeepInit( - context: SharedReminderContext, -): Promise { - if (!DEEP_INIT_AUTO_LAUNCH_ENABLED) return null; - if (!context.state.shallowInitCompleted) return null; - if (context.state.deepInitFired) return null; - if (context.state.turnCount < 8) return null; - - const memfsEnabled = settingsManager.isMemfsEnabled(context.agent.id); - if (!memfsEnabled) return null; - - if (context.maybeLaunchDeepInitSubagent) { - // Don't latch deepInitFired here — it's set in the onComplete callback - // only on success, so a failed deep init allows automatic retry. - await context.maybeLaunchDeepInitSubagent(); - } - return null; -} - const MAX_COMMAND_REMINDERS_PER_TURN = 10; const MAX_TOOLSET_REMINDERS_PER_TURN = 5; const MAX_COMMAND_INPUT_CHARS = 2000; @@ -349,7 +325,6 @@ export const sharedReminderProviders: Record< "plan-mode": buildPlanModeReminder, "reflection-step-count": buildReflectionStepReminder, "reflection-compaction": buildReflectionCompactionReminder, - "deep-init": maybeLaunchDeepInit, "command-io": buildCommandIoReminder, "toolset-change": buildToolsetChangeReminder, "auto-init": buildAutoInitReminder, diff --git a/src/reminders/state.ts b/src/reminders/state.ts index 42792f4..d7d58e9 100644 --- a/src/reminders/state.ts +++ b/src/reminders/state.ts @@ -28,8 +28,6 @@ export interface SharedReminderState { pendingAutoInitReminder: boolean; pendingCommandIoReminders: CommandIoReminder[]; pendingToolsetChangeReminders: ToolsetChangeReminder[]; - shallowInitCompleted: boolean; - deepInitFired: boolean; } export function createSharedReminderState(): SharedReminderState { @@ -42,8 +40,6 @@ export function createSharedReminderState(): SharedReminderState { pendingAutoInitReminder: false, pendingCommandIoReminders: [], pendingToolsetChangeReminders: [], - shallowInitCompleted: false, - deepInitFired: false, }; } diff --git a/src/tests/cli/auto-init.test.ts b/src/tests/cli/auto-init.test.ts index 6c48401..259d8f9 100644 --- a/src/tests/cli/auto-init.test.ts +++ b/src/tests/cli/auto-init.test.ts @@ -95,23 +95,22 @@ describe("auto-init lifecycle guards", () => { expect(setDelete).toBeGreaterThan(firedCheck); }); - test("manual /init clears pending auto-init for current agent after spawn", () => { + test("manual /init clears pending auto-init for current agent", () => { const appSource = readSource("../../cli/App.tsx"); - // The /init handler must delete the current agent from the pending set, - // but only after the background subagent has been spawned (inside the try). + // The /init handler must delete the current agent from the pending set + // before the interactive processConversation call. const initHandlerIdx = appSource.indexOf('trimmed === "/init"'); expect(initHandlerIdx).toBeGreaterThan(-1); - // Search from the /init handler to the end of the block const afterInit = appSource.slice(initHandlerIdx); - const spawnIdx = afterInit.indexOf("spawnBackgroundSubagentTask({"); const deleteIdx = afterInit.indexOf( "autoInitPendingAgentIdsRef.current.delete(agentId)", ); - expect(spawnIdx).toBeGreaterThan(-1); + const processIdx = afterInit.indexOf("processConversation("); expect(deleteIdx).toBeGreaterThan(-1); - expect(deleteIdx).toBeGreaterThan(spawnIdx); + expect(processIdx).toBeGreaterThan(-1); + expect(deleteIdx).toBeLessThan(processIdx); }); test("fireAutoInit returns false (not throw) when init subagent is active", () => { diff --git a/src/tests/cli/init-background-subagent.test.ts b/src/tests/cli/init-background-subagent.test.ts index 2525639..5ba6b0c 100644 --- a/src/tests/cli/init-background-subagent.test.ts +++ b/src/tests/cli/init-background-subagent.test.ts @@ -1,46 +1,38 @@ import { describe, expect, test } from "bun:test"; import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; -import { buildMemoryInitRuntimePrompt } from "../../cli/helpers/initCommand"; +import { + buildInitMessage, + buildShallowInitPrompt, +} from "../../cli/helpers/initCommand"; -describe("init background subagent wiring", () => { +describe("init wiring", () => { const readSource = (relativePath: string) => readFileSync( fileURLToPath(new URL(relativePath, import.meta.url)), "utf-8", ); - test("App.tsx checks pending approvals before either branch", () => { + test("App.tsx checks pending approvals before /init runs", () => { const appSource = readSource("../../cli/App.tsx"); - // The approval check must appear before the MemFS branch const approvalIdx = appSource.indexOf( "checkPendingApprovalsForSlashCommand", appSource.indexOf('trimmed === "/init"'), ); - const memfsBranchIdx = appSource.indexOf( - "isMemfsEnabled", + const initMessageIdx = appSource.indexOf( + "buildInitMessage", appSource.indexOf('trimmed === "/init"'), ); expect(approvalIdx).toBeGreaterThan(-1); - expect(memfsBranchIdx).toBeGreaterThan(-1); - expect(approvalIdx).toBeLessThan(memfsBranchIdx); + expect(initMessageIdx).toBeGreaterThan(-1); + expect(approvalIdx).toBeLessThan(initMessageIdx); }); - test("App.tsx branches on MemFS: background subagent vs legacy processConversation", () => { + test("App.tsx uses processConversation for /init", () => { const appSource = readSource("../../cli/App.tsx"); - // MemFS path — background subagent - expect(appSource).toContain("hasActiveInitSubagent()"); - expect(appSource).toContain("buildMemoryInitRuntimePrompt({"); - expect(appSource).toContain("spawnBackgroundSubagentTask({"); - expect(appSource).toContain('subagentType: "init"'); - expect(appSource).toContain("silentCompletion: true"); - expect(appSource).toContain("appendTaskNotificationEvents("); - expect(appSource).toContain("Learning about you and your codebase"); - - // Legacy non-MemFS path — primary agent - expect(appSource).toContain("buildLegacyInitMessage({"); + expect(appSource).toContain("buildInitMessage({"); expect(appSource).toContain("processConversation("); }); @@ -49,10 +41,8 @@ describe("init background subagent wiring", () => { expect(helperSource).toContain("export function hasActiveInitSubagent("); expect(helperSource).toContain("export function gatherGitContext()"); - expect(helperSource).toContain( - "export function buildMemoryInitRuntimePrompt(", - ); - expect(helperSource).toContain("export function buildLegacyInitMessage("); + expect(helperSource).toContain("export function buildShallowInitPrompt("); + expect(helperSource).toContain("export function buildInitMessage("); }); test("init.md exists as a builtin subagent", () => { @@ -79,36 +69,28 @@ describe("init background subagent wiring", () => { gitContext: "## Git context\nsome git info", }; - test('buildMemoryInitRuntimePrompt includes "research_depth: shallow" when depth is "shallow"', () => { - const prompt = buildMemoryInitRuntimePrompt({ - ...baseArgs, - depth: "shallow", - }); + test("buildShallowInitPrompt produces shallow-only prompt", () => { + const prompt = buildShallowInitPrompt(baseArgs); expect(prompt).toContain("research_depth: shallow"); expect(prompt).toContain("Shallow init"); expect(prompt).not.toContain("Deep init"); }); - test('buildMemoryInitRuntimePrompt includes "research_depth: deep" when depth is "deep"', () => { - const prompt = buildMemoryInitRuntimePrompt({ - ...baseArgs, - depth: "deep", + test("buildInitMessage includes memoryDir when provided", () => { + const msg = buildInitMessage({ + gitContext: "## Git\nsome info", + memoryDir: "/tmp/.memory", }); - expect(prompt).toContain("research_depth: deep"); - expect(prompt).toContain("Deep init"); - expect(prompt).not.toContain("Shallow init"); + expect(msg).toContain("Memory filesystem is enabled"); + expect(msg).toContain("/tmp/.memory"); + expect(msg).toContain("initializing-memory"); }); - test('buildMemoryInitRuntimePrompt defaults to "deep" when depth is omitted', () => { - const prompt = buildMemoryInitRuntimePrompt(baseArgs); - expect(prompt).toContain("research_depth: deep"); - expect(prompt).toContain("Deep init"); - }); - - test("App.tsx contains maybeLaunchDeepInitSubagent", () => { - const appSource = readSource("../../cli/App.tsx"); - expect(appSource).toContain("maybeLaunchDeepInitSubagent"); - expect(appSource).toContain("Deep memory initialization"); - expect(appSource).toContain('depth: "deep"'); + test("buildInitMessage works without memoryDir", () => { + const msg = buildInitMessage({ + gitContext: "## Git\nsome info", + }); + expect(msg).not.toContain("Memory filesystem"); + expect(msg).toContain("initializing-memory"); }); }); diff --git a/src/tests/cli/memory-subagent-recompile-wiring.test.ts b/src/tests/cli/memory-subagent-recompile-wiring.test.ts index 09c3fc8..02f7698 100644 --- a/src/tests/cli/memory-subagent-recompile-wiring.test.ts +++ b/src/tests/cli/memory-subagent-recompile-wiring.test.ts @@ -24,42 +24,24 @@ describe("memory subagent recompile handling", () => { ); }); - test("updates init progress and recompiles after successful shallow init", async () => { - const progressUpdates: Array<{ - agentId: string; - update: Record; - }> = []; - + test("recompiles system prompt after successful init", async () => { const message = await handleMemorySubagentCompletion( { agentId: "agent-init-1", conversationId: "conv-init-1", subagentType: "init", - initDepth: "shallow", success: true, }, { recompileByConversation: new Map(), recompileQueuedByConversation: new Set(), recompileAgentSystemPromptImpl: recompileAgentSystemPromptMock, - updateInitProgress: (agentId, update) => { - progressUpdates.push({ - agentId, - update: update as Record, - }); - }, }, ); expect(message).toBe( "Built a memory palace of you. Visit it with /palace.", ); - expect(progressUpdates).toEqual([ - { - agentId: "agent-init-1", - update: { shallowCompleted: true }, - }, - ]); expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith( "conv-init-1", {}, @@ -79,7 +61,6 @@ describe("memory subagent recompile handling", () => { recompileByConversation, recompileQueuedByConversation, recompileAgentSystemPromptImpl: recompileAgentSystemPromptMock, - updateInitProgress: () => {}, }; const first = handleMemorySubagentCompletion( @@ -145,7 +126,6 @@ describe("memory subagent recompile handling", () => { recompileByConversation: new Map>(), recompileQueuedByConversation: new Set(), recompileAgentSystemPromptImpl: recompileAgentSystemPromptMock, - updateInitProgress: () => {}, }; const [firstMessage, secondMessage] = await Promise.all([ diff --git a/src/tests/cli/memoryReminder.test.ts b/src/tests/cli/memoryReminder.test.ts index aed57f1..5003856 100644 --- a/src/tests/cli/memoryReminder.test.ts +++ b/src/tests/cli/memoryReminder.test.ts @@ -10,11 +10,6 @@ import { reflectionSettingsToLegacyMode, shouldFireStepCountTrigger, } from "../../cli/helpers/memoryReminder"; -import { - type SharedReminderContext, - sharedReminderProviders, -} from "../../reminders/engine"; -import { createSharedReminderState } from "../../reminders/state"; import { settingsManager } from "../../settings-manager"; const originalGetLocalProjectSettings = settingsManager.getLocalProjectSettings; @@ -175,121 +170,3 @@ describe("memoryReminder", () => { ).toBe(false); }); }); - -describe("deep-init trigger", () => { - const deepInitProvider = sharedReminderProviders["deep-init"]; - - function makeContext( - overrides: Partial<{ - shallowInitCompleted: boolean; - deepInitFired: boolean; - turnCount: number; - memfsEnabled: boolean; - callback: (() => Promise) | undefined; - }> = {}, - ): SharedReminderContext { - const state = createSharedReminderState(); - state.shallowInitCompleted = overrides.shallowInitCompleted ?? false; - state.deepInitFired = overrides.deepInitFired ?? false; - state.turnCount = overrides.turnCount ?? 0; - - const memfsEnabled = overrides.memfsEnabled ?? true; - (settingsManager as typeof settingsManager).isMemfsEnabled = (() => - memfsEnabled) as typeof settingsManager.isMemfsEnabled; - - return { - mode: "interactive", - agent: { id: "test-agent", name: "test" }, - state, - sessionContextReminderEnabled: false, - reflectionSettings: { - trigger: "step-count", - behavior: "auto-launch", - stepCount: 25, - }, - skillSources: [], - resolvePlanModeReminder: async () => "", - maybeLaunchDeepInitSubagent: overrides.callback, - }; - } - - test("does not fire before turn 8", async () => { - let launched = false; - const ctx = makeContext({ - shallowInitCompleted: true, - turnCount: 7, - callback: async () => { - launched = true; - return true; - }, - }); - const result = await deepInitProvider(ctx); - expect(result).toBeNull(); - expect(launched).toBe(false); - }); - - // Deep init auto-launch is currently disabled (reflection + deep init - // at similar turn counts is too chaotic). This test documents the - // disabled behavior; re-enable when subagent prompts are tuned. - test("is currently disabled — does not launch even when conditions are met", async () => { - let launched = false; - const ctx = makeContext({ - shallowInitCompleted: true, - turnCount: 8, - callback: async () => { - launched = true; - return true; - }, - }); - const result = await deepInitProvider(ctx); - expect(result).toBeNull(); - expect(launched).toBe(false); - }); - - test("does not re-fire once deepInitFired is true", async () => { - let launched = false; - const ctx = makeContext({ - shallowInitCompleted: true, - deepInitFired: true, - turnCount: 10, - callback: async () => { - launched = true; - return true; - }, - }); - const result = await deepInitProvider(ctx); - expect(result).toBeNull(); - expect(launched).toBe(false); - }); - - test("does not fire when shallowInitCompleted is false", async () => { - let launched = false; - const ctx = makeContext({ - shallowInitCompleted: false, - turnCount: 10, - callback: async () => { - launched = true; - return true; - }, - }); - const result = await deepInitProvider(ctx); - expect(result).toBeNull(); - expect(launched).toBe(false); - }); - - test("does not fire when memfs is disabled", async () => { - let launched = false; - const ctx = makeContext({ - shallowInitCompleted: true, - turnCount: 8, - memfsEnabled: false, - callback: async () => { - launched = true; - return true; - }, - }); - const result = await deepInitProvider(ctx); - expect(result).toBeNull(); - expect(launched).toBe(false); - }); -});