feat: Recompile system prompt after memory subagents finish (#1310)

This commit is contained in:
Devansh Jain
2026-03-09 16:50:40 -07:00
committed by GitHub
parent f5d6f095a6
commit 89d6ed2c87
9 changed files with 547 additions and 52 deletions

View File

@@ -232,6 +232,7 @@ import {
type ReflectionSettings,
reflectionSettingsToLegacyMode,
} from "./helpers/memoryReminder";
import { handleMemorySubagentCompletion } from "./helpers/memorySubagentCompletion";
import {
type QueuedMessage,
setMessageQueueAdder,
@@ -1746,6 +1747,10 @@ export default function App({
const initProgressByAgentRef = useRef(
new Map<string, { shallowCompleted: boolean; deepFired: boolean }>(),
);
const systemPromptRecompileByAgentRef = useRef(
new Map<string, Promise<void>>(),
);
const queuedSystemPromptRecompileByAgentRef = useRef(new Set<string>());
const updateInitProgress = (
forAgentId: string,
update: Partial<{ shallowCompleted: boolean; deepFired: boolean }>,
@@ -9305,13 +9310,24 @@ export default function App({
prompt: initPrompt,
description: "Initializing memory",
silentCompletion: true,
onComplete: ({ success, error }) => {
if (success) {
updateInitProgress(agentId, { deepFired: true });
}
const msg = success
? "Built a memory palace of you. Visit it with /palace."
: `Memory initialization failed: ${error || "Unknown error"}`;
onComplete: async ({ success, error }) => {
const msg = await handleMemorySubagentCompletion(
{
agentId,
subagentType: "init",
initDepth: "deep",
success,
error,
},
{
recompileByAgent: systemPromptRecompileByAgentRef.current,
recompileQueuedByAgent:
queuedSystemPromptRecompileByAgentRef.current,
updateInitProgress,
logRecompileFailure: (message) =>
debugWarn("memory", message),
},
);
appendTaskNotificationEvents([msg]);
},
});
@@ -9479,15 +9495,29 @@ export default function App({
// attempt (e.g. another /init subagent in flight) preserves the entry for retry.
if (autoInitPendingAgentIdsRef.current.has(agentId) && !isSystemOnly) {
try {
const fired = await fireAutoInit(agentId, ({ success, error }) => {
if (success) {
updateInitProgress(agentId, { shallowCompleted: true });
}
const msg = success
? "Built a memory palace of you. Visit it with /palace."
: `Memory initialization failed: ${error || "Unknown error"}`;
appendTaskNotificationEvents([msg]);
});
const fired = await fireAutoInit(
agentId,
async ({ success, error }) => {
const msg = await handleMemorySubagentCompletion(
{
agentId,
subagentType: "init",
initDepth: "shallow",
success,
error,
},
{
recompileByAgent: systemPromptRecompileByAgentRef.current,
recompileQueuedByAgent:
queuedSystemPromptRecompileByAgentRef.current,
updateInitProgress,
logRecompileFailure: (message) =>
debugWarn("memory", message),
},
);
appendTaskNotificationEvents([msg]);
},
);
if (fired) {
autoInitPendingAgentIdsRef.current.delete(agentId);
sharedReminderStateRef.current.pendingAutoInitReminder = true;
@@ -9596,10 +9626,23 @@ ${SYSTEM_REMINDER_CLOSE}
prompt: AUTO_REFLECTION_PROMPT,
description: AUTO_REFLECTION_DESCRIPTION,
silentCompletion: true,
onComplete: ({ success, error }) => {
const msg = success
? "Reflected on /palace, the halls remember more now."
: `Tried to reflect, but got lost in the palace: ${error}`;
onComplete: async ({ success, error }) => {
const msg = await handleMemorySubagentCompletion(
{
agentId,
subagentType: "reflection",
success,
error,
},
{
recompileByAgent: systemPromptRecompileByAgentRef.current,
recompileQueuedByAgent:
queuedSystemPromptRecompileByAgentRef.current,
updateInitProgress,
logRecompileFailure: (message) =>
debugWarn("memory", message),
},
);
appendTaskNotificationEvents([msg]);
},
});
@@ -9638,13 +9681,24 @@ ${SYSTEM_REMINDER_CLOSE}
prompt: initPrompt,
description: "Deep memory initialization",
silentCompletion: true,
onComplete: ({ success, error }) => {
if (success) {
updateInitProgress(agentId, { deepFired: true });
}
const msg = success
? "Built a memory palace of you. Visit it with /palace."
: `Deep memory initialization failed: ${error || "Unknown error"}`;
onComplete: async ({ success, error }) => {
const msg = await handleMemorySubagentCompletion(
{
agentId,
subagentType: "init",
initDepth: "deep",
success,
error,
},
{
recompileByAgent: systemPromptRecompileByAgentRef.current,
recompileQueuedByAgent:
queuedSystemPromptRecompileByAgentRef.current,
updateInitProgress,
logRecompileFailure: (message) =>
debugWarn("memory", message),
},
);
appendTaskNotificationEvents([msg]);
},
});

View File

@@ -139,7 +139,10 @@ Instructions:
*/
export async function fireAutoInit(
agentId: string,
onComplete: (result: { success: boolean; error?: string }) => void,
onComplete: (result: {
success: boolean;
error?: string;
}) => void | Promise<void>,
): Promise<boolean> {
if (hasActiveInitSubagent()) return false;
if (!settingsManager.isMemfsEnabled(agentId)) return false;

View File

@@ -0,0 +1,123 @@
import {
type RecompileAgentSystemPromptOptions,
recompileAgentSystemPrompt,
} from "../../agent/modify";
export type MemorySubagentType = "init" | "reflection";
export type MemoryInitDepth = "shallow" | "deep";
export interface MemoryInitProgressUpdate {
shallowCompleted: boolean;
deepFired: boolean;
}
type RecompileAgentSystemPromptFn = (
agentId: string,
options?: RecompileAgentSystemPromptOptions,
) => Promise<string>;
export type MemorySubagentCompletionArgs =
| {
agentId: string;
subagentType: "init";
initDepth: MemoryInitDepth;
success: boolean;
error?: string;
}
| {
agentId: string;
subagentType: "reflection";
initDepth?: never;
success: boolean;
error?: string;
};
export interface MemorySubagentCompletionDeps {
recompileByAgent: Map<string, Promise<void>>;
recompileQueuedByAgent: Set<string>;
updateInitProgress: (
agentId: string,
update: Partial<MemoryInitProgressUpdate>,
) => 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.
*/
export async function handleMemorySubagentCompletion(
args: MemorySubagentCompletionArgs,
deps: MemorySubagentCompletionDeps,
): Promise<string> {
const { agentId, subagentType, initDepth, 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.recompileByAgent.get(agentId);
if (!inFlight) {
inFlight = (async () => {
do {
deps.recompileQueuedByAgent.delete(agentId);
await recompileAgentSystemPromptFn(agentId, {
updateTimestamp: true,
});
} while (deps.recompileQueuedByAgent.has(agentId));
})().finally(() => {
// Cleanup runs only after the shared promise settles, so every
// concurrent caller awaits the same full recompile lifecycle.
deps.recompileQueuedByAgent.delete(agentId);
deps.recompileByAgent.delete(agentId);
});
deps.recompileByAgent.set(agentId, inFlight);
} else {
deps.recompileQueuedByAgent.add(agentId);
}
await inFlight;
} catch (recompileFailure) {
recompileError =
recompileFailure instanceof Error
? recompileFailure.message
: String(recompileFailure);
deps.logRecompileFailure?.(
`Failed to recompile system prompt after ${subagentType} subagent for ${agentId}: ${recompileError}`,
);
}
}
if (!success) {
const normalizedError = error || "Unknown error";
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}`;
}
const baseMessage =
subagentType === "reflection"
? "Reflected on /palace, the halls remember more now."
: "Built a memory palace of you. Visit it with /palace.";
if (!recompileError) {
return baseMessage;
}
return `${baseMessage} System prompt recompilation failed: ${recompileError}`;
}