diff --git a/src/agent/modify.ts b/src/agent/modify.ts index bedebf5..9ada82e 100644 --- a/src/agent/modify.ts +++ b/src/agent/modify.ts @@ -270,59 +270,46 @@ export async function updateConversationLLMConfig( return client.conversations.update(conversationId, payload); } -export interface RecompileAgentSystemPromptOptions { - dryRun?: boolean; - /** - * Required when recompiling the special "default" conversation route. - * Passed as body param `agent_id` for agent-direct mode. - */ - agentId?: string; -} - -interface ConversationSystemPromptRecompileClient { - conversations: { - recompile: ( - conversationId: string, - params: { - dry_run?: boolean; - }, - ) => Promise; - }; -} - /** * Recompile an agent's system prompt after memory writes so server-side prompt * state picks up the latest memory content. * * @param conversationId - The conversation whose prompt should be recompiled - * @param options - Optional dry-run control + * @param agentId - Agent id for the parent conversation + * @param dryRun - Optional dry-run control * @param clientOverride - Optional injected client for tests * @returns The compiled system prompt returned by the API */ export async function recompileAgentSystemPrompt( conversationId: string, - options: RecompileAgentSystemPromptOptions = {}, - clientOverride?: ConversationSystemPromptRecompileClient, + agentId: string, + dryRun?: boolean, + clientOverride?: { + conversations: { + recompile: ( + conversationId: string, + params: { + dry_run?: boolean; + agent_id?: string; + }, + ) => Promise; + }; + }, ): Promise { - const client = (clientOverride ?? - (await getClient())) as ConversationSystemPromptRecompileClient; + const client = (clientOverride ?? (await getClient())) as Exclude< + typeof clientOverride, + undefined + >; - const params: { - dry_run?: boolean; - agent_id?: string; - } = { - dry_run: options.dryRun, - }; - - if (conversationId === "default") { - if (!options.agentId) { - throw new Error( - 'recompileAgentSystemPrompt requires options.agentId when conversationId is "default"', - ); - } - params.agent_id = options.agentId; + if (!agentId) { + throw new Error("recompileAgentSystemPrompt requires agentId"); } + const params = { + dry_run: dryRun, + agent_id: agentId, + }; + return client.conversations.recompile(conversationId, params); } diff --git a/src/cli/helpers/memorySubagentCompletion.ts b/src/cli/helpers/memorySubagentCompletion.ts index 4bf9fa7..14910fb 100644 --- a/src/cli/helpers/memorySubagentCompletion.ts +++ b/src/cli/helpers/memorySubagentCompletion.ts @@ -1,13 +1,11 @@ -import { - type RecompileAgentSystemPromptOptions, - recompileAgentSystemPrompt, -} from "../../agent/modify"; +import { recompileAgentSystemPrompt } from "../../agent/modify"; export type MemorySubagentType = "init" | "reflection"; type RecompileAgentSystemPromptFn = ( conversationId: string, - options?: RecompileAgentSystemPromptOptions, + agentId: string, + dryRun?: boolean, ) => Promise; export interface MemorySubagentCompletionArgs { @@ -46,9 +44,7 @@ export async function handleMemorySubagentCompletion( inFlight = (async () => { do { deps.recompileQueuedByConversation.delete(conversationId); - await recompileAgentSystemPromptFn(conversationId, { - ...(conversationId === "default" ? { agentId } : {}), - }); + await recompileAgentSystemPromptFn(conversationId, agentId); } while (deps.recompileQueuedByConversation.has(conversationId)); })().finally(() => { // Cleanup runs only after the shared promise settles, so every diff --git a/src/tests/agent/recompile-system-prompt.test.ts b/src/tests/agent/recompile-system-prompt.test.ts index 7c1b576..213343d 100644 --- a/src/tests/agent/recompile-system-prompt.test.ts +++ b/src/tests/agent/recompile-system-prompt.test.ts @@ -3,71 +3,87 @@ import { recompileAgentSystemPrompt } from "../../agent/modify"; describe("recompileAgentSystemPrompt", () => { test("calls the conversation recompile endpoint with mapped params", async () => { - const agentsRecompileMock = mock( + const conversationsRecompileMock = mock( (_conversationId: string, _params?: Record) => Promise.resolve("compiled-system-prompt"), ); const client = { conversations: { - recompile: agentsRecompileMock, + recompile: conversationsRecompileMock, }, }; const compiledPrompt = await recompileAgentSystemPrompt( "conv-123", - { - dryRun: true, - }, + "agent-123", + true, client, ); expect(compiledPrompt).toBe("compiled-system-prompt"); - expect(agentsRecompileMock).toHaveBeenCalledWith("conv-123", { + expect(conversationsRecompileMock).toHaveBeenCalledWith("conv-123", { dry_run: true, + agent_id: "agent-123", }); }); test("passes agent_id for default conversation recompiles", async () => { - const agentsRecompileMock = mock( + const conversationsRecompileMock = mock( (_conversationId: string, _params?: Record) => Promise.resolve("compiled-system-prompt"), ); const client = { conversations: { - recompile: agentsRecompileMock, + recompile: conversationsRecompileMock, }, }; - await recompileAgentSystemPrompt( - "default", - { - agentId: "agent-123", - }, - client, - ); + await recompileAgentSystemPrompt("default", "agent-123", undefined, client); - expect(agentsRecompileMock).toHaveBeenCalledWith("default", { + expect(conversationsRecompileMock).toHaveBeenCalledWith("default", { dry_run: undefined, agent_id: "agent-123", }); }); - test("throws when default conversation recompile lacks agent id", async () => { - const agentsRecompileMock = mock( + test("passes non-default conversation ids through unchanged", async () => { + const conversationsRecompileMock = mock( (_conversationId: string, _params?: Record) => Promise.resolve("compiled-system-prompt"), ); const client = { conversations: { - recompile: agentsRecompileMock, + recompile: conversationsRecompileMock, + }, + }; + + await recompileAgentSystemPrompt( + "['default']", + "agent-123", + undefined, + client, + ); + + expect(conversationsRecompileMock).toHaveBeenCalledWith("['default']", { + dry_run: undefined, + agent_id: "agent-123", + }); + }); + + test("throws when conversation recompile has empty agent id", async () => { + const conversationsRecompileMock = mock( + (_conversationId: string, _params?: Record) => + Promise.resolve("compiled-system-prompt"), + ); + const client = { + conversations: { + recompile: conversationsRecompileMock, }, }; await expect( - recompileAgentSystemPrompt("default", {}, client), - ).rejects.toThrow( - 'recompileAgentSystemPrompt requires options.agentId when conversationId is "default"', - ); - expect(agentsRecompileMock).not.toHaveBeenCalled(); + recompileAgentSystemPrompt("default", "", undefined, client), + ).rejects.toThrow("recompileAgentSystemPrompt requires agentId"); + expect(conversationsRecompileMock).not.toHaveBeenCalled(); }); }); diff --git a/src/tests/cli/memory-subagent-recompile-wiring.test.ts b/src/tests/cli/memory-subagent-recompile-wiring.test.ts index 7899f80..6f36457 100644 --- a/src/tests/cli/memory-subagent-recompile-wiring.test.ts +++ b/src/tests/cli/memory-subagent-recompile-wiring.test.ts @@ -1,9 +1,8 @@ import { beforeEach, describe, expect, mock, test } from "bun:test"; -import type { RecompileAgentSystemPromptOptions } from "../../agent/modify"; import { handleMemorySubagentCompletion } from "../../cli/helpers/memorySubagentCompletion"; const recompileAgentSystemPromptMock = mock( - (_conversationId: string, _opts?: RecompileAgentSystemPromptOptions) => + (_conversationId: string, _agentId: string, _dryRun?: boolean) => Promise.resolve("compiled-system-prompt"), ); @@ -19,7 +18,7 @@ describe("memory subagent recompile handling", () => { beforeEach(() => { recompileAgentSystemPromptMock.mockReset(); recompileAgentSystemPromptMock.mockImplementation( - (_agentId: string, _opts?: RecompileAgentSystemPromptOptions) => + (_conversationId: string, _agentId: string, _dryRun?: boolean) => Promise.resolve("compiled-system-prompt"), ); }); @@ -44,7 +43,7 @@ describe("memory subagent recompile handling", () => { ); expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith( "conv-init-1", - {}, + "agent-init-1", ); }); @@ -63,9 +62,10 @@ describe("memory subagent recompile handling", () => { }, ); - expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith("default", { - agentId: "agent-default", - }); + expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith( + "default", + "agent-default", + ); }); test("queues a trailing recompile when later completions land mid-flight", async () => { @@ -176,7 +176,13 @@ describe("memory subagent recompile handling", () => { "Reflected on /palace, the halls remember more now.", ); expect(recompileAgentSystemPromptMock).toHaveBeenCalledTimes(2); - expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith("conv-a", {}); - expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith("conv-b", {}); + expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith( + "conv-a", + "agent-shared", + ); + expect(recompileAgentSystemPromptMock).toHaveBeenCalledWith( + "conv-b", + "agent-shared", + ); }); });