/** * Layer 1: Microcompaction (tool result trimming). * * Progressively reduces the footprint of old tool results in conversation * history. Operates in-memory only via transformContext; never modifies * the persisted conversation history (agent.state.messages). * * Two sub-mechanisms: * 1. Insertion-time cap: Truncate large tool results at insertion time. * 2. Cache-aware token-offset trimming: When the prompt cache has gone * cold and context utilization is above the trim floor, walk history * from newest to oldest accumulating token offsets. Tool results * within the hot zone stay full; beyond it, bookend size shrinks * linearly across the degradation span; beyond the span, results * become placeholder or clear based on tool category. * * When a persistResult callback is configured, full content is persisted * to disk before any destructive trim (bookend, placeholder, clear) for * non-reproducible and computational tools, and the in-context replacement * includes the disk path so the agent can Read the content back. * * References: * - compaction-strategy.md (Layer 1: Tool Result Trimming) * - observational-memory-architecture.md (cache-aware L1) * - tool-result-persistence.md (proactive persistence at execution) */ import type { AgentMessage } from '../context-manager.js'; import type { MicrocompactionConfig, ToolCategory } from '../types.js'; export declare const MICROCOMPACTION_DEFAULTS: MicrocompactionConfig; /** * Trim instruction for a single tool result message. * Describes how to transform the message content for the LLM context. */ export type TrimAction = { kind: 'full'; } | { kind: 'bookend'; headChars: number; tailChars: number; originalTokens: number; } | { kind: 'placeholder'; toolName: string; preview: string; } | { kind: 'clear'; }; /** * Cached trim state. Keyed on history length and a coarse utilization band * so the engine can replay identical trim decisions across consecutive * transformContext calls when the underlying conversation hasn't changed * meaningfully. */ export interface TrimState { /** History length at the time the state was computed. */ historyLength: number; /** Coarse utilization band: floor(usageRatio * 10). */ utilizationBand: number; /** Map from conversation history index to trim action. */ actions: Map; } /** * Cap a tool result at insertion time. If the result exceeds maxResultTokens, * truncate to head + tail bookend format using bookendMaxChars per side. * * This runs at insertion, NOT in transformContext. The truncated result is * stored in conversation history. */ export declare function capToolResult(content: string, config: Pick): string; /** * Extract the text content from a message's content field. * Handles both string content and content arrays. * For content arrays, extracts text from 'text' parts and also from * 'tool_result' parts that have a 'text' field (which is where * pi-agent-core stores tool output). */ export declare function extractTextContent(message: AgentMessage): string; /** * Check if a message is a tool result. * Pi-agent-core stores tool results as messages with content arrays * containing tool_result type parts. */ export declare function isToolResultMessage(message: AgentMessage): boolean; /** * Check if a message contains a tool use (tool call from the assistant). */ export declare function isToolUseMessage(message: AgentMessage): boolean; /** * Extract the tool name from a tool result or tool use message. * Returns null if the message is not a tool-related message. */ export declare function extractToolName(message: AgentMessage): string | null; /** * Get the effective tool category for a tool name. */ export declare function getToolCategory(toolName: string, customCategories?: Record): ToolCategory | undefined; /** * Compute the effective hot zone size in tokens. * `max(hotZoneMinTokens, contextWindow * hotZoneRatio)`. */ export declare function computeHotZone(contextWindow: number, config: Pick): number; /** * Resolve the effective extended retention multiplier. When the config value * is undefined, use 1.0 if a persister is configured (content recoverable * from disk) or 1.5 if not (content is truly lost on trim). */ export declare function resolveExtendedRetentionMultiplier(config: MicrocompactionConfig): number; /** * Determine the trim action for a tool result based on its token offset * from the most recent message. * * @param message - The tool result message * @param tokenOffset - Cumulative tokens between this message and the end of history * @param hotZone - Hot zone size in tokens (preserved fully) * @param degradationSpan - Degradation span in tokens (bookend size shrinks across this span) * @param config - Microcompaction config * @param extendedMultiplier - Resolved extended retention multiplier for non-reproducible tools */ export declare function computeAction(message: AgentMessage, tokenOffset: number, hotZone: number, degradationSpan: number, config: MicrocompactionConfig, extendedMultiplier: number): TrimAction; /** * Compute the full trim state by walking history from newest to oldest, * accumulating token offsets. */ export declare function computeTrimState(history: AgentMessage[], contextWindow: number, usageRatio: number, config: MicrocompactionConfig): TrimState; /** * Apply a bookend trim to content. */ export declare function applyBookend(content: string, headChars: number, tailChars: number, originalTokens: number): string; /** * Apply a bookend trim with a persisted file reference. The agent can * Read the path to recover the trimmed middle portion. */ export declare function applyBookendWithPersistence(content: string, headChars: number, tailChars: number, originalTokens: number, toolName: string, path: string): string; /** * Apply a trim action to a message, returning a new message. * * Preserves the content array structure for tool_result messages so that * tool_use_id linkage is maintained. The Anthropic API requires every * tool_use block to have a matching tool_result with the same tool_use_id; * replacing the content with a plain string would break this contract. */ export declare function applyTrimAction(message: AgentMessage, action: TrimAction): AgentMessage; /** * Stateful engine for microcompaction. Caches trim state across consecutive * calls with the same history length and utilization band so the same trim * decisions are replayed when the conversation hasn't changed. */ export declare class MicrocompactionEngine { private readonly config; private cachedState; constructor(config?: Partial); /** * Whether a persist callback is configured. */ get hasPersistCallback(): boolean; /** * Get the current config (for testing/inspection). */ getConfig(): MicrocompactionConfig; /** * Cap a tool result at insertion time. */ capAtInsertion(content: string): string; /** * Apply microcompaction to conversation history messages. * Called inside transformContext. Returns a new array; never modifies the input. * * Cache-aware gating: * - When `cacheCold` is false (cache warm), L1 is dormant and history * is returned untouched. This preserves cache hits during active use. * - When `cacheCold` is true, L1 may run if utilization is at or above * `trimFloorRatio` (default 25%). * * Token-offset trimming: * Walks history from newest to oldest. Tool results within the hot zone * stay full. Beyond the hot zone, bookend size shrinks linearly across * the degradation span. Beyond the span, results become placeholder or * clear based on tool category. * * Persistence: * When a persistResult callback is configured, full content is saved to * disk before any destructive action (bookend, placeholder, clear) for * non-reproducible and computational tools. The in-context replacement * includes the disk path so the agent can Read the content back. * * @param history - Conversation history messages (post-slot region) * @param contextWindow - Total context window size in tokens * @param currentTokens - Current estimated token count * @param options.cacheCold - Whether the prompt cache has expired (or is unused) * @returns Potentially trimmed conversation history */ apply(history: AgentMessage[], contextWindow: number, currentTokens: number, options?: { cacheCold: boolean; }): Promise; /** * If a persistResult callback is configured and the action is destructive * (bookend, placeholder, or clear), persist each non-reproducible or * computational tool_result part's content to disk individually and * replace each part's text with a path-referencing representation. * * Multi-part messages (from parallel tool calls) get per-part treatment so * each part's disk path maps back to its own content. * * Parts that don't qualify for persistence (rereadable, ephemeral, no * callback, or non-tool-result parts) still get the standard trim action * applied to their own text. */ private maybePersistBeforeTrim; /** * Reset the cached trim state. Called after Layer 2 compaction * replaces conversation history. */ resetCache(): void; /** * Get the cached state (for testing/inspection). */ getCachedState(): TrimState | null; } //# sourceMappingURL=microcompaction.d.ts.map