fix: Disable all shared reminders for subagents (#1073)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
@@ -1343,7 +1343,7 @@ ${SYSTEM_REMINDER_CLOSE}
|
|||||||
const lastRunAt = (agent as { last_run_completion?: string })
|
const lastRunAt = (agent as { last_run_completion?: string })
|
||||||
.last_run_completion;
|
.last_run_completion;
|
||||||
const { parts: sharedReminderParts } = await buildSharedReminderParts({
|
const { parts: sharedReminderParts } = await buildSharedReminderParts({
|
||||||
mode: "headless-one-shot",
|
mode: isSubagent ? "subagent" : "headless-one-shot",
|
||||||
agent: {
|
agent: {
|
||||||
id: agent.id,
|
id: agent.id,
|
||||||
name: agent.name,
|
name: agent.name,
|
||||||
@@ -2256,6 +2256,7 @@ async function runBidirectionalMode(
|
|||||||
let currentAbortController: AbortController | null = null;
|
let currentAbortController: AbortController | null = null;
|
||||||
const reminderContextTracker = createContextTracker();
|
const reminderContextTracker = createContextTracker();
|
||||||
const sharedReminderState = createSharedReminderState();
|
const sharedReminderState = createSharedReminderState();
|
||||||
|
const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
|
||||||
|
|
||||||
// Resolve pending approvals for this conversation before retrying user input.
|
// Resolve pending approvals for this conversation before retrying user input.
|
||||||
const resolveAllPendingApprovals = async () => {
|
const resolveAllPendingApprovals = async () => {
|
||||||
@@ -2793,7 +2794,7 @@ async function runBidirectionalMode(
|
|||||||
const lastRunAt = (agent as { last_run_completion?: string })
|
const lastRunAt = (agent as { last_run_completion?: string })
|
||||||
.last_run_completion;
|
.last_run_completion;
|
||||||
const { parts: sharedReminderParts } = await buildSharedReminderParts({
|
const { parts: sharedReminderParts } = await buildSharedReminderParts({
|
||||||
mode: "headless-bidirectional",
|
mode: isSubagent ? "subagent" : "headless-bidirectional",
|
||||||
agent: {
|
agent: {
|
||||||
id: agent.id,
|
id: agent.id,
|
||||||
name: agent.name,
|
name: agent.name,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
export type SharedReminderMode =
|
export type SharedReminderMode =
|
||||||
| "interactive"
|
| "interactive"
|
||||||
| "headless-one-shot"
|
| "headless-one-shot"
|
||||||
| "headless-bidirectional";
|
| "headless-bidirectional"
|
||||||
|
| "subagent";
|
||||||
|
|
||||||
export type SharedReminderId =
|
export type SharedReminderId =
|
||||||
| "session-context"
|
| "session-context"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe("headless shared reminder wiring", () => {
|
|||||||
);
|
);
|
||||||
const source = readFileSync(headlessPath, "utf-8");
|
const source = readFileSync(headlessPath, "utf-8");
|
||||||
|
|
||||||
expect(source).toContain('mode: "headless-one-shot"');
|
expect(source).toContain('isSubagent ? "subagent" : "headless-one-shot"');
|
||||||
expect(source).toContain(
|
expect(source).toContain(
|
||||||
"sessionContextReminderEnabled: systemInfoReminderEnabled",
|
"sessionContextReminderEnabled: systemInfoReminderEnabled",
|
||||||
);
|
);
|
||||||
@@ -21,7 +21,9 @@ describe("headless shared reminder wiring", () => {
|
|||||||
);
|
);
|
||||||
const source = readFileSync(headlessPath, "utf-8");
|
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("resolvePlanModeReminder: async () => {");
|
||||||
expect(source).toContain("const { PLAN_MODE_REMINDER } = await import");
|
expect(source).toContain("const { PLAN_MODE_REMINDER } = await import");
|
||||||
});
|
});
|
||||||
@@ -36,6 +38,21 @@ describe("headless shared reminder wiring", () => {
|
|||||||
expect(source).toContain("reminderContextTracker");
|
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", () => {
|
test("one-shot approval drain uses shared stream processor", () => {
|
||||||
const headlessPath = fileURLToPath(
|
const headlessPath = fileURLToPath(
|
||||||
new URL("../../headless.ts", import.meta.url),
|
new URL("../../headless.ts", import.meta.url),
|
||||||
|
|||||||
@@ -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", () => {
|
test("command and toolset reminders are interactive-only", () => {
|
||||||
const commandReminder = SHARED_REMINDER_CATALOG.find(
|
const commandReminder = SHARED_REMINDER_CATALOG.find(
|
||||||
(entry) => entry.id === "command-io",
|
(entry) => entry.id === "command-io",
|
||||||
|
|||||||
@@ -88,4 +88,34 @@ describe("shared reminder parity", () => {
|
|||||||
reminderIdsForMode("headless-bidirectional"),
|
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([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user