From eb722aa977c6d4fd593e7bfa952438dfc66b57e3 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 28 Apr 2026 17:59:50 +0900 Subject: [PATCH] perf(compaction): reuse message update parts for no-text tails Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- ...eemptive-compaction-degradation-monitor.ts | 2 ++ .../preemptive-compaction-no-text-tail.ts | 7 +++++- ...ive-compaction.degradation-monitor.test.ts | 24 +++++++++++++++++++ src/hooks/preemptive-compaction.ts | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/hooks/preemptive-compaction-degradation-monitor.ts b/src/hooks/preemptive-compaction-degradation-monitor.ts index 6c93a0e4e..29605ac96 100644 --- a/src/hooks/preemptive-compaction-degradation-monitor.ts +++ b/src/hooks/preemptive-compaction-degradation-monitor.ts @@ -43,6 +43,7 @@ interface ClientLike { export interface AssistantCompactionMessageInfo { sessionID: string id?: string + parts?: unknown } async function withTimeout( @@ -185,6 +186,7 @@ export function createPostCompactionDegradationMonitor(args: { sessionID: info.sessionID, messageID: info.id, directory, + parts: info.parts, }) if (!isNoTextTail) { diff --git a/src/hooks/preemptive-compaction-no-text-tail.ts b/src/hooks/preemptive-compaction-no-text-tail.ts index 712ed1ff3..b3ca2dd66 100644 --- a/src/hooks/preemptive-compaction-no-text-tail.ts +++ b/src/hooks/preemptive-compaction-no-text-tail.ts @@ -46,8 +46,13 @@ export async function resolveNoTextTailFromSession(args: { sessionID: string messageID?: string directory: string + parts?: unknown }): Promise { - const { client, sessionID, messageID, directory } = args + const { client, sessionID, messageID, directory, parts } = args + + if (Array.isArray(parts)) { + return isStepOnlyNoTextParts(parts) + } try { const response = await client.session.messages({ diff --git a/src/hooks/preemptive-compaction.degradation-monitor.test.ts b/src/hooks/preemptive-compaction.degradation-monitor.test.ts index ae7f73a57..4399c81f7 100644 --- a/src/hooks/preemptive-compaction.degradation-monitor.test.ts +++ b/src/hooks/preemptive-compaction.degradation-monitor.test.ts @@ -192,4 +192,28 @@ describe("preemptive-compaction post-compaction degradation monitor", () => { // then expect(ctx.client.session.summarize).not.toHaveBeenCalled() }) + + it("uses message update parts without refetching session messages", async () => { + // given + const sessionHistory: AssistantHistoryMessage[] = [] + const ctx = createMockCtx(sessionHistory) + const hook = createPreemptiveCompactionHook(ctx as never, {} as never) + const sessionID = "ses_tail_update_parts" + const stepOnlyParts = [{ type: "step-start" }, { type: "step-finish" }] + + await hook.event({ + event: { + type: "session.compacted", + properties: { sessionID }, + }, + }) + + // when + await hook.event(buildAssistantUpdate({ sessionID, id: "msg_1", parts: stepOnlyParts })) + await hook.event(buildAssistantUpdate({ sessionID, id: "msg_2", parts: stepOnlyParts })) + + // then + expect(ctx.client.session.messages).not.toHaveBeenCalled() + expect(ctx.client.session.summarize).not.toHaveBeenCalled() + }) }) diff --git a/src/hooks/preemptive-compaction.ts b/src/hooks/preemptive-compaction.ts index 7b4828dcb..a8da4b91e 100644 --- a/src/hooks/preemptive-compaction.ts +++ b/src/hooks/preemptive-compaction.ts @@ -76,6 +76,7 @@ export function createPreemptiveCompactionHook( modelID?: string finish?: boolean tokens?: TokenInfo + parts?: unknown } | undefined if (!info || info.role !== "assistant" || !info.finish || !info.sessionID) return @@ -92,6 +93,7 @@ export function createPreemptiveCompactionHook( await postCompactionMonitor.onAssistantMessageUpdated({ sessionID: info.sessionID, id: info.id, + parts: info.parts, }) } }