/** * ContextManager: slot-based persistent context + ephemeral per-call injection. * * Manages the content an agent sees through two mechanisms: * - **Slots**: Named content blocks at the start of the message array. * Persistent, updated immediately via setSlot(). Ordered by stability * (most stable first) for prefix cache optimization. * - **Ephemeral context**: Per-call content injected via transformContext. * Never stored in agent.state.messages. Rebuilt every LLM call. * * Message array layout: * [SLOT REGION (0..N-1)] [CONVERSATION HISTORY] [EPHEMERAL (in transformContext)] [PROMPT] * * Reference: context-manager.md */ import type { ContextManagerConfig } from './types.js'; /** * Minimal interface for pi-agent-core's Agent.state.messages entries. * The actual type is Message from @earendil-works/pi-ai, but we define * only what we need to avoid a hard dependency. */ export interface AgentMessage { role: 'user' | 'assistant' | 'toolResult'; content: string | Array<{ type: string; text?: string; [key: string]: unknown; }>; toolCallId?: string; toolName?: string; details?: unknown; isError?: boolean; /** Epoch milliseconds when this message was created. Stamped by Cortex at turn boundaries. */ timestamp: number; } /** * Minimal interface for pi-agent-core's Agent to access state.messages. * We only need to read and write the messages array. */ export interface AgentStateAccessor { state: { messages: AgentMessage[]; systemPrompt?: string; model?: unknown; thinkingLevel?: string; tools?: unknown[]; error?: string; errorMessage?: string; }; } /** * The context object passed to transformContext hooks. * Mirrors pi-agent-core's AgentContext shape. */ export interface AgentContext { systemPrompt: string; model: unknown; messages: AgentMessage[]; tools: unknown[]; thinkingLevel: string; } export declare class ContextManager { private readonly agent; private readonly slotNames; private readonly slotIndexMap; private ephemeralContent; /** * Create a ContextManager. * * @param agent - The pi-agent-core Agent instance (or any object with state.messages) * @param config - Configuration with ordered slot names */ constructor(agent: AgentStateAccessor, config: ContextManagerConfig); /** * The number of context slots. */ get slotCount(): number; /** * The ordered slot names (frozen copy). */ get slots(): readonly string[]; /** * Update a slot's content. Immediately updates the corresponding * message in agent.state.messages at the slot's position. * * @param name - The slot name (must match a name from the config) * @param content - The raw string content (consumer handles formatting) * @throws Error if the slot name is not recognized */ setSlot(name: string, content: string): void; /** * Read current slot content. * * @param name - The slot name * @returns The slot's content string, or null if the slot has not been set * @throws Error if the slot name is not recognized */ getSlot(name: string): string | null; /** * Set ephemeral content for the next LLM call(s). * Injected at the end of the message array inside the transformContext hook. * Never written to agent.state.messages. * Pass null to clear. * * @param content - The ephemeral content string, or null to clear */ setEphemeral(content: string | null): void; /** * Get the current ephemeral content. * * @returns The ephemeral content, or null if not set */ getEphemeral(): string | null; /** * Returns a transformContext hook function that appends ephemeral content. * * The hook is composable: the consumer can chain it with other transformContext * logic (compaction, skill buffer, etc.). * * The ephemeral content is appended as a user-role message at the end of * the messages array, after all conversation history but before the prompt. * This placement ensures it does not invalidate the prefix cache for * content above it. * * @returns A function suitable for use as a transformContext hook */ getTransformContextHook(): (context: AgentContext) => AgentContext; /** * Initialize slot positions with empty user-role messages. * Ensures the messages array has the correct length from construction. */ private initializeSlots; } //# sourceMappingURL=context-manager.d.ts.map