@archships/dim-plugin-auto-compact
Advanced tools
+63
-18
@@ -7,3 +7,3 @@ //#region src/index.ts | ||
| const DEFAULT_RECENT_TOOL_OUTPUTS_TO_PRESERVE = 2; | ||
| const DEFAULT_TOOL_OUTPUT_CHAR_LIMIT = 1200; | ||
| const DEFAULT_TOOL_OUTPUT_PREVIEW_CHAR_LIMIT = 1200; | ||
| const DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN = 1024; | ||
@@ -124,3 +124,2 @@ const MAX_SUMMARY_RECURSION_PASSES = 2; | ||
| compactedMessages: request.plan.compactedMessages, | ||
| summaryInputMode: request.summaryInputMode, | ||
| pruneToolOutputs: input.options.compaction.prune, | ||
@@ -194,3 +193,3 @@ sessionId: input.context.sessionId, | ||
| async function generateSummary(input) { | ||
| const renderedInput = buildSummaryInput(input.existingSystemSegments, input.compactedMessages, input.summaryInputMode, input.pruneToolOutputs, input.contextStatus); | ||
| const renderedInput = buildSummaryInput(input.existingSystemSegments, input.compactedMessages, input.pruneToolOutputs, input.contextStatus); | ||
| const summaryInputTokens = estimateSectionsTokens([...renderedInput.prefixSections, ...renderedInput.messageSections]); | ||
@@ -231,4 +230,4 @@ const summaryInputBudget = Math.max(256, input.summaryInputMaxTokens - DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN); | ||
| } | ||
| function buildSummaryInput(existingSystemSegments, compactedMessages, summaryInputMode, pruneToolOutputs, status) { | ||
| const summaryMessages = summaryInputMode === "exclude_tool_messages" ? compactedMessages.filter((message) => message.role !== "tool") : compactedMessages; | ||
| function buildSummaryInput(existingSystemSegments, compactedMessages, pruneToolOutputs, status) { | ||
| const summaryMessages = compactedMessages; | ||
| if (summaryMessages.length === 0) return { | ||
@@ -371,2 +370,7 @@ prefixSections: [ | ||
| const text = renderMessageText(message).trim() || "(empty)"; | ||
| if (message.role === "assistant") return { | ||
| text: `[assistant] ${[text, renderAssistantToolCalls(message)].filter((entry) => entry.trim().length > 0).join("\n\n") || "(empty)"}`, | ||
| prunedToolOutput: false, | ||
| preservedToolOutput: false | ||
| }; | ||
| if (message.role !== "tool") return { | ||
@@ -378,23 +382,52 @@ text: `[${message.role}] ${text}`, | ||
| const header = `[tool:${message.toolName} call=${message.toolCallId} status=${message.isError ? "error" : "ok"}]`; | ||
| if (!pruneToolOutputs || preservedToolOutputIds.has(message.id)) return { | ||
| text: [header, truncateText(text, DEFAULT_TOOL_OUTPUT_CHAR_LIMIT)].join("\n"), | ||
| prunedToolOutput: false, | ||
| preservedToolOutput: pruneToolOutputs | ||
| }; | ||
| const renderedBody = renderToolMessageBody(message, pruneToolOutputs, preservedToolOutputIds); | ||
| return { | ||
| text: `${header}\noutput omitted for compaction summary (originalChars=${text.length})`, | ||
| prunedToolOutput: true, | ||
| preservedToolOutput: false | ||
| text: [header, renderedBody.text].join("\n"), | ||
| prunedToolOutput: renderedBody.pruned, | ||
| preservedToolOutput: renderedBody.preserved | ||
| }; | ||
| } | ||
| function renderMessageText(message) { | ||
| const text = message.content.map((block) => { | ||
| const text = renderMessageContentText(message); | ||
| if (message.role === "tool" && text.length === 0 && message.structuredContent) return JSON.stringify(message.structuredContent); | ||
| return text; | ||
| } | ||
| function renderMessageContentText(message) { | ||
| return message.content.map((block) => { | ||
| if (block.type === "text") return block.text; | ||
| return `[file:${block.mediaType}]`; | ||
| }).join("\n").trim(); | ||
| if (message.role === "tool" && text.length === 0 && message.structuredContent) return JSON.stringify(message.structuredContent); | ||
| return text; | ||
| } | ||
| function renderAssistantToolCalls(message) { | ||
| if (!message.toolCalls || message.toolCalls.length === 0) return ""; | ||
| return ["toolCalls:", ...message.toolCalls.map((toolCall, index) => [ | ||
| `- index: ${index + 1}`, | ||
| ` id: ${toolCall.id}`, | ||
| ` name: ${toolCall.function.name}`, | ||
| ` arguments: ${stringifyJson(toolCall.function.arguments)}` | ||
| ].join("\n"))].join("\n"); | ||
| } | ||
| function renderToolMessageBody(message, pruneToolOutputs, preservedToolOutputIds) { | ||
| const contentText = renderMessageContentText(message).trim(); | ||
| const structuredContentText = message.structuredContent === void 0 ? "" : stringifyJson(message.structuredContent); | ||
| if (pruneToolOutputs && !preservedToolOutputIds.has(message.id)) return { | ||
| text: `output omitted for compaction summary (${[`contentChars=${contentText.length}`, `structuredContentChars=${structuredContentText.length}`].join(", ")})`, | ||
| pruned: true, | ||
| preserved: false | ||
| }; | ||
| const sections = []; | ||
| if (contentText.length > 0) sections.push(renderToolOutputSection("content", contentText, pruneToolOutputs)); | ||
| if (structuredContentText.length > 0) sections.push(renderToolOutputSection("structuredContent", structuredContentText, pruneToolOutputs)); | ||
| return { | ||
| text: sections.join("\n\n") || "(empty)", | ||
| pruned: false, | ||
| preserved: pruneToolOutputs | ||
| }; | ||
| } | ||
| function renderToolOutputSection(label, text, pruneToolOutputs) { | ||
| if (!pruneToolOutputs) return `${label}:\n${text}`; | ||
| return `${label}Preview:\n${truncateText(text, DEFAULT_TOOL_OUTPUT_PREVIEW_CHAR_LIMIT)}`; | ||
| } | ||
| function buildPreservedToolOutputIds(messages, pruneToolOutputs) { | ||
| if (!pruneToolOutputs) return new Set(messages.filter((message) => message.role === "tool").map((message) => message.id)); | ||
| if (!pruneToolOutputs) return /* @__PURE__ */ new Set(); | ||
| const preserved = /* @__PURE__ */ new Set(); | ||
@@ -406,2 +439,9 @@ const toolMessages = messages.filter((message) => message.role === "tool"); | ||
| } | ||
| function stringifyJson(value) { | ||
| try { | ||
| return JSON.stringify(value, null, 2); | ||
| } catch { | ||
| return String(value); | ||
| } | ||
| } | ||
| function createRenderedSummarySection(id, text) { | ||
@@ -447,3 +487,8 @@ return { | ||
| const preservedChars = Math.max(0, maxChars - suffix.length); | ||
| return `${text.slice(0, preservedChars).trimEnd()}${suffix}`; | ||
| if (preservedChars <= 256) return `${text.slice(0, preservedChars).trimEnd()}${suffix}`; | ||
| const omittedMarker = "\n[...]\n"; | ||
| const availableChars = Math.max(0, preservedChars - 7); | ||
| const headChars = Math.ceil(availableChars * .65); | ||
| const tailChars = Math.max(0, availableChars - headChars); | ||
| return [text.slice(0, headChars).trimEnd(), text.slice(Math.max(headChars, text.length - tailChars)).trimStart()].join(omittedMarker) + suffix; | ||
| } | ||
@@ -450,0 +495,0 @@ function joinSummarySections(prefixSections, messageSections) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n CompactionExecutionRequest,\n CompactionExecutionResult,\n CompactionSummaryInputMode,\n Message,\n ModelRef,\n ModelRequest,\n ModelRequestUsageScope,\n ModelStreamEvent,\n SessionCompactorController,\n SessionStatus,\n UsageRequestKind,\n} from '@archships/dim-agent-sdk'\nimport type {\n DimPlugin,\n LoggerGateway,\n PluginSessionControllerContext,\n PluginSessionStateEntry,\n} from '@archships/dim-plugin-api'\n\nexport interface AutoCompactPluginOptions {\n summaryModel?: ModelRef\n maxSummaryTokens?: number\n summaryInputMaxTokens?: number\n summaryPrompt?: string\n retainMessages?: number\n compaction?: {\n auto?: boolean\n prune?: boolean\n reserved?: number\n }\n}\n\ninterface ResolvedOptions {\n summaryModel?: ModelRef\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n retainMessages: number\n compaction: {\n auto: boolean\n prune: boolean\n reserved: number\n }\n}\n\ninterface AutoCompactPluginStateData {\n strategy: 'controller-v2'\n summaryModel?: ModelRef\n lastResult?: AutoCompactPersistedResult\n}\n\ninterface AutoCompactPersistedResult {\n trigger: 'manual' | 'threshold'\n status: 'compacted' | 'skipped' | 'failed'\n reasonCode?: string\n reasonMessage?: string\n compactedMessageCount: number\n retainedMessageCount: number\n summaryNormalization?: SummaryNormalizationMode\n summaryInputTokens?: number\n summaryOutputTokensEstimate?: number\n summaryChars?: number\n summaryCallCount?: number\n summaryChunkCount?: number\n prunedToolOutputCount?: number\n preservedToolOutputCount?: number\n updatedAt: number\n}\n\ninterface RenderedSummarySection {\n id: string\n text: string\n tokens: number\n}\n\ninterface RenderedSummaryInput {\n prefixSections: RenderedSummarySection[]\n messageSections: RenderedSummarySection[]\n prunedToolOutputCount: number\n preservedToolOutputCount: number\n}\n\ninterface NormalizedSummaryGenerationResult {\n summary: string\n summaryNormalization: SummaryNormalizationMode\n summaryInputTokens: number\n summaryOutputTokensEstimate: number\n summaryChars: number\n summaryCallCount: number\n summaryChunkCount: number\n prunedToolOutputCount: number\n preservedToolOutputCount: number\n}\n\ntype SummaryGenerationResult =\n | ({ status: 'normalized' } & NormalizedSummaryGenerationResult)\n | { status: 'empty_body_preserve_previous' }\n | { status: 'invalid_summary_contract' }\n\ntype SummaryNormalizationMode = 'plain_text' | 'wrapped_block' | 'extracted_block'\n\ntype CanonicalContinuationSummary =\n | {\n status: 'normalized'\n summary: string\n normalization: SummaryNormalizationMode\n }\n | {\n status: 'empty_body'\n }\n\ntype SuccessfulContinuationSummary = Extract<\n CanonicalContinuationSummary,\n { status: 'normalized' }\n>\n\ninterface RenderedMessage {\n text: string\n prunedToolOutput: boolean\n preservedToolOutput: boolean\n}\n\ninterface AutoCompactInspectorConfig {\n summaryModel?: { provider: string; modelId: string }\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n retainMessages: number\n compaction: {\n auto: boolean\n prune: boolean\n reserved: number\n }\n}\n\ninterface AutoCompactPluginStateRecord {\n strategy: 'controller-v2'\n summaryModel?: {\n provider: string\n modelId: string\n }\n lastResult?: AutoCompactPersistedResult\n}\n\ninterface AutoCompactPlanningController extends SessionCompactorController {\n readPlanningOptions(): {\n auto: boolean\n retainMessages: number\n reservedTokens: number\n summaryTokenReserve: number\n }\n}\n\ninterface AutoCompactPluginStateDataCandidate {\n strategy?: unknown\n summaryModel?: unknown\n lastResult?: unknown\n}\n\ninterface AutoCompactPersistedResultCandidate {\n trigger?: unknown\n status?: unknown\n compactedMessageCount?: unknown\n retainedMessageCount?: unknown\n updatedAt?: unknown\n reasonCode?: unknown\n reasonMessage?: unknown\n summaryNormalization?: unknown\n summaryInputTokens?: unknown\n summaryOutputTokensEstimate?: unknown\n summaryChars?: unknown\n summaryCallCount?: unknown\n summaryChunkCount?: unknown\n prunedToolOutputCount?: unknown\n preservedToolOutputCount?: unknown\n}\n\ninterface ModelRefCandidate {\n provider?: unknown\n modelId?: unknown\n}\n\ninterface ErrorCodeCandidate {\n code?: unknown\n}\n\nconst DEFAULT_MAX_SUMMARY_TOKENS = 1024\nconst DEFAULT_SUMMARY_INPUT_MAX_TOKENS = 16000\nconst DEFAULT_RETAIN_MESSAGES = 4\nconst DEFAULT_THRESHOLD_HEADROOM = 1024\nconst DEFAULT_RECENT_TOOL_OUTPUTS_TO_PRESERVE = 2\nconst DEFAULT_TOOL_OUTPUT_CHAR_LIMIT = 1200\nconst DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN = 1024\nconst MAX_SUMMARY_RECURSION_PASSES = 2\nconst CONTINUATION_SUMMARY_OPEN_TAG = '<continuation_summary>'\nconst CONTINUATION_SUMMARY_CLOSE_TAG = '</continuation_summary>'\nconst CONTINUATION_SUMMARY_BLOCK_PATTERN =\n /<continuation_summary>([\\s\\S]*?)<\\/continuation_summary>/g\nconst CONTINUATION_SUMMARY_TAG_FRAGMENT_PATTERN = /<\\/?continuation_summary>?/g\n\nconst DEFAULT_SUMMARY_PROMPT = `You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:\n\nTask Overview\nThe user's core request and success criteria\nAny clarifications or constraints they specified\n\nCurrent State\nWhat has been completed so far\nFiles created, modified, or analyzed (with paths if relevant)\nKey outputs or artifacts produced\n\nImportant Discoveries\nTechnical constraints or requirements uncovered\nDecisions made and their rationale\nErrors encountered and how they were resolved\nWhat approaches were tried that didn't work (and why)\n\nNext Steps\nSpecific actions needed to complete the task\nAny blockers or open questions to resolve\nPriority order if multiple steps remain\n\nContext to Preserve\nUser preferences or style requirements\nDomain-specific details that aren't obvious\nAny promises made to the user\n\nBe concise but complete—err on the side of including information that would prevent duplicate work or repeated mistakes.\nWrite in a way that enables immediate resumption of the task.\nReturn only the continuation summary body as plain text. Do not add XML tags, wrappers, or surrounding commentary.`\n\nexport function createAutoCompactPlugin(): DimPlugin<'auto-compact', SessionCompactorController>\nexport function createAutoCompactPlugin(\n options: AutoCompactPluginOptions,\n): DimPlugin<'auto-compact', SessionCompactorController>\nexport function createAutoCompactPlugin<TId extends string>(\n options: AutoCompactPluginOptions & { id: TId },\n): DimPlugin<TId, SessionCompactorController>\nexport function createAutoCompactPlugin<TId extends string>(\n options: AutoCompactPluginOptions & { id?: TId } = {},\n): DimPlugin<TId, SessionCompactorController> {\n const resolved = resolveOptions(options)\n\n return {\n manifest: {\n id: (options.id ?? 'auto-compact') as TId,\n version: '0.2.0',\n apiVersion: 1,\n permissions: { model: true },\n capabilities: ['auto-compact'],\n },\n setup(context) {\n return {\n inspector: {\n getConfig: async (): Promise<AutoCompactInspectorConfig> => {\n const config: AutoCompactInspectorConfig = {\n maxSummaryTokens: resolved.maxSummaryTokens,\n summaryInputMaxTokens: resolved.summaryInputMaxTokens,\n summaryPrompt: resolved.summaryPrompt,\n retainMessages: resolved.retainMessages,\n compaction: {\n auto: resolved.compaction.auto,\n prune: resolved.compaction.prune,\n reserved: resolved.compaction.reserved,\n },\n }\n if (resolved.summaryModel) {\n config.summaryModel = {\n provider: resolved.summaryModel.provider,\n modelId: resolved.summaryModel.modelId,\n }\n }\n return config\n },\n getSessionState: async (sessionId) =>\n structuredClone(\n readPluginState(await context.services.pluginState.get(sessionId)),\n ),\n },\n createSessionController: (controllerContext) =>\n createAutoCompactController({\n options: resolved,\n logger: context.services.logger,\n model: context.services.model,\n context: controllerContext,\n }),\n }\n },\n }\n}\n\nfunction createAutoCompactController(input: {\n options: ResolvedOptions\n logger: LoggerGateway\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n context: PluginSessionControllerContext\n}): AutoCompactPlanningController {\n return {\n readPlanningOptions() {\n return {\n auto: input.options.compaction.auto,\n retainMessages: input.options.retainMessages,\n reservedTokens: input.options.compaction.reserved,\n summaryTokenReserve: input.options.maxSummaryTokens,\n }\n },\n async compact(request: CompactionExecutionRequest): Promise<CompactionExecutionResult> {\n const sessionStatus = input.context.getStatus()\n const summaryModel = input.options.summaryModel ?? sessionStatus.model\n\n if (!summaryModel) {\n const result: CompactionExecutionResult = {\n status: 'skipped',\n reasonCode: 'missing_summary_model',\n reasonMessage: 'Auto compact summary model is unavailable',\n diagnostics: {},\n }\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n ...(input.options.summaryModel ? { summaryModel: input.options.summaryModel } : {}),\n lastResult: createPersistedResult(request, result),\n })\n return result\n }\n\n try {\n const summary = await generateSummary({\n contextStatus: sessionStatus,\n summaryModel,\n maxSummaryTokens: input.options.maxSummaryTokens,\n summaryInputMaxTokens: input.options.summaryInputMaxTokens,\n summaryPrompt: input.options.summaryPrompt,\n existingSystemSegments: request.plan.existingSystemSegments,\n compactedMessages: request.plan.compactedMessages,\n summaryInputMode: request.summaryInputMode,\n pruneToolOutputs: input.options.compaction.prune,\n sessionId: input.context.sessionId,\n usageKind:\n request.plan.trigger === 'manual' ? 'manual_compaction' : 'auto_compaction',\n model: input.model,\n logger: input.logger,\n })\n\n const result =\n summary.status === 'normalized'\n ? {\n status: 'compacted' as const,\n summary: summary.summary,\n diagnostics: {\n summaryNormalization: summary.summaryNormalization,\n summaryInputTokens: summary.summaryInputTokens,\n summaryOutputTokensEstimate: summary.summaryOutputTokensEstimate,\n summaryChars: summary.summaryChars,\n summaryCallCount: summary.summaryCallCount,\n summaryChunkCount: summary.summaryChunkCount,\n prunedToolOutputCount: summary.prunedToolOutputCount,\n preservedToolOutputCount: summary.preservedToolOutputCount,\n },\n }\n : summary.status === 'empty_body_preserve_previous'\n ? {\n status: 'skipped' as const,\n reasonCode: 'empty_summary_preserved_previous',\n reasonMessage:\n 'Summary generation produced an empty body and preserved the existing continuation summary',\n diagnostics: {},\n }\n : {\n status: 'failed' as const,\n reasonCode: 'invalid_summary_contract',\n reasonMessage: 'Auto compact summary body cannot be empty',\n diagnostics: {},\n }\n\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n summaryModel,\n lastResult: createPersistedResult(request, result),\n })\n return result\n } catch (error) {\n const result: CompactionExecutionResult = {\n status: 'failed',\n reasonCode: readErrorCode(error) ?? 'summary_generation_failed',\n reasonMessage: readErrorMessage(error),\n diagnostics: {},\n }\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n summaryModel,\n lastResult: createPersistedResult(request, result),\n })\n return result\n }\n },\n }\n}\n\nfunction resolveOptions(options: AutoCompactPluginOptions): ResolvedOptions {\n return {\n summaryModel: options.summaryModel,\n maxSummaryTokens: positiveIntegerOr(\n options.maxSummaryTokens,\n DEFAULT_MAX_SUMMARY_TOKENS,\n ),\n summaryInputMaxTokens: Math.max(\n DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN + 256,\n positiveIntegerOr(options.summaryInputMaxTokens, DEFAULT_SUMMARY_INPUT_MAX_TOKENS),\n ),\n summaryPrompt: options.summaryPrompt?.trim() || DEFAULT_SUMMARY_PROMPT,\n retainMessages: Math.max(1, positiveIntegerOr(options.retainMessages, DEFAULT_RETAIN_MESSAGES)),\n compaction: {\n auto: options.compaction?.auto ?? true,\n prune: options.compaction?.prune ?? true,\n reserved: Math.max(0, Math.floor(options.compaction?.reserved ?? DEFAULT_THRESHOLD_HEADROOM)),\n },\n }\n}\n\nasync function generateSummary(input: {\n contextStatus?: SessionStatus\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n existingSystemSegments: string[]\n compactedMessages: Message[]\n summaryInputMode: CompactionSummaryInputMode\n pruneToolOutputs: boolean\n sessionId: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n}): Promise<SummaryGenerationResult> {\n const renderedInput = buildSummaryInput(\n input.existingSystemSegments,\n input.compactedMessages,\n input.summaryInputMode,\n input.pruneToolOutputs,\n input.contextStatus,\n )\n const summaryInputTokens = estimateSectionsTokens([\n ...renderedInput.prefixSections,\n ...renderedInput.messageSections,\n ])\n const summaryInputBudget = Math.max(\n 256,\n input.summaryInputMaxTokens - DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN,\n )\n let summarized: Awaited<ReturnType<typeof summarizeRenderedSections>>\n\n try {\n summarized = await summarizeRenderedSections({\n stage: 'source',\n remainingLevels: MAX_SUMMARY_RECURSION_PASSES,\n prefixSections: renderedInput.prefixSections,\n messageSections: renderedInput.messageSections,\n summaryInputBudget,\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n usageKind: input.usageKind,\n model: input.model,\n logger: input.logger,\n })\n } catch (error) {\n if (readErrorCode(error) === 'empty_summary_body') {\n return input.existingSystemSegments.join('\\n\\n').trim()\n ? { status: 'empty_body_preserve_previous' }\n : { status: 'invalid_summary_contract' }\n }\n throw error\n }\n\n return {\n status: 'normalized',\n summary: summarized.summary,\n summaryNormalization: summarized.summaryNormalization,\n summaryInputTokens,\n summaryOutputTokensEstimate: estimateTextTokens(summarized.summary),\n summaryChars: summarized.summary.length,\n summaryCallCount: summarized.summaryCallCount,\n summaryChunkCount: summarized.summaryChunkCount,\n prunedToolOutputCount: renderedInput.prunedToolOutputCount,\n preservedToolOutputCount: renderedInput.preservedToolOutputCount,\n }\n}\n\nfunction buildSummaryInput(\n existingSystemSegments: string[],\n compactedMessages: Message[],\n summaryInputMode: CompactionSummaryInputMode,\n pruneToolOutputs: boolean,\n status?: SessionStatus,\n): RenderedSummaryInput {\n const summaryMessages =\n summaryInputMode === 'exclude_tool_messages'\n ? compactedMessages.filter((message) => message.role !== 'tool')\n : compactedMessages\n if (summaryMessages.length === 0) {\n return {\n prefixSections: [\n createRenderedSummarySection(\n 'status',\n [\n 'Current canonical session status:',\n status\n ? [\n `- sessionId: ${status.sessionId}`,\n `- model: ${status.model.provider}/${status.model.modelId}`,\n `- messageCount: ${status.messageCount}`,\n `- compactionCursor: ${status.compaction.cursor}`,\n ].join('\\n')\n : '- unavailable',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'existing-summary',\n [\n 'Existing compaction summary:',\n existingSystemSegments.length > 0 ? existingSystemSegments.join('\\n\\n') : '(none)',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'messages-heading',\n 'Messages to compact:\\n(no eligible messages after summary-input filtering)',\n ),\n ],\n messageSections: [],\n prunedToolOutputCount: 0,\n preservedToolOutputCount: 0,\n }\n }\n\n const preservedToolOutputIds = buildPreservedToolOutputIds(summaryMessages, pruneToolOutputs)\n let prunedToolOutputCount = 0\n let preservedToolOutputCount = 0\n\n const prefixSections = [\n createRenderedSummarySection(\n 'status',\n [\n 'Current canonical session status:',\n status\n ? [\n `- sessionId: ${status.sessionId}`,\n `- model: ${status.model.provider}/${status.model.modelId}`,\n `- messageCount: ${status.messageCount}`,\n `- compactionCursor: ${status.compaction.cursor}`,\n ].join('\\n')\n : '- unavailable',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'existing-summary',\n [\n 'Existing compaction summary:',\n existingSystemSegments.length > 0 ? existingSystemSegments.join('\\n\\n') : '(none)',\n ].join('\\n'),\n ),\n createRenderedSummarySection('messages-heading', 'Messages to compact:'),\n ]\n\n const messageSections = summaryMessages.map((message, index) => {\n const renderedMessage = renderMessage(message, pruneToolOutputs, preservedToolOutputIds)\n if (renderedMessage.prunedToolOutput) prunedToolOutputCount += 1\n if (renderedMessage.preservedToolOutput) preservedToolOutputCount += 1\n\n return createRenderedSummarySection(\n message.id,\n [`Message ${index + 1}`, renderedMessage.text].join('\\n'),\n )\n })\n\n return {\n prefixSections,\n messageSections,\n prunedToolOutputCount,\n preservedToolOutputCount,\n }\n}\n\nasync function summarizeRenderedSections(input: {\n stage: 'source' | 'merge'\n remainingLevels: number\n prefixSections: RenderedSummarySection[]\n messageSections: RenderedSummarySection[]\n summaryInputBudget: number\n sessionId: string\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryPrompt: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n}): Promise<{\n summary: string\n summaryNormalization: SummaryNormalizationMode\n summaryCallCount: number\n summaryChunkCount: number\n}> {\n const combinedText = joinSummarySections(input.prefixSections, input.messageSections)\n if (estimateTextTokens(combinedText) <= input.summaryInputBudget) {\n const canonical = await streamSummaryText({\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n summaryInputText: combinedText,\n summaryKind: input.stage === 'source' ? 'summary' : 'summary-merge',\n usageKind: input.usageKind,\n model: input.model,\n logger: input.logger,\n })\n return {\n summary: canonical.summary,\n summaryNormalization: canonical.normalization,\n summaryCallCount: 1,\n summaryChunkCount: 0,\n }\n }\n\n if (input.remainingLevels <= 1) {\n throw createCodedError(\n input.stage === 'merge' ? 'summary_merge_over_budget' : 'summary_source_too_large',\n input.stage === 'merge'\n ? 'Chunk summaries still exceed the summary model input budget'\n : 'Source history exceeds the summary model input budget',\n )\n }\n\n const chunks = createSummaryChunks(\n input.prefixSections,\n input.messageSections,\n input.summaryInputBudget,\n )\n if (chunks.length <= 1) {\n throw createCodedError(\n input.stage === 'merge' ? 'summary_merge_over_budget' : 'summary_source_too_large',\n input.stage === 'merge'\n ? 'Unable to merge chunk summaries within the summary model input budget'\n : 'Unable to fit source history into chunked summary requests',\n )\n }\n\n let summaryCallCount = 0\n let summaryNormalization: SummaryNormalizationMode = 'plain_text'\n const chunkSummarySections: RenderedSummarySection[] = []\n\n for (const [index, chunk] of chunks.entries()) {\n const canonical = await streamSummaryText({\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n summaryInputText: joinSummarySections(input.prefixSections, chunk),\n summaryKind: 'summary-chunk',\n usageKind: input.usageKind,\n model: input.model,\n chunkIndex: index,\n chunkCount: chunks.length,\n logger: input.logger,\n })\n summaryCallCount += 1\n summaryNormalization = mergeSummaryNormalizationModes(\n summaryNormalization,\n canonical.normalization,\n )\n\n chunkSummarySections.push(\n createRenderedSummarySection(\n `chunk-summary-${index + 1}`,\n `Chunk summary ${index + 1} of ${chunks.length}\\n${canonical.summary}`,\n ),\n )\n }\n\n const merged = await summarizeRenderedSections({\n ...input,\n stage: 'merge',\n remainingLevels: input.remainingLevels - 1,\n messageSections: chunkSummarySections,\n })\n\n return {\n summary: merged.summary,\n summaryNormalization: mergeSummaryNormalizationModes(\n summaryNormalization,\n merged.summaryNormalization,\n ),\n summaryCallCount: summaryCallCount + merged.summaryCallCount,\n summaryChunkCount: chunks.length + merged.summaryChunkCount,\n }\n}\n\nasync function streamSummaryText(input: {\n sessionId: string\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryPrompt: string\n summaryInputText: string\n summaryKind: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n chunkIndex?: number\n chunkCount?: number\n}): Promise<SuccessfulContinuationSummary> {\n const request: ModelRequest = {\n model: input.summaryModel,\n maxOutputTokens: input.maxSummaryTokens,\n metadata: {\n dimAutoCompact: true,\n dimAutoCompactKind: input.summaryKind,\n sessionId: input.sessionId,\n ...(typeof input.chunkIndex === 'number' ? { chunkIndex: input.chunkIndex } : {}),\n ...(typeof input.chunkCount === 'number' ? { chunkCount: input.chunkCount } : {}),\n },\n messages: [\n createSyntheticMessage('system', input.summaryPrompt),\n createSyntheticMessage('user', input.summaryInputText),\n ],\n }\n\n let text = ''\n for await (const event of input.model.stream(request, {\n usage: {\n sessionId: input.sessionId,\n kind: input.usageKind,\n },\n })) {\n if (event.type === 'text_delta') text += event.delta\n if (event.type === 'error')\n throw createCodedError(\n event.error.code ?? 'summary_generation_failed',\n event.error.message,\n )\n }\n\n if (!text.trim())\n throw createCodedError('empty_summary_body', 'Auto compact summary body cannot be empty')\n\n const canonical = canonicalizeContinuationSummary(text)\n if (canonical.status === 'empty_body') {\n throw createCodedError('empty_summary_body', 'Auto compact summary body cannot be empty')\n }\n if (canonical.normalization !== 'plain_text') {\n input.logger.emit({\n level: 'warn',\n source: 'auto-compact',\n message:\n 'Auto compact summary output deviated from the preferred plain-text contract; normalized automatically',\n metadata: {\n sessionId: input.sessionId,\n summaryKind: input.summaryKind,\n summaryNormalization: canonical.normalization,\n ...(typeof input.chunkIndex === 'number' ? { chunkIndex: input.chunkIndex } : {}),\n ...(typeof input.chunkCount === 'number' ? { chunkCount: input.chunkCount } : {}),\n },\n })\n }\n\n return canonical\n}\n\nfunction renderMessage(\n message: Message,\n pruneToolOutputs: boolean,\n preservedToolOutputIds: Set<string>,\n): RenderedMessage {\n const text = renderMessageText(message).trim() || '(empty)'\n\n if (message.role !== 'tool') {\n return {\n text: `[${message.role}] ${text}`,\n prunedToolOutput: false,\n preservedToolOutput: false,\n }\n }\n\n const header = `[tool:${message.toolName} call=${message.toolCallId} status=${\n message.isError ? 'error' : 'ok'\n }]`\n if (!pruneToolOutputs || preservedToolOutputIds.has(message.id)) {\n const truncated = truncateText(text, DEFAULT_TOOL_OUTPUT_CHAR_LIMIT)\n return {\n text: [header, truncated].join('\\n'),\n prunedToolOutput: false,\n preservedToolOutput: pruneToolOutputs,\n }\n }\n\n return {\n text: `${header}\\noutput omitted for compaction summary (originalChars=${text.length})`,\n prunedToolOutput: true,\n preservedToolOutput: false,\n }\n}\n\nfunction renderMessageText(message: Message): string {\n const blocks = message.content.map((block) => {\n if (block.type === 'text') return block.text\n return `[file:${block.mediaType}]`\n })\n const text = blocks.join('\\n').trim()\n\n if (message.role === 'tool' && text.length === 0 && message.structuredContent)\n return JSON.stringify(message.structuredContent)\n\n return text\n}\n\nfunction buildPreservedToolOutputIds(\n messages: Message[],\n pruneToolOutputs: boolean,\n): Set<string> {\n if (!pruneToolOutputs)\n return new Set(\n messages\n .filter((message) => message.role === 'tool')\n .map((message) => message.id),\n )\n\n const preserved = new Set<string>()\n const toolMessages = messages.filter(\n (message): message is Extract<Message, { role: 'tool' }> => message.role === 'tool',\n )\n\n for (const message of toolMessages.slice(-DEFAULT_RECENT_TOOL_OUTPUTS_TO_PRESERVE))\n preserved.add(message.id)\n for (const message of toolMessages) {\n if (message.isError) preserved.add(message.id)\n }\n\n return preserved\n}\n\nfunction createRenderedSummarySection(id: string, text: string): RenderedSummarySection {\n return {\n id,\n text,\n tokens: estimateTextTokens(text),\n }\n}\n\nfunction createSummaryChunks(\n prefixSections: RenderedSummarySection[],\n messageSections: RenderedSummarySection[],\n summaryInputBudget: number,\n): RenderedSummarySection[][] {\n if (messageSections.length === 0) return []\n\n const prefixTokens = estimateSectionsTokens(prefixSections)\n const messageBudget = summaryInputBudget - prefixTokens\n if (messageBudget <= 64) return []\n\n const chunks: RenderedSummarySection[][] = []\n let currentChunk: RenderedSummarySection[] = []\n let currentChunkTokens = 0\n\n for (const section of messageSections) {\n let nextSection = section\n if (nextSection.tokens > messageBudget) {\n nextSection = truncateSectionToBudget(nextSection, messageBudget)\n if (nextSection.tokens > messageBudget) return []\n }\n\n if (currentChunk.length > 0 && currentChunkTokens + nextSection.tokens > messageBudget) {\n chunks.push(currentChunk)\n currentChunk = []\n currentChunkTokens = 0\n }\n\n currentChunk.push(nextSection)\n currentChunkTokens += nextSection.tokens\n }\n\n if (currentChunk.length > 0) chunks.push(currentChunk)\n return chunks\n}\n\nfunction truncateSectionToBudget(\n section: RenderedSummarySection,\n budgetTokens: number,\n): RenderedSummarySection {\n const budgetChars = Math.max(128, budgetTokens * 4 - 64)\n if (section.text.length <= budgetChars) return section\n\n return createRenderedSummarySection(section.id, truncateText(section.text, budgetChars))\n}\n\nfunction truncateText(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text\n\n const suffix = `\\n[truncated from ${text.length} chars]`\n const preservedChars = Math.max(0, maxChars - suffix.length)\n return `${text.slice(0, preservedChars).trimEnd()}${suffix}`\n}\n\nfunction joinSummarySections(\n prefixSections: RenderedSummarySection[],\n messageSections: RenderedSummarySection[],\n): string {\n return [...prefixSections, ...messageSections].map((section) => section.text).join('\\n\\n')\n}\n\nfunction estimateSectionsTokens(sections: RenderedSummarySection[]): number {\n return sections.reduce((total, section) => total + section.tokens, 0)\n}\n\nfunction estimateTextTokens(text: string): number {\n return Math.max(1, Math.ceil(text.length / 4))\n}\n\nfunction createSyntheticMessage(role: 'system' | 'user', text: string): Message {\n return {\n id: `auto_compact_${role}_${Date.now()}`,\n role,\n content: [{ type: 'text', text }],\n createdAt: Date.now(),\n }\n}\n\nfunction canonicalizeContinuationSummary(summary: string): CanonicalContinuationSummary {\n const trimmed = summary.trim()\n if (!trimmed) return { status: 'empty_body' }\n\n const blockMatches = [...trimmed.matchAll(CONTINUATION_SUMMARY_BLOCK_PATTERN)]\n const blockBodies = blockMatches\n .map((match) => match?.[1]?.trim() ?? '')\n .filter((body) => body.length > 0)\n\n if (blockBodies.length > 0) {\n const [match] = blockMatches\n return {\n status: 'normalized',\n summary: renderCanonicalContinuationSummary(blockBodies.join('\\n\\n')),\n normalization:\n blockMatches.length === 1 && match?.index === 0 && match[0].length === trimmed.length\n ? 'wrapped_block'\n : 'extracted_block',\n }\n }\n\n const stripped = stripContinuationSummaryTagFragments(trimmed).trim()\n if (!stripped) return { status: 'empty_body' }\n\n return {\n status: 'normalized',\n summary: renderCanonicalContinuationSummary(stripped),\n normalization: stripped === trimmed ? 'plain_text' : 'extracted_block',\n }\n}\n\nfunction renderCanonicalContinuationSummary(body: string): string {\n return `${CONTINUATION_SUMMARY_OPEN_TAG}\\n${body}\\n${CONTINUATION_SUMMARY_CLOSE_TAG}`\n}\n\nfunction stripContinuationSummaryTagFragments(text: string): string {\n return text.replace(CONTINUATION_SUMMARY_TAG_FRAGMENT_PATTERN, '\\n')\n}\n\nfunction mergeSummaryNormalizationModes(\n left: SummaryNormalizationMode,\n right: SummaryNormalizationMode,\n): SummaryNormalizationMode {\n const rank: Record<SummaryNormalizationMode, number> = {\n plain_text: 0,\n wrapped_block: 1,\n extracted_block: 2,\n }\n return rank[left] >= rank[right] ? left : right\n}\n\nasync function persistPluginState(\n context: PluginSessionControllerContext,\n state: AutoCompactPluginStateData,\n): Promise<void> {\n await context.pluginState.replace(context.sessionId, {\n version: 2,\n data: serializePluginState(state),\n updatedAt: Date.now(),\n })\n}\n\nfunction readPluginState(entry: PluginSessionStateEntry | undefined): AutoCompactPluginStateData {\n if (!entry || entry.version !== 2) return { strategy: 'controller-v2' }\n if (!isAutoCompactPluginStateData(entry.data)) return { strategy: 'controller-v2' }\n return structuredClone(entry.data)\n}\n\nfunction serializePluginState(state: AutoCompactPluginStateData): AutoCompactPluginStateRecord {\n const serialized: AutoCompactPluginStateRecord = {\n strategy: state.strategy,\n }\n\n if (state.summaryModel) {\n serialized.summaryModel = {\n provider: state.summaryModel.provider,\n modelId: state.summaryModel.modelId,\n }\n }\n\n if (state.lastResult) {\n serialized.lastResult = {\n trigger: state.lastResult.trigger,\n status: state.lastResult.status,\n compactedMessageCount: state.lastResult.compactedMessageCount,\n retainedMessageCount: state.lastResult.retainedMessageCount,\n updatedAt: state.lastResult.updatedAt,\n }\n if (state.lastResult.reasonCode) serialized.lastResult.reasonCode = state.lastResult.reasonCode\n if (state.lastResult.reasonMessage) serialized.lastResult.reasonMessage = state.lastResult.reasonMessage\n if (state.lastResult.summaryNormalization)\n serialized.lastResult.summaryNormalization = state.lastResult.summaryNormalization\n if (typeof state.lastResult.summaryInputTokens === 'number')\n serialized.lastResult.summaryInputTokens = state.lastResult.summaryInputTokens\n if (typeof state.lastResult.summaryOutputTokensEstimate === 'number')\n serialized.lastResult.summaryOutputTokensEstimate = state.lastResult.summaryOutputTokensEstimate\n if (typeof state.lastResult.summaryChars === 'number')\n serialized.lastResult.summaryChars = state.lastResult.summaryChars\n if (typeof state.lastResult.summaryCallCount === 'number')\n serialized.lastResult.summaryCallCount = state.lastResult.summaryCallCount\n if (typeof state.lastResult.summaryChunkCount === 'number')\n serialized.lastResult.summaryChunkCount = state.lastResult.summaryChunkCount\n if (typeof state.lastResult.prunedToolOutputCount === 'number')\n serialized.lastResult.prunedToolOutputCount = state.lastResult.prunedToolOutputCount\n if (typeof state.lastResult.preservedToolOutputCount === 'number')\n serialized.lastResult.preservedToolOutputCount = state.lastResult.preservedToolOutputCount\n }\n\n return serialized\n}\n\nfunction createPersistedResult(\n request: CompactionExecutionRequest,\n result: CompactionExecutionResult,\n): AutoCompactPersistedResult {\n return {\n trigger: request.plan.trigger,\n status: result.status,\n compactedMessageCount: request.plan.compactedMessages.length,\n retainedMessageCount: request.plan.retainedMessages.length,\n updatedAt: Date.now(),\n ...(result.reasonCode ? { reasonCode: result.reasonCode } : {}),\n ...(result.reasonMessage ? { reasonMessage: result.reasonMessage } : {}),\n ...(result.diagnostics.summaryNormalization\n ? { summaryNormalization: result.diagnostics.summaryNormalization }\n : {}),\n ...(typeof result.diagnostics.summaryInputTokens === 'number'\n ? { summaryInputTokens: result.diagnostics.summaryInputTokens }\n : {}),\n ...(typeof result.diagnostics.summaryOutputTokensEstimate === 'number'\n ? {\n summaryOutputTokensEstimate: result.diagnostics.summaryOutputTokensEstimate,\n }\n : {}),\n ...(typeof result.diagnostics.summaryChars === 'number'\n ? { summaryChars: result.diagnostics.summaryChars }\n : {}),\n ...(typeof result.diagnostics.summaryCallCount === 'number'\n ? { summaryCallCount: result.diagnostics.summaryCallCount }\n : {}),\n ...(typeof result.diagnostics.summaryChunkCount === 'number'\n ? { summaryChunkCount: result.diagnostics.summaryChunkCount }\n : {}),\n ...(typeof result.diagnostics.prunedToolOutputCount === 'number'\n ? { prunedToolOutputCount: result.diagnostics.prunedToolOutputCount }\n : {}),\n ...(typeof result.diagnostics.preservedToolOutputCount === 'number'\n ? { preservedToolOutputCount: result.diagnostics.preservedToolOutputCount }\n : {}),\n }\n}\n\nfunction positiveIntegerOr(value: number | undefined, fallback: number): number {\n if (!Number.isFinite(value) || value === undefined || value <= 0) return fallback\n return Math.floor(value)\n}\n\nfunction isAutoCompactPluginStateData(value: unknown): value is AutoCompactPluginStateData {\n const candidate = readAutoCompactPluginStateDataCandidate(value)\n if (!candidate) return false\n if (candidate.strategy !== 'controller-v2') return false\n if (candidate.summaryModel !== undefined && !isModelRef(candidate.summaryModel)) return false\n if (\n candidate.lastResult !== undefined &&\n !isAutoCompactPersistedResult(candidate.lastResult)\n )\n return false\n return true\n}\n\nfunction isAutoCompactPersistedResult(value: unknown): value is AutoCompactPersistedResult {\n const candidate = readAutoCompactPersistedResultCandidate(value)\n if (!candidate) return false\n if (candidate.trigger !== 'manual' && candidate.trigger !== 'threshold') return false\n if (\n candidate.status !== 'compacted' &&\n candidate.status !== 'skipped' &&\n candidate.status !== 'failed'\n )\n return false\n if (typeof candidate.compactedMessageCount !== 'number') return false\n if (typeof candidate.retainedMessageCount !== 'number') return false\n if (typeof candidate.updatedAt !== 'number') return false\n if (candidate.reasonCode !== undefined && typeof candidate.reasonCode !== 'string') return false\n if (\n candidate.reasonMessage !== undefined &&\n typeof candidate.reasonMessage !== 'string'\n )\n return false\n if (\n candidate.summaryNormalization !== undefined &&\n candidate.summaryNormalization !== 'plain_text' &&\n candidate.summaryNormalization !== 'wrapped_block' &&\n candidate.summaryNormalization !== 'extracted_block'\n )\n return false\n if (\n candidate.summaryInputTokens !== undefined &&\n typeof candidate.summaryInputTokens !== 'number'\n )\n return false\n if (\n candidate.summaryOutputTokensEstimate !== undefined &&\n typeof candidate.summaryOutputTokensEstimate !== 'number'\n )\n return false\n if (candidate.summaryChars !== undefined && typeof candidate.summaryChars !== 'number')\n return false\n if (\n candidate.summaryCallCount !== undefined &&\n typeof candidate.summaryCallCount !== 'number'\n )\n return false\n if (\n candidate.summaryChunkCount !== undefined &&\n typeof candidate.summaryChunkCount !== 'number'\n )\n return false\n if (\n candidate.prunedToolOutputCount !== undefined &&\n typeof candidate.prunedToolOutputCount !== 'number'\n )\n return false\n if (\n candidate.preservedToolOutputCount !== undefined &&\n typeof candidate.preservedToolOutputCount !== 'number'\n )\n return false\n return true\n}\n\nfunction isModelRef(value: unknown): value is ModelRef {\n const candidate = readModelRefCandidate(value)\n return typeof candidate?.provider === 'string' && typeof candidate.modelId === 'string'\n}\n\nfunction createCodedError(code: string, message: string): Error & { code: string } {\n const error = new Error(message) as Error & { code: string }\n error.code = code\n return error\n}\n\nfunction readErrorCode(error: unknown): string | undefined {\n const candidate = readErrorCodeCandidate(error)\n return typeof candidate?.code === 'string' ? candidate.code : undefined\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction readAutoCompactPluginStateDataCandidate(\n value: unknown,\n): AutoCompactPluginStateDataCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as AutoCompactPluginStateDataCandidate\n}\n\nfunction readAutoCompactPersistedResultCandidate(\n value: unknown,\n): AutoCompactPersistedResultCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as AutoCompactPersistedResultCandidate\n}\n\nfunction readModelRefCandidate(value: unknown): ModelRefCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as ModelRefCandidate\n}\n\nfunction readErrorCodeCandidate(value: unknown): ErrorCodeCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as ErrorCodeCandidate\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n CompactionExecutionRequest,\n CompactionExecutionResult,\n Message,\n ModelRef,\n ModelRequest,\n ModelRequestUsageScope,\n ModelStreamEvent,\n SessionCompactorController,\n SessionStatus,\n UsageRequestKind,\n} from '@archships/dim-agent-sdk'\nimport type {\n DimPlugin,\n LoggerGateway,\n PluginSessionControllerContext,\n PluginSessionStateEntry,\n} from '@archships/dim-plugin-api'\n\nexport interface AutoCompactPluginOptions {\n summaryModel?: ModelRef\n maxSummaryTokens?: number\n summaryInputMaxTokens?: number\n summaryPrompt?: string\n retainMessages?: number\n compaction?: {\n auto?: boolean\n prune?: boolean\n reserved?: number\n }\n}\n\ninterface ResolvedOptions {\n summaryModel?: ModelRef\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n retainMessages: number\n compaction: {\n auto: boolean\n prune: boolean\n reserved: number\n }\n}\n\ninterface AutoCompactPluginStateData {\n strategy: 'controller-v2'\n summaryModel?: ModelRef\n lastResult?: AutoCompactPersistedResult\n}\n\ninterface AutoCompactPersistedResult {\n trigger: 'manual' | 'threshold'\n status: 'compacted' | 'skipped' | 'failed'\n reasonCode?: string\n reasonMessage?: string\n compactedMessageCount: number\n retainedMessageCount: number\n summaryNormalization?: SummaryNormalizationMode\n summaryInputTokens?: number\n summaryOutputTokensEstimate?: number\n summaryChars?: number\n summaryCallCount?: number\n summaryChunkCount?: number\n prunedToolOutputCount?: number\n preservedToolOutputCount?: number\n updatedAt: number\n}\n\ninterface RenderedSummarySection {\n id: string\n text: string\n tokens: number\n}\n\ninterface RenderedSummaryInput {\n prefixSections: RenderedSummarySection[]\n messageSections: RenderedSummarySection[]\n prunedToolOutputCount: number\n preservedToolOutputCount: number\n}\n\ninterface NormalizedSummaryGenerationResult {\n summary: string\n summaryNormalization: SummaryNormalizationMode\n summaryInputTokens: number\n summaryOutputTokensEstimate: number\n summaryChars: number\n summaryCallCount: number\n summaryChunkCount: number\n prunedToolOutputCount: number\n preservedToolOutputCount: number\n}\n\ntype SummaryGenerationResult =\n | ({ status: 'normalized' } & NormalizedSummaryGenerationResult)\n | { status: 'empty_body_preserve_previous' }\n | { status: 'invalid_summary_contract' }\n\ntype SummaryNormalizationMode = 'plain_text' | 'wrapped_block' | 'extracted_block'\n\ntype CanonicalContinuationSummary =\n | {\n status: 'normalized'\n summary: string\n normalization: SummaryNormalizationMode\n }\n | {\n status: 'empty_body'\n }\n\ntype SuccessfulContinuationSummary = Extract<\n CanonicalContinuationSummary,\n { status: 'normalized' }\n>\n\ninterface RenderedMessage {\n text: string\n prunedToolOutput: boolean\n preservedToolOutput: boolean\n}\n\ninterface AutoCompactInspectorConfig {\n summaryModel?: { provider: string; modelId: string }\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n retainMessages: number\n compaction: {\n auto: boolean\n prune: boolean\n reserved: number\n }\n}\n\ninterface AutoCompactPluginStateRecord {\n strategy: 'controller-v2'\n summaryModel?: {\n provider: string\n modelId: string\n }\n lastResult?: AutoCompactPersistedResult\n}\n\ninterface AutoCompactPlanningController extends SessionCompactorController {\n readPlanningOptions(): {\n auto: boolean\n retainMessages: number\n reservedTokens: number\n summaryTokenReserve: number\n }\n}\n\ninterface AutoCompactPluginStateDataCandidate {\n strategy?: unknown\n summaryModel?: unknown\n lastResult?: unknown\n}\n\ninterface AutoCompactPersistedResultCandidate {\n trigger?: unknown\n status?: unknown\n compactedMessageCount?: unknown\n retainedMessageCount?: unknown\n updatedAt?: unknown\n reasonCode?: unknown\n reasonMessage?: unknown\n summaryNormalization?: unknown\n summaryInputTokens?: unknown\n summaryOutputTokensEstimate?: unknown\n summaryChars?: unknown\n summaryCallCount?: unknown\n summaryChunkCount?: unknown\n prunedToolOutputCount?: unknown\n preservedToolOutputCount?: unknown\n}\n\ninterface ModelRefCandidate {\n provider?: unknown\n modelId?: unknown\n}\n\ninterface ErrorCodeCandidate {\n code?: unknown\n}\n\nconst DEFAULT_MAX_SUMMARY_TOKENS = 1024\nconst DEFAULT_SUMMARY_INPUT_MAX_TOKENS = 16000\nconst DEFAULT_RETAIN_MESSAGES = 4\nconst DEFAULT_THRESHOLD_HEADROOM = 1024\nconst DEFAULT_RECENT_TOOL_OUTPUTS_TO_PRESERVE = 2\nconst DEFAULT_TOOL_OUTPUT_PREVIEW_CHAR_LIMIT = 1200\nconst DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN = 1024\nconst MAX_SUMMARY_RECURSION_PASSES = 2\nconst CONTINUATION_SUMMARY_OPEN_TAG = '<continuation_summary>'\nconst CONTINUATION_SUMMARY_CLOSE_TAG = '</continuation_summary>'\nconst CONTINUATION_SUMMARY_BLOCK_PATTERN =\n /<continuation_summary>([\\s\\S]*?)<\\/continuation_summary>/g\nconst CONTINUATION_SUMMARY_TAG_FRAGMENT_PATTERN = /<\\/?continuation_summary>?/g\n\nconst DEFAULT_SUMMARY_PROMPT = `You have been working on the task described above but have not yet completed it. Write a continuation summary that will allow you (or another instance of yourself) to resume work efficiently in a future context window where the conversation history will be replaced with this summary. Your summary should be structured, concise, and actionable. Include:\n\nTask Overview\nThe user's core request and success criteria\nAny clarifications or constraints they specified\n\nCurrent State\nWhat has been completed so far\nFiles created, modified, or analyzed (with paths if relevant)\nKey outputs or artifacts produced\n\nImportant Discoveries\nTechnical constraints or requirements uncovered\nDecisions made and their rationale\nErrors encountered and how they were resolved\nWhat approaches were tried that didn't work (and why)\n\nNext Steps\nSpecific actions needed to complete the task\nAny blockers or open questions to resolve\nPriority order if multiple steps remain\n\nContext to Preserve\nUser preferences or style requirements\nDomain-specific details that aren't obvious\nAny promises made to the user\n\nBe concise but complete—err on the side of including information that would prevent duplicate work or repeated mistakes.\nWrite in a way that enables immediate resumption of the task.\nReturn only the continuation summary body as plain text. Do not add XML tags, wrappers, or surrounding commentary.`\n\nexport function createAutoCompactPlugin(): DimPlugin<'auto-compact', SessionCompactorController>\nexport function createAutoCompactPlugin(\n options: AutoCompactPluginOptions,\n): DimPlugin<'auto-compact', SessionCompactorController>\nexport function createAutoCompactPlugin<TId extends string>(\n options: AutoCompactPluginOptions & { id: TId },\n): DimPlugin<TId, SessionCompactorController>\nexport function createAutoCompactPlugin<TId extends string>(\n options: AutoCompactPluginOptions & { id?: TId } = {},\n): DimPlugin<TId, SessionCompactorController> {\n const resolved = resolveOptions(options)\n\n return {\n manifest: {\n id: (options.id ?? 'auto-compact') as TId,\n version: '0.2.0',\n apiVersion: 1,\n permissions: { model: true },\n capabilities: ['auto-compact'],\n },\n setup(context) {\n return {\n inspector: {\n getConfig: async (): Promise<AutoCompactInspectorConfig> => {\n const config: AutoCompactInspectorConfig = {\n maxSummaryTokens: resolved.maxSummaryTokens,\n summaryInputMaxTokens: resolved.summaryInputMaxTokens,\n summaryPrompt: resolved.summaryPrompt,\n retainMessages: resolved.retainMessages,\n compaction: {\n auto: resolved.compaction.auto,\n prune: resolved.compaction.prune,\n reserved: resolved.compaction.reserved,\n },\n }\n if (resolved.summaryModel) {\n config.summaryModel = {\n provider: resolved.summaryModel.provider,\n modelId: resolved.summaryModel.modelId,\n }\n }\n return config\n },\n getSessionState: async (sessionId) =>\n structuredClone(\n readPluginState(await context.services.pluginState.get(sessionId)),\n ),\n },\n createSessionController: (controllerContext) =>\n createAutoCompactController({\n options: resolved,\n logger: context.services.logger,\n model: context.services.model,\n context: controllerContext,\n }),\n }\n },\n }\n}\n\nfunction createAutoCompactController(input: {\n options: ResolvedOptions\n logger: LoggerGateway\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n context: PluginSessionControllerContext\n}): AutoCompactPlanningController {\n return {\n readPlanningOptions() {\n return {\n auto: input.options.compaction.auto,\n retainMessages: input.options.retainMessages,\n reservedTokens: input.options.compaction.reserved,\n summaryTokenReserve: input.options.maxSummaryTokens,\n }\n },\n async compact(request: CompactionExecutionRequest): Promise<CompactionExecutionResult> {\n const sessionStatus = input.context.getStatus()\n const summaryModel = input.options.summaryModel ?? sessionStatus.model\n\n if (!summaryModel) {\n const result: CompactionExecutionResult = {\n status: 'skipped',\n reasonCode: 'missing_summary_model',\n reasonMessage: 'Auto compact summary model is unavailable',\n diagnostics: {},\n }\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n ...(input.options.summaryModel ? { summaryModel: input.options.summaryModel } : {}),\n lastResult: createPersistedResult(request, result),\n })\n return result\n }\n\n try {\n const summary = await generateSummary({\n contextStatus: sessionStatus,\n summaryModel,\n maxSummaryTokens: input.options.maxSummaryTokens,\n summaryInputMaxTokens: input.options.summaryInputMaxTokens,\n summaryPrompt: input.options.summaryPrompt,\n existingSystemSegments: request.plan.existingSystemSegments,\n compactedMessages: request.plan.compactedMessages,\n pruneToolOutputs: input.options.compaction.prune,\n sessionId: input.context.sessionId,\n usageKind:\n request.plan.trigger === 'manual' ? 'manual_compaction' : 'auto_compaction',\n model: input.model,\n logger: input.logger,\n })\n\n const result =\n summary.status === 'normalized'\n ? {\n status: 'compacted' as const,\n summary: summary.summary,\n diagnostics: {\n summaryNormalization: summary.summaryNormalization,\n summaryInputTokens: summary.summaryInputTokens,\n summaryOutputTokensEstimate: summary.summaryOutputTokensEstimate,\n summaryChars: summary.summaryChars,\n summaryCallCount: summary.summaryCallCount,\n summaryChunkCount: summary.summaryChunkCount,\n prunedToolOutputCount: summary.prunedToolOutputCount,\n preservedToolOutputCount: summary.preservedToolOutputCount,\n },\n }\n : summary.status === 'empty_body_preserve_previous'\n ? {\n status: 'skipped' as const,\n reasonCode: 'empty_summary_preserved_previous',\n reasonMessage:\n 'Summary generation produced an empty body and preserved the existing continuation summary',\n diagnostics: {},\n }\n : {\n status: 'failed' as const,\n reasonCode: 'invalid_summary_contract',\n reasonMessage: 'Auto compact summary body cannot be empty',\n diagnostics: {},\n }\n\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n summaryModel,\n lastResult: createPersistedResult(request, result),\n })\n return result\n } catch (error) {\n const result: CompactionExecutionResult = {\n status: 'failed',\n reasonCode: readErrorCode(error) ?? 'summary_generation_failed',\n reasonMessage: readErrorMessage(error),\n diagnostics: {},\n }\n await persistPluginState(input.context, {\n strategy: 'controller-v2',\n summaryModel,\n lastResult: createPersistedResult(request, result),\n })\n return result\n }\n },\n }\n}\n\nfunction resolveOptions(options: AutoCompactPluginOptions): ResolvedOptions {\n return {\n summaryModel: options.summaryModel,\n maxSummaryTokens: positiveIntegerOr(\n options.maxSummaryTokens,\n DEFAULT_MAX_SUMMARY_TOKENS,\n ),\n summaryInputMaxTokens: Math.max(\n DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN + 256,\n positiveIntegerOr(options.summaryInputMaxTokens, DEFAULT_SUMMARY_INPUT_MAX_TOKENS),\n ),\n summaryPrompt: options.summaryPrompt?.trim() || DEFAULT_SUMMARY_PROMPT,\n retainMessages: Math.max(1, positiveIntegerOr(options.retainMessages, DEFAULT_RETAIN_MESSAGES)),\n compaction: {\n auto: options.compaction?.auto ?? true,\n prune: options.compaction?.prune ?? true,\n reserved: Math.max(0, Math.floor(options.compaction?.reserved ?? DEFAULT_THRESHOLD_HEADROOM)),\n },\n }\n}\n\nasync function generateSummary(input: {\n contextStatus?: SessionStatus\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryInputMaxTokens: number\n summaryPrompt: string\n existingSystemSegments: string[]\n compactedMessages: Message[]\n pruneToolOutputs: boolean\n sessionId: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n}): Promise<SummaryGenerationResult> {\n const renderedInput = buildSummaryInput(\n input.existingSystemSegments,\n input.compactedMessages,\n input.pruneToolOutputs,\n input.contextStatus,\n )\n const summaryInputTokens = estimateSectionsTokens([\n ...renderedInput.prefixSections,\n ...renderedInput.messageSections,\n ])\n const summaryInputBudget = Math.max(\n 256,\n input.summaryInputMaxTokens - DEFAULT_SUMMARY_INPUT_SAFETY_MARGIN,\n )\n let summarized: Awaited<ReturnType<typeof summarizeRenderedSections>>\n\n try {\n summarized = await summarizeRenderedSections({\n stage: 'source',\n remainingLevels: MAX_SUMMARY_RECURSION_PASSES,\n prefixSections: renderedInput.prefixSections,\n messageSections: renderedInput.messageSections,\n summaryInputBudget,\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n usageKind: input.usageKind,\n model: input.model,\n logger: input.logger,\n })\n } catch (error) {\n if (readErrorCode(error) === 'empty_summary_body') {\n return input.existingSystemSegments.join('\\n\\n').trim()\n ? { status: 'empty_body_preserve_previous' }\n : { status: 'invalid_summary_contract' }\n }\n throw error\n }\n\n return {\n status: 'normalized',\n summary: summarized.summary,\n summaryNormalization: summarized.summaryNormalization,\n summaryInputTokens,\n summaryOutputTokensEstimate: estimateTextTokens(summarized.summary),\n summaryChars: summarized.summary.length,\n summaryCallCount: summarized.summaryCallCount,\n summaryChunkCount: summarized.summaryChunkCount,\n prunedToolOutputCount: renderedInput.prunedToolOutputCount,\n preservedToolOutputCount: renderedInput.preservedToolOutputCount,\n }\n}\n\nfunction buildSummaryInput(\n existingSystemSegments: string[],\n compactedMessages: Message[],\n pruneToolOutputs: boolean,\n status?: SessionStatus,\n): RenderedSummaryInput {\n const summaryMessages = compactedMessages\n if (summaryMessages.length === 0) {\n return {\n prefixSections: [\n createRenderedSummarySection(\n 'status',\n [\n 'Current canonical session status:',\n status\n ? [\n `- sessionId: ${status.sessionId}`,\n `- model: ${status.model.provider}/${status.model.modelId}`,\n `- messageCount: ${status.messageCount}`,\n `- compactionCursor: ${status.compaction.cursor}`,\n ].join('\\n')\n : '- unavailable',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'existing-summary',\n [\n 'Existing compaction summary:',\n existingSystemSegments.length > 0 ? existingSystemSegments.join('\\n\\n') : '(none)',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'messages-heading',\n 'Messages to compact:\\n(no eligible messages after summary-input filtering)',\n ),\n ],\n messageSections: [],\n prunedToolOutputCount: 0,\n preservedToolOutputCount: 0,\n }\n }\n\n const preservedToolOutputIds = buildPreservedToolOutputIds(summaryMessages, pruneToolOutputs)\n let prunedToolOutputCount = 0\n let preservedToolOutputCount = 0\n\n const prefixSections = [\n createRenderedSummarySection(\n 'status',\n [\n 'Current canonical session status:',\n status\n ? [\n `- sessionId: ${status.sessionId}`,\n `- model: ${status.model.provider}/${status.model.modelId}`,\n `- messageCount: ${status.messageCount}`,\n `- compactionCursor: ${status.compaction.cursor}`,\n ].join('\\n')\n : '- unavailable',\n ].join('\\n'),\n ),\n createRenderedSummarySection(\n 'existing-summary',\n [\n 'Existing compaction summary:',\n existingSystemSegments.length > 0 ? existingSystemSegments.join('\\n\\n') : '(none)',\n ].join('\\n'),\n ),\n createRenderedSummarySection('messages-heading', 'Messages to compact:'),\n ]\n\n const messageSections = summaryMessages.map((message, index) => {\n const renderedMessage = renderMessage(message, pruneToolOutputs, preservedToolOutputIds)\n if (renderedMessage.prunedToolOutput) prunedToolOutputCount += 1\n if (renderedMessage.preservedToolOutput) preservedToolOutputCount += 1\n\n return createRenderedSummarySection(\n message.id,\n [`Message ${index + 1}`, renderedMessage.text].join('\\n'),\n )\n })\n\n return {\n prefixSections,\n messageSections,\n prunedToolOutputCount,\n preservedToolOutputCount,\n }\n}\n\nasync function summarizeRenderedSections(input: {\n stage: 'source' | 'merge'\n remainingLevels: number\n prefixSections: RenderedSummarySection[]\n messageSections: RenderedSummarySection[]\n summaryInputBudget: number\n sessionId: string\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryPrompt: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n}): Promise<{\n summary: string\n summaryNormalization: SummaryNormalizationMode\n summaryCallCount: number\n summaryChunkCount: number\n}> {\n const combinedText = joinSummarySections(input.prefixSections, input.messageSections)\n if (estimateTextTokens(combinedText) <= input.summaryInputBudget) {\n const canonical = await streamSummaryText({\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n summaryInputText: combinedText,\n summaryKind: input.stage === 'source' ? 'summary' : 'summary-merge',\n usageKind: input.usageKind,\n model: input.model,\n logger: input.logger,\n })\n return {\n summary: canonical.summary,\n summaryNormalization: canonical.normalization,\n summaryCallCount: 1,\n summaryChunkCount: 0,\n }\n }\n\n if (input.remainingLevels <= 1) {\n throw createCodedError(\n input.stage === 'merge' ? 'summary_merge_over_budget' : 'summary_source_too_large',\n input.stage === 'merge'\n ? 'Chunk summaries still exceed the summary model input budget'\n : 'Source history exceeds the summary model input budget',\n )\n }\n\n const chunks = createSummaryChunks(\n input.prefixSections,\n input.messageSections,\n input.summaryInputBudget,\n )\n if (chunks.length <= 1) {\n throw createCodedError(\n input.stage === 'merge' ? 'summary_merge_over_budget' : 'summary_source_too_large',\n input.stage === 'merge'\n ? 'Unable to merge chunk summaries within the summary model input budget'\n : 'Unable to fit source history into chunked summary requests',\n )\n }\n\n let summaryCallCount = 0\n let summaryNormalization: SummaryNormalizationMode = 'plain_text'\n const chunkSummarySections: RenderedSummarySection[] = []\n\n for (const [index, chunk] of chunks.entries()) {\n const canonical = await streamSummaryText({\n sessionId: input.sessionId,\n summaryModel: input.summaryModel,\n maxSummaryTokens: input.maxSummaryTokens,\n summaryPrompt: input.summaryPrompt,\n summaryInputText: joinSummarySections(input.prefixSections, chunk),\n summaryKind: 'summary-chunk',\n usageKind: input.usageKind,\n model: input.model,\n chunkIndex: index,\n chunkCount: chunks.length,\n logger: input.logger,\n })\n summaryCallCount += 1\n summaryNormalization = mergeSummaryNormalizationModes(\n summaryNormalization,\n canonical.normalization,\n )\n\n chunkSummarySections.push(\n createRenderedSummarySection(\n `chunk-summary-${index + 1}`,\n `Chunk summary ${index + 1} of ${chunks.length}\\n${canonical.summary}`,\n ),\n )\n }\n\n const merged = await summarizeRenderedSections({\n ...input,\n stage: 'merge',\n remainingLevels: input.remainingLevels - 1,\n messageSections: chunkSummarySections,\n })\n\n return {\n summary: merged.summary,\n summaryNormalization: mergeSummaryNormalizationModes(\n summaryNormalization,\n merged.summaryNormalization,\n ),\n summaryCallCount: summaryCallCount + merged.summaryCallCount,\n summaryChunkCount: chunks.length + merged.summaryChunkCount,\n }\n}\n\nasync function streamSummaryText(input: {\n sessionId: string\n summaryModel: ModelRef\n maxSummaryTokens: number\n summaryPrompt: string\n summaryInputText: string\n summaryKind: string\n usageKind: UsageRequestKind\n model: {\n stream(\n request: ModelRequest,\n options?: { usage?: ModelRequestUsageScope },\n ): AsyncIterable<ModelStreamEvent>\n }\n logger: LoggerGateway\n chunkIndex?: number\n chunkCount?: number\n}): Promise<SuccessfulContinuationSummary> {\n const request: ModelRequest = {\n model: input.summaryModel,\n maxOutputTokens: input.maxSummaryTokens,\n metadata: {\n dimAutoCompact: true,\n dimAutoCompactKind: input.summaryKind,\n sessionId: input.sessionId,\n ...(typeof input.chunkIndex === 'number' ? { chunkIndex: input.chunkIndex } : {}),\n ...(typeof input.chunkCount === 'number' ? { chunkCount: input.chunkCount } : {}),\n },\n messages: [\n createSyntheticMessage('system', input.summaryPrompt),\n createSyntheticMessage('user', input.summaryInputText),\n ],\n }\n\n let text = ''\n for await (const event of input.model.stream(request, {\n usage: {\n sessionId: input.sessionId,\n kind: input.usageKind,\n },\n })) {\n if (event.type === 'text_delta') text += event.delta\n if (event.type === 'error')\n throw createCodedError(\n event.error.code ?? 'summary_generation_failed',\n event.error.message,\n )\n }\n\n if (!text.trim())\n throw createCodedError('empty_summary_body', 'Auto compact summary body cannot be empty')\n\n const canonical = canonicalizeContinuationSummary(text)\n if (canonical.status === 'empty_body') {\n throw createCodedError('empty_summary_body', 'Auto compact summary body cannot be empty')\n }\n if (canonical.normalization !== 'plain_text') {\n input.logger.emit({\n level: 'warn',\n source: 'auto-compact',\n message:\n 'Auto compact summary output deviated from the preferred plain-text contract; normalized automatically',\n metadata: {\n sessionId: input.sessionId,\n summaryKind: input.summaryKind,\n summaryNormalization: canonical.normalization,\n ...(typeof input.chunkIndex === 'number' ? { chunkIndex: input.chunkIndex } : {}),\n ...(typeof input.chunkCount === 'number' ? { chunkCount: input.chunkCount } : {}),\n },\n })\n }\n\n return canonical\n}\n\nfunction renderMessage(\n message: Message,\n pruneToolOutputs: boolean,\n preservedToolOutputIds: Set<string>,\n): RenderedMessage {\n const text = renderMessageText(message).trim() || '(empty)'\n\n if (message.role === 'assistant') {\n const toolCalls = renderAssistantToolCalls(message)\n const body = [text, toolCalls].filter((entry) => entry.trim().length > 0).join('\\n\\n')\n return {\n text: `[assistant] ${body || '(empty)'}`,\n prunedToolOutput: false,\n preservedToolOutput: false,\n }\n }\n\n if (message.role !== 'tool') {\n return {\n text: `[${message.role}] ${text}`,\n prunedToolOutput: false,\n preservedToolOutput: false,\n }\n }\n\n const header = `[tool:${message.toolName} call=${message.toolCallId} status=${\n message.isError ? 'error' : 'ok'\n }]`\n\n const renderedBody = renderToolMessageBody(message, pruneToolOutputs, preservedToolOutputIds)\n return {\n text: [header, renderedBody.text].join('\\n'),\n prunedToolOutput: renderedBody.pruned,\n preservedToolOutput: renderedBody.preserved,\n }\n}\n\nfunction renderMessageText(message: Message): string {\n const text = renderMessageContentText(message)\n\n if (message.role === 'tool' && text.length === 0 && message.structuredContent)\n return JSON.stringify(message.structuredContent)\n\n return text\n}\n\nfunction renderMessageContentText(message: Message): string {\n const blocks = message.content.map((block) => {\n if (block.type === 'text') return block.text\n return `[file:${block.mediaType}]`\n })\n return blocks.join('\\n').trim()\n}\n\nfunction renderAssistantToolCalls(message: Extract<Message, { role: 'assistant' }>): string {\n if (!message.toolCalls || message.toolCalls.length === 0) return ''\n\n return [\n 'toolCalls:',\n ...message.toolCalls.map((toolCall, index) =>\n [\n `- index: ${index + 1}`,\n ` id: ${toolCall.id}`,\n ` name: ${toolCall.function.name}`,\n ` arguments: ${stringifyJson(toolCall.function.arguments)}`,\n ].join('\\n'),\n ),\n ].join('\\n')\n}\n\nfunction renderToolMessageBody(\n message: Extract<Message, { role: 'tool' }>,\n pruneToolOutputs: boolean,\n preservedToolOutputIds: Set<string>,\n): { text: string; pruned: boolean; preserved: boolean } {\n const contentText = renderMessageContentText(message).trim()\n const structuredContentText =\n message.structuredContent === undefined ? '' : stringifyJson(message.structuredContent)\n\n if (pruneToolOutputs && !preservedToolOutputIds.has(message.id)) {\n const descriptors = [\n `contentChars=${contentText.length}`,\n `structuredContentChars=${structuredContentText.length}`,\n ]\n return {\n text: `output omitted for compaction summary (${descriptors.join(', ')})`,\n pruned: true,\n preserved: false,\n }\n }\n\n const sections: string[] = []\n if (contentText.length > 0) {\n sections.push(renderToolOutputSection('content', contentText, pruneToolOutputs))\n }\n if (structuredContentText.length > 0) {\n sections.push(\n renderToolOutputSection('structuredContent', structuredContentText, pruneToolOutputs),\n )\n }\n return {\n text: sections.join('\\n\\n') || '(empty)',\n pruned: false,\n preserved: pruneToolOutputs,\n }\n}\n\nfunction renderToolOutputSection(\n label: string,\n text: string,\n pruneToolOutputs: boolean,\n): string {\n if (!pruneToolOutputs) return `${label}:\\n${text}`\n\n const truncated = truncateText(text, DEFAULT_TOOL_OUTPUT_PREVIEW_CHAR_LIMIT)\n return `${label}Preview:\\n${truncated}`\n}\n\nfunction buildPreservedToolOutputIds(\n messages: Message[],\n pruneToolOutputs: boolean,\n): Set<string> {\n if (!pruneToolOutputs) return new Set()\n\n const preserved = new Set<string>()\n const toolMessages = messages.filter(\n (message): message is Extract<Message, { role: 'tool' }> => message.role === 'tool',\n )\n\n for (const message of toolMessages.slice(-DEFAULT_RECENT_TOOL_OUTPUTS_TO_PRESERVE))\n preserved.add(message.id)\n for (const message of toolMessages) {\n if (message.isError) preserved.add(message.id)\n }\n\n return preserved\n}\n\nfunction stringifyJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2)\n } catch {\n return String(value)\n }\n}\n\nfunction createRenderedSummarySection(id: string, text: string): RenderedSummarySection {\n return {\n id,\n text,\n tokens: estimateTextTokens(text),\n }\n}\n\nfunction createSummaryChunks(\n prefixSections: RenderedSummarySection[],\n messageSections: RenderedSummarySection[],\n summaryInputBudget: number,\n): RenderedSummarySection[][] {\n if (messageSections.length === 0) return []\n\n const prefixTokens = estimateSectionsTokens(prefixSections)\n const messageBudget = summaryInputBudget - prefixTokens\n if (messageBudget <= 64) return []\n\n const chunks: RenderedSummarySection[][] = []\n let currentChunk: RenderedSummarySection[] = []\n let currentChunkTokens = 0\n\n for (const section of messageSections) {\n let nextSection = section\n if (nextSection.tokens > messageBudget) {\n nextSection = truncateSectionToBudget(nextSection, messageBudget)\n if (nextSection.tokens > messageBudget) return []\n }\n\n if (currentChunk.length > 0 && currentChunkTokens + nextSection.tokens > messageBudget) {\n chunks.push(currentChunk)\n currentChunk = []\n currentChunkTokens = 0\n }\n\n currentChunk.push(nextSection)\n currentChunkTokens += nextSection.tokens\n }\n\n if (currentChunk.length > 0) chunks.push(currentChunk)\n return chunks\n}\n\nfunction truncateSectionToBudget(\n section: RenderedSummarySection,\n budgetTokens: number,\n): RenderedSummarySection {\n const budgetChars = Math.max(128, budgetTokens * 4 - 64)\n if (section.text.length <= budgetChars) return section\n\n return createRenderedSummarySection(section.id, truncateText(section.text, budgetChars))\n}\n\nfunction truncateText(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text\n\n const suffix = `\\n[truncated from ${text.length} chars]`\n const preservedChars = Math.max(0, maxChars - suffix.length)\n if (preservedChars <= 256) return `${text.slice(0, preservedChars).trimEnd()}${suffix}`\n\n const omittedMarker = '\\n[...]\\n'\n const availableChars = Math.max(0, preservedChars - omittedMarker.length)\n const headChars = Math.ceil(availableChars * 0.65)\n const tailChars = Math.max(0, availableChars - headChars)\n return [\n text.slice(0, headChars).trimEnd(),\n text.slice(Math.max(headChars, text.length - tailChars)).trimStart(),\n ].join(omittedMarker) + suffix\n}\n\nfunction joinSummarySections(\n prefixSections: RenderedSummarySection[],\n messageSections: RenderedSummarySection[],\n): string {\n return [...prefixSections, ...messageSections].map((section) => section.text).join('\\n\\n')\n}\n\nfunction estimateSectionsTokens(sections: RenderedSummarySection[]): number {\n return sections.reduce((total, section) => total + section.tokens, 0)\n}\n\nfunction estimateTextTokens(text: string): number {\n return Math.max(1, Math.ceil(text.length / 4))\n}\n\nfunction createSyntheticMessage(role: 'system' | 'user', text: string): Message {\n return {\n id: `auto_compact_${role}_${Date.now()}`,\n role,\n content: [{ type: 'text', text }],\n createdAt: Date.now(),\n }\n}\n\nfunction canonicalizeContinuationSummary(summary: string): CanonicalContinuationSummary {\n const trimmed = summary.trim()\n if (!trimmed) return { status: 'empty_body' }\n\n const blockMatches = [...trimmed.matchAll(CONTINUATION_SUMMARY_BLOCK_PATTERN)]\n const blockBodies = blockMatches\n .map((match) => match?.[1]?.trim() ?? '')\n .filter((body) => body.length > 0)\n\n if (blockBodies.length > 0) {\n const [match] = blockMatches\n return {\n status: 'normalized',\n summary: renderCanonicalContinuationSummary(blockBodies.join('\\n\\n')),\n normalization:\n blockMatches.length === 1 && match?.index === 0 && match[0].length === trimmed.length\n ? 'wrapped_block'\n : 'extracted_block',\n }\n }\n\n const stripped = stripContinuationSummaryTagFragments(trimmed).trim()\n if (!stripped) return { status: 'empty_body' }\n\n return {\n status: 'normalized',\n summary: renderCanonicalContinuationSummary(stripped),\n normalization: stripped === trimmed ? 'plain_text' : 'extracted_block',\n }\n}\n\nfunction renderCanonicalContinuationSummary(body: string): string {\n return `${CONTINUATION_SUMMARY_OPEN_TAG}\\n${body}\\n${CONTINUATION_SUMMARY_CLOSE_TAG}`\n}\n\nfunction stripContinuationSummaryTagFragments(text: string): string {\n return text.replace(CONTINUATION_SUMMARY_TAG_FRAGMENT_PATTERN, '\\n')\n}\n\nfunction mergeSummaryNormalizationModes(\n left: SummaryNormalizationMode,\n right: SummaryNormalizationMode,\n): SummaryNormalizationMode {\n const rank: Record<SummaryNormalizationMode, number> = {\n plain_text: 0,\n wrapped_block: 1,\n extracted_block: 2,\n }\n return rank[left] >= rank[right] ? left : right\n}\n\nasync function persistPluginState(\n context: PluginSessionControllerContext,\n state: AutoCompactPluginStateData,\n): Promise<void> {\n await context.pluginState.replace(context.sessionId, {\n version: 2,\n data: serializePluginState(state),\n updatedAt: Date.now(),\n })\n}\n\nfunction readPluginState(entry: PluginSessionStateEntry | undefined): AutoCompactPluginStateData {\n if (!entry || entry.version !== 2) return { strategy: 'controller-v2' }\n if (!isAutoCompactPluginStateData(entry.data)) return { strategy: 'controller-v2' }\n return structuredClone(entry.data)\n}\n\nfunction serializePluginState(state: AutoCompactPluginStateData): AutoCompactPluginStateRecord {\n const serialized: AutoCompactPluginStateRecord = {\n strategy: state.strategy,\n }\n\n if (state.summaryModel) {\n serialized.summaryModel = {\n provider: state.summaryModel.provider,\n modelId: state.summaryModel.modelId,\n }\n }\n\n if (state.lastResult) {\n serialized.lastResult = {\n trigger: state.lastResult.trigger,\n status: state.lastResult.status,\n compactedMessageCount: state.lastResult.compactedMessageCount,\n retainedMessageCount: state.lastResult.retainedMessageCount,\n updatedAt: state.lastResult.updatedAt,\n }\n if (state.lastResult.reasonCode) serialized.lastResult.reasonCode = state.lastResult.reasonCode\n if (state.lastResult.reasonMessage) serialized.lastResult.reasonMessage = state.lastResult.reasonMessage\n if (state.lastResult.summaryNormalization)\n serialized.lastResult.summaryNormalization = state.lastResult.summaryNormalization\n if (typeof state.lastResult.summaryInputTokens === 'number')\n serialized.lastResult.summaryInputTokens = state.lastResult.summaryInputTokens\n if (typeof state.lastResult.summaryOutputTokensEstimate === 'number')\n serialized.lastResult.summaryOutputTokensEstimate = state.lastResult.summaryOutputTokensEstimate\n if (typeof state.lastResult.summaryChars === 'number')\n serialized.lastResult.summaryChars = state.lastResult.summaryChars\n if (typeof state.lastResult.summaryCallCount === 'number')\n serialized.lastResult.summaryCallCount = state.lastResult.summaryCallCount\n if (typeof state.lastResult.summaryChunkCount === 'number')\n serialized.lastResult.summaryChunkCount = state.lastResult.summaryChunkCount\n if (typeof state.lastResult.prunedToolOutputCount === 'number')\n serialized.lastResult.prunedToolOutputCount = state.lastResult.prunedToolOutputCount\n if (typeof state.lastResult.preservedToolOutputCount === 'number')\n serialized.lastResult.preservedToolOutputCount = state.lastResult.preservedToolOutputCount\n }\n\n return serialized\n}\n\nfunction createPersistedResult(\n request: CompactionExecutionRequest,\n result: CompactionExecutionResult,\n): AutoCompactPersistedResult {\n return {\n trigger: request.plan.trigger,\n status: result.status,\n compactedMessageCount: request.plan.compactedMessages.length,\n retainedMessageCount: request.plan.retainedMessages.length,\n updatedAt: Date.now(),\n ...(result.reasonCode ? { reasonCode: result.reasonCode } : {}),\n ...(result.reasonMessage ? { reasonMessage: result.reasonMessage } : {}),\n ...(result.diagnostics.summaryNormalization\n ? { summaryNormalization: result.diagnostics.summaryNormalization }\n : {}),\n ...(typeof result.diagnostics.summaryInputTokens === 'number'\n ? { summaryInputTokens: result.diagnostics.summaryInputTokens }\n : {}),\n ...(typeof result.diagnostics.summaryOutputTokensEstimate === 'number'\n ? {\n summaryOutputTokensEstimate: result.diagnostics.summaryOutputTokensEstimate,\n }\n : {}),\n ...(typeof result.diagnostics.summaryChars === 'number'\n ? { summaryChars: result.diagnostics.summaryChars }\n : {}),\n ...(typeof result.diagnostics.summaryCallCount === 'number'\n ? { summaryCallCount: result.diagnostics.summaryCallCount }\n : {}),\n ...(typeof result.diagnostics.summaryChunkCount === 'number'\n ? { summaryChunkCount: result.diagnostics.summaryChunkCount }\n : {}),\n ...(typeof result.diagnostics.prunedToolOutputCount === 'number'\n ? { prunedToolOutputCount: result.diagnostics.prunedToolOutputCount }\n : {}),\n ...(typeof result.diagnostics.preservedToolOutputCount === 'number'\n ? { preservedToolOutputCount: result.diagnostics.preservedToolOutputCount }\n : {}),\n }\n}\n\nfunction positiveIntegerOr(value: number | undefined, fallback: number): number {\n if (!Number.isFinite(value) || value === undefined || value <= 0) return fallback\n return Math.floor(value)\n}\n\nfunction isAutoCompactPluginStateData(value: unknown): value is AutoCompactPluginStateData {\n const candidate = readAutoCompactPluginStateDataCandidate(value)\n if (!candidate) return false\n if (candidate.strategy !== 'controller-v2') return false\n if (candidate.summaryModel !== undefined && !isModelRef(candidate.summaryModel)) return false\n if (\n candidate.lastResult !== undefined &&\n !isAutoCompactPersistedResult(candidate.lastResult)\n )\n return false\n return true\n}\n\nfunction isAutoCompactPersistedResult(value: unknown): value is AutoCompactPersistedResult {\n const candidate = readAutoCompactPersistedResultCandidate(value)\n if (!candidate) return false\n if (candidate.trigger !== 'manual' && candidate.trigger !== 'threshold') return false\n if (\n candidate.status !== 'compacted' &&\n candidate.status !== 'skipped' &&\n candidate.status !== 'failed'\n )\n return false\n if (typeof candidate.compactedMessageCount !== 'number') return false\n if (typeof candidate.retainedMessageCount !== 'number') return false\n if (typeof candidate.updatedAt !== 'number') return false\n if (candidate.reasonCode !== undefined && typeof candidate.reasonCode !== 'string') return false\n if (\n candidate.reasonMessage !== undefined &&\n typeof candidate.reasonMessage !== 'string'\n )\n return false\n if (\n candidate.summaryNormalization !== undefined &&\n candidate.summaryNormalization !== 'plain_text' &&\n candidate.summaryNormalization !== 'wrapped_block' &&\n candidate.summaryNormalization !== 'extracted_block'\n )\n return false\n if (\n candidate.summaryInputTokens !== undefined &&\n typeof candidate.summaryInputTokens !== 'number'\n )\n return false\n if (\n candidate.summaryOutputTokensEstimate !== undefined &&\n typeof candidate.summaryOutputTokensEstimate !== 'number'\n )\n return false\n if (candidate.summaryChars !== undefined && typeof candidate.summaryChars !== 'number')\n return false\n if (\n candidate.summaryCallCount !== undefined &&\n typeof candidate.summaryCallCount !== 'number'\n )\n return false\n if (\n candidate.summaryChunkCount !== undefined &&\n typeof candidate.summaryChunkCount !== 'number'\n )\n return false\n if (\n candidate.prunedToolOutputCount !== undefined &&\n typeof candidate.prunedToolOutputCount !== 'number'\n )\n return false\n if (\n candidate.preservedToolOutputCount !== undefined &&\n typeof candidate.preservedToolOutputCount !== 'number'\n )\n return false\n return true\n}\n\nfunction isModelRef(value: unknown): value is ModelRef {\n const candidate = readModelRefCandidate(value)\n return typeof candidate?.provider === 'string' && typeof candidate.modelId === 'string'\n}\n\nfunction createCodedError(code: string, message: string): Error & { code: string } {\n const error = new Error(message) as Error & { code: string }\n error.code = code\n return error\n}\n\nfunction readErrorCode(error: unknown): string | undefined {\n const candidate = readErrorCodeCandidate(error)\n return typeof candidate?.code === 'string' ? candidate.code : undefined\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction readAutoCompactPluginStateDataCandidate(\n value: unknown,\n): AutoCompactPluginStateDataCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as AutoCompactPluginStateDataCandidate\n}\n\nfunction readAutoCompactPersistedResultCandidate(\n value: unknown,\n): AutoCompactPersistedResultCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as AutoCompactPersistedResultCandidate\n}\n\nfunction readModelRefCandidate(value: unknown): ModelRefCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as ModelRefCandidate\n}\n\nfunction readErrorCodeCandidate(value: unknown): ErrorCodeCandidate | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as ErrorCodeCandidate\n}\n"],"mappings":"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"} |
+3
-3
| { | ||
| "name": "@archships/dim-plugin-auto-compact", | ||
| "version": "0.0.19", | ||
| "version": "0.0.20", | ||
| "description": "Official auto compaction plugin for dim-agent-sdk.", | ||
@@ -27,4 +27,4 @@ "homepage": "https://dimcode.dev/", | ||
| "devDependencies": { | ||
| "@archships/dim-agent-sdk": "0.0.59", | ||
| "@archships/dim-plugin-api": "0.0.25" | ||
| "@archships/dim-agent-sdk": "0.0.67", | ||
| "@archships/dim-plugin-api": "0.0.28" | ||
| }, | ||
@@ -31,0 +31,0 @@ "scripts": { |
+7
-6
@@ -10,5 +10,5 @@ # @archships/dim-plugin-auto-compact | ||
| - optionally uses a dedicated `summaryModel` instead of the session model | ||
| - accepts an SDK-owned `CompactionExecutionRequest`, including `summaryInputMode: 'default' | 'exclude_tool_messages'` | ||
| - accepts an SDK-owned `CompactionExecutionRequest` | ||
| - normalizes summary output back into one canonical `<continuation_summary>...</continuation_summary>` block | ||
| - prunes older tool outputs inside the plugin summary input when configured | ||
| - includes assistant tool calls and tool result metadata in the summary input; with `compaction.prune: true`, older tool outputs are omitted with character counts while recent/error outputs render bounded previews | ||
| - keeps full `session.messages` intact for UI and restore | ||
@@ -55,13 +55,14 @@ - stores plugin-owned provenance in `pluginState['auto-compact']`, including semantic `lastResult` diagnostics for the controller call only | ||
| - SDK core owns planning, cursor movement, checkpoints, typed notifications, and threshold fallback orchestration | ||
| - threshold fallback order is fixed in SDK core: default summary, one `exclude_tool_messages` retry, then SDK-owned last-message fallback | ||
| - threshold fallback order is fixed in SDK core: one summary attempt, then SDK-owned last-message fallback | ||
| - the plugin only returns typed controller results; SDK-owned last-message fallback does not write into plugin state | ||
| - summary model calls now opt into the SDK usage ledger with semantic request kinds: threshold-triggered passes record `auto_compaction`, and `session.compact()` summary calls record `manual_compaction` | ||
| - `compaction.prune` defaults to `true`; set it to `false` only when the summary model should receive full tool text and structured content before chunking/truncation | ||
| - the default summary prompt asks the model for plain-text summary body only; runtime normalizes accepted output back into one canonical `<continuation_summary>...</continuation_summary>` block before replay, including wrapped blocks, merged multi-block outputs, and malformed-tag fragments that still yield a non-empty semantic body | ||
| - when normalization yields an empty body, runtime preserves the previous saved continuation summary when one already exists; only empty output without a previous summary fails with `invalid_summary_contract` | ||
| - `lastResult` is updated on every controller call with `compacted` / `skipped` / `failed`, plus summary normalization and summary-call diagnostics when available | ||
| - runtime notifications expose typed fallback metadata: `context.compacted.metadata.resolution` can be `summary`, `summary_without_tools`, or `last_message_fallback`; `context.compaction.failed.metadata.attemptStage` distinguishes `default_summary` from `summary_without_tools` | ||
| - runtime notifications expose typed fallback metadata: `context.compacted.metadata.resolution` can be `summary` or `last_message_fallback`; controller failures use `context.compaction.failed.metadata.attemptStage = 'default_summary'` | ||
| - persisted plugin state keeps only semantic provenance fields; summary-call counters and per-message id arrays stay out of `pluginState` | ||
| - `context.compacted` notifications now include compacted / retained message counts plus estimator-based before / after / saved token fields when budgeting is enabled | ||
| - `retainMessages` remains a preferred target, but the planner can keep compacting down to the newest real user boundary when needed | ||
| - the runtime keeps leading system messages first, appends runtime prompt/context next, then uses synthetic `user` messages for the auto-compact environment note and the compaction summary around the retained anchor query | ||
| - `retainMessages` remains a preferred target, but the planner adjusts to legal message boundaries and can use terminal compaction when the visible history ends with assistant/tool messages | ||
| - the runtime keeps leading system messages first, appends runtime prompt/context next, then uses synthetic `user` messages for the auto-compact environment note and the compaction summary before retained messages | ||
| - run `pnpm run demo:auto-compact` in the repo for the scripted walkthrough |
96564
6.38%683
7.05%67
1.52%