Skip to content

Commit e22ec02

Browse files
authored
fix(agent): continue cloud tasks after compaction
Treat manual /compact commands as an intermediate cloud turn and send a hidden continuation prompt before reporting completion. Add a regression test covering compact commands with continuation instructions. Generated-By: PostHog Code Task-Id: 233a983e-daa3-4d81-af56-bb43488687ab
1 parent e59bf31 commit e22ec02

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

packages/agent/src/server/agent-server.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,52 @@ describe("AgentServer HTTP Mode", () => {
14331433
expect(body.error).toBe("No active session for this run");
14341434
}, 20000);
14351435

1436+
it("continues a cloud task after a manual compact command", async () => {
1437+
const s = createServer();
1438+
await s.start();
1439+
const prompt = vi.fn(async (_params: { prompt: ContentBlock[] }) => ({
1440+
stopReason: "end_turn",
1441+
}));
1442+
const serverInternals = s as unknown as {
1443+
session: { clientConnection: { prompt: typeof prompt } };
1444+
};
1445+
serverInternals.session.clientConnection.prompt = prompt;
1446+
1447+
const token = createToken();
1448+
const response = await fetch(`http://localhost:${port}/command`, {
1449+
method: "POST",
1450+
headers: {
1451+
Authorization: `Bearer ${token}`,
1452+
"Content-Type": "application/json",
1453+
},
1454+
body: JSON.stringify({
1455+
jsonrpc: "2.0",
1456+
id: "compact-and-continue",
1457+
method: "user_message",
1458+
params: {
1459+
content:
1460+
"/compact Continue with the task using the question tool and plan.",
1461+
},
1462+
}),
1463+
});
1464+
1465+
expect(response.status).toBe(200);
1466+
expect(prompt).toHaveBeenCalledTimes(2);
1467+
expect(prompt.mock.calls[0]?.[0].prompt).toEqual([
1468+
{
1469+
type: "text",
1470+
text: "/compact Continue with the task using the question tool and plan.",
1471+
},
1472+
]);
1473+
expect(prompt.mock.calls[1]?.[0].prompt).toEqual([
1474+
{
1475+
type: "text",
1476+
text: expect.stringContaining("Continue working on the task"),
1477+
_meta: { ui: { hidden: true } },
1478+
},
1479+
]);
1480+
}, 20000);
1481+
14361482
it("rewrites a bundled local skill slash command before sending the prompt", async () => {
14371483
const skillDefinition = [
14381484
"---",

packages/agent/src/server/agent-server.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ function hiddenTextBlock(text: string): ContentBlock {
289289
} as ContentBlock;
290290
}
291291

292+
function isManualCompactPrompt(prompt: ContentBlock[]): boolean {
293+
return /^\/compact(?:\s|$)/.test(promptBlocksToText(prompt).trimStart());
294+
}
295+
292296
interface LocalSkillPromptContext {
293297
/** Set when the message is a bare `/skill` invocation the adapter should strip. */
294298
skillName?: string;
@@ -960,6 +964,21 @@ export class AgentServer {
960964
? { _meta: promptMeta }
961965
: {}),
962966
});
967+
968+
if (
969+
result.stopReason === "end_turn" &&
970+
isManualCompactPrompt(prompt)
971+
) {
972+
this.recordTurnUsage(result.usage);
973+
result = await this.promptWithUpstreamRetry({
974+
sessionId: this.session.acpSessionId,
975+
prompt: [
976+
hiddenTextBlock(
977+
"Compaction is complete. Continue working on the task from the compacted context, following the user's instructions from the /compact command.",
978+
),
979+
],
980+
});
981+
}
963982
} catch (error) {
964983
if (messageId) {
965984
this.deliveredMessageIds.delete(messageId);

0 commit comments

Comments
 (0)