From 787dfa5279f5bc0516849e351662ba3ab23f5438 Mon Sep 17 00:00:00 2001 From: hoverlover Date: Mon, 26 Jan 2026 20:31:36 -0600 Subject: [PATCH 1/2] feat(plugins): wire up compaction hooks with summary data - Extend PluginHookAfterCompactionEvent with summary, sessionId, sessionKey - Call runBeforeCompaction before session.compact() - Call runAfterCompaction after (fire-and-forget pattern) - Enables memory plugins like Supermemory to store compacted summaries Co-Authored-By: Claude --- src/agents/pi-embedded-runner/compact.ts | 38 ++++++++++++++++++++++++ src/plugins/types.ts | 6 ++++ 2 files changed, 44 insertions(+) diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index 2daafd086..206e32728 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -69,6 +69,7 @@ import type { EmbeddedPiCompactResult } from "./types.js"; import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js"; import { describeUnknownError, mapThinkingLevel, resolveExecToolDefaults } from "./utils.js"; import { buildTtsSystemPromptHint } from "../../tts/tts.js"; +import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js"; export type CompactEmbeddedPiSessionParams = { sessionId: string; @@ -424,6 +425,22 @@ export async function compactEmbeddedPiSessionDirect( if (limited.length > 0) { session.agent.replaceMessages(limited); } + + // Run before_compaction hooks + const hookRunner = getGlobalHookRunner(); + const messageCountBefore = session.messages.length; + if (hookRunner?.hasHooks("before_compaction")) { + await hookRunner.runBeforeCompaction( + { messageCount: messageCountBefore, tokenCount: undefined }, + { + agentId: sessionAgentId, + sessionKey: params.sessionKey, + workspaceDir: effectiveWorkspace, + messageProvider: runtimeChannel, + }, + ); + } + const result = await session.compact(params.customInstructions); // Estimate tokens after compaction by summing token estimates for remaining messages let tokensAfter: number | undefined; @@ -440,6 +457,27 @@ export async function compactEmbeddedPiSessionDirect( // If estimation fails, leave tokensAfter undefined tokensAfter = undefined; } + + // Run after_compaction hooks (fire-and-forget) + if (hookRunner?.hasHooks("after_compaction")) { + void hookRunner.runAfterCompaction( + { + messageCount: session.messages.length, + tokenCount: tokensAfter, + compactedCount: messageCountBefore - session.messages.length, + summary: result.summary, + sessionId: params.sessionId, + sessionKey: params.sessionKey, + }, + { + agentId: sessionAgentId, + sessionKey: params.sessionKey, + workspaceDir: effectiveWorkspace, + messageProvider: runtimeChannel, + }, + ); + } + return { ok: true, compacted: true, diff --git a/src/plugins/types.ts b/src/plugins/types.ts index 1ce9731ea..64c2b3b92 100644 --- a/src/plugins/types.ts +++ b/src/plugins/types.ts @@ -339,6 +339,12 @@ export type PluginHookAfterCompactionEvent = { messageCount: number; tokenCount?: number; compactedCount: number; + /** Compacted summary text - essential for memory plugins */ + summary: string; + /** Session identifier */ + sessionId?: string; + /** Session key for context */ + sessionKey?: string; }; // Message context From 55ae82738a5521de325ffb5263e2bc9ff06004bf Mon Sep 17 00:00:00 2001 From: hoverlover Date: Mon, 26 Jan 2026 22:39:07 -0600 Subject: [PATCH 2/2] Export stripEnvelope from plugin SDK Expose the chat sanitization utility for plugins to use when stripping channel envelope metadata from user prompts. Co-Authored-By: Claude --- src/plugin-sdk/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugin-sdk/index.ts b/src/plugin-sdk/index.ts index c0c201ff0..282e963ec 100644 --- a/src/plugin-sdk/index.ts +++ b/src/plugin-sdk/index.ts @@ -369,3 +369,6 @@ export type { ProcessedLineMessage } from "../line/markdown-to-line.js"; // Media utilities export { loadWebMedia, type WebMediaResult } from "../web/media.js"; + +// Chat sanitization utilities +export { stripEnvelope } from "../gateway/chat-sanitize.js";