diff --git a/src/headless.ts b/src/headless.ts index 688891c..a60e1ca 100644 --- a/src/headless.ts +++ b/src/headless.ts @@ -1343,7 +1343,7 @@ ${SYSTEM_REMINDER_CLOSE} const lastRunAt = (agent as { last_run_completion?: string }) .last_run_completion; const { parts: sharedReminderParts } = await buildSharedReminderParts({ - mode: "headless-one-shot", + mode: isSubagent ? "subagent" : "headless-one-shot", agent: { id: agent.id, name: agent.name, @@ -2256,6 +2256,7 @@ async function runBidirectionalMode( let currentAbortController: AbortController | null = null; const reminderContextTracker = createContextTracker(); const sharedReminderState = createSharedReminderState(); + const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent"; // Resolve pending approvals for this conversation before retrying user input. const resolveAllPendingApprovals = async () => { @@ -2793,7 +2794,7 @@ async function runBidirectionalMode( const lastRunAt = (agent as { last_run_completion?: string }) .last_run_completion; const { parts: sharedReminderParts } = await buildSharedReminderParts({ - mode: "headless-bidirectional", + mode: isSubagent ? "subagent" : "headless-bidirectional", agent: { id: agent.id, name: agent.name, diff --git a/src/reminders/catalog.ts b/src/reminders/catalog.ts index 80c2674..b228f32 100644 --- a/src/reminders/catalog.ts +++ b/src/reminders/catalog.ts @@ -1,7 +1,8 @@ export type SharedReminderMode = | "interactive" | "headless-one-shot" - | "headless-bidirectional"; + | "headless-bidirectional" + | "subagent"; export type SharedReminderId = | "session-context" diff --git a/src/tests/headless/reminder-wiring.test.ts b/src/tests/headless/reminder-wiring.test.ts index 370d34f..5b26c54 100644 --- a/src/tests/headless/reminder-wiring.test.ts +++ b/src/tests/headless/reminder-wiring.test.ts @@ -9,7 +9,7 @@ describe("headless shared reminder wiring", () => { ); const source = readFileSync(headlessPath, "utf-8"); - expect(source).toContain('mode: "headless-one-shot"'); + expect(source).toContain('isSubagent ? "subagent" : "headless-one-shot"'); expect(source).toContain( "sessionContextReminderEnabled: systemInfoReminderEnabled", ); @@ -21,7 +21,9 @@ describe("headless shared reminder wiring", () => { ); const source = readFileSync(headlessPath, "utf-8"); - expect(source).toContain('mode: "headless-bidirectional"'); + expect(source).toContain( + 'isSubagent ? "subagent" : "headless-bidirectional"', + ); expect(source).toContain("resolvePlanModeReminder: async () => {"); expect(source).toContain("const { PLAN_MODE_REMINDER } = await import"); }); @@ -36,6 +38,21 @@ describe("headless shared reminder wiring", () => { expect(source).toContain("reminderContextTracker"); }); + test("subagent mode is wired via LETTA_CODE_AGENT_ROLE check", () => { + const headlessPath = fileURLToPath( + new URL("../../headless.ts", import.meta.url), + ); + const source = readFileSync(headlessPath, "utf-8"); + + expect(source).toContain( + 'process.env.LETTA_CODE_AGENT_ROLE === "subagent"', + ); + expect(source).toContain('isSubagent ? "subagent" : "headless-one-shot"'); + expect(source).toContain( + 'isSubagent ? "subagent" : "headless-bidirectional"', + ); + }); + test("one-shot approval drain uses shared stream processor", () => { const headlessPath = fileURLToPath( new URL("../../headless.ts", import.meta.url), diff --git a/src/tests/reminders/catalog.test.ts b/src/tests/reminders/catalog.test.ts index 458ef6e..04ccbee 100644 --- a/src/tests/reminders/catalog.test.ts +++ b/src/tests/reminders/catalog.test.ts @@ -30,6 +30,13 @@ describe("shared reminder catalog", () => { } }); + test("subagent mode has no reminders", () => { + const subagentReminders = SHARED_REMINDER_CATALOG.filter((entry) => + entry.modes.includes("subagent"), + ); + expect(subagentReminders).toEqual([]); + }); + test("command and toolset reminders are interactive-only", () => { const commandReminder = SHARED_REMINDER_CATALOG.find( (entry) => entry.id === "command-io", diff --git a/src/tests/reminders/engine-parity.test.ts b/src/tests/reminders/engine-parity.test.ts index 0c66f04..9531e00 100644 --- a/src/tests/reminders/engine-parity.test.ts +++ b/src/tests/reminders/engine-parity.test.ts @@ -88,4 +88,34 @@ describe("shared reminder parity", () => { reminderIdsForMode("headless-bidirectional"), ); }); + + test("subagent mode produces no reminders", async () => { + for (const reminderId of SHARED_REMINDER_IDS) { + providerMap[reminderId] = async () => reminderId; + } + + const reflectionSettings: ReflectionSettings = { + trigger: "off", + behavior: "reminder", + stepCount: 25, + }; + + const subagent = await buildSharedReminderParts({ + agent: { + id: "agent-1", + name: "Agent 1", + description: "test", + lastRunAt: null, + }, + sessionContextReminderEnabled: true, + reflectionSettings, + skillSources: [] as SkillSource[], + resolvePlanModeReminder: () => "plan", + mode: "subagent", + state: createSharedReminderState(), + }); + + expect(subagent.appliedReminderIds).toEqual([]); + expect(subagent.parts).toEqual([]); + }); });