/** * Memory controller: the session's plug-and-play memory subsystem — the read-only OKF retrieval * provider, the bounded prompt-evidence surfacing pilot, cross-session recall effectiveness, and the * live {@link MemoryManager} (bundled file-store + transcript-recall providers plus any extension * contributions). * * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lazily-built OKF * provider, the latest retrieval/prompt-inclusion reports, the recreated-on-reload MemoryManager, the * recall {@link EffectivenessTracker}, and the extension-contributed pending providers. Everything * else it needs — settings, the current turn index, agent/workspace dirs, the session id, the * child-session flag, and the tool-registry refresh — is reached through narrow deps accessors rather * than the whole AgentSession. * * Context-transform boundary (deliberate): {@link runMemoryRetrieval} and * {@link maybeAppendMemoryEvidenceBlock} are invoked from the session's context transform as one-line * delegations. This controller deliberately imports no compaction/context-pipeline internals — it only * ever reads settings and builds the retrieval report + the bounded evidence block, so the transform * stays the single owner of the pass ordering. */ import type { AgentMessage } from "@caupulican/pi-agent-core"; import { type MemoryPromptInclusionReport, type MemoryRetrievalDiagnostics } from "./context/memory-diagnostics.ts"; import { type MemoryProvider as ContextMemoryProvider } from "./context/memory-provider-contract.ts"; import { type MemoryRetrievalReport } from "./context/memory-retrieval.ts"; import type { GoalState } from "./goals/goal-state.ts"; import { MemoryManager } from "./memory/memory-manager.ts"; import type { MemoryProvider } from "./memory/memory-provider.ts"; import { type StructuredReflectionApplyResult, type StructuredReflectionRollback, type StructuredReflectionWrite } from "./memory/providers/file-store.ts"; import { type SettingsManager } from "./settings-manager.ts"; export interface MemoryControllerDeps { /** Memory-retrieval + prompt-inclusion settings (default-on gates for retrieval and surfacing). */ getSettingsManager(): SettingsManager; /** Current turn index, stamped into a retrieval request's `createdAtTurn`. */ getTurnIndex(): number; /** Agent root — the durable OKF memory docs live under `/okf-memory`. */ getAgentDir(): string; /** Workspace root, passed to provider initialization. */ getCwd(): string; /** This session's id, passed to provider initialization. */ getSessionId(): string; /** Child sessions gate durable memory writes; passed to provider initialization. */ isChildSession(): boolean; /** Re-derive the tool registry after (re)init so the newly-surfaced memory tools take effect. */ refreshToolRegistry(): void; /** Active model context window, used to cap prompt-visible memory. */ getContextWindow(): number | undefined; /** Latest active goal state, used for short-term current-work memory. */ getGoalState(): GoalState | undefined; } /** Extension-contributed memory state staged across an atomic runtime reload. */ export interface MemoryControllerReloadSnapshot { pendingMemoryProviders: MemoryProvider[]; pendingContextMemoryProviders: ContextMemoryProvider[]; memoryOkfProvider: ContextMemoryProvider | undefined; fileStoreMemoryProvider: ContextMemoryProvider | undefined; } export declare class MemoryController { private _memoryOkfProvider; private _fileStoreMemoryProvider; private _localGraphProvider; private _localGraphResolved; private _latestMemoryRetrievalReport; private _latestMemoryPromptInclusionReport; /** Plug-and-play memory subsystem. Recreated on each (re)initialize so reload is safe. */ private _memoryManager; /** Active generation's single durable file/OKF writer, also used by parent-owned reflection. */ private _fileStoreWriter; /** R4: tracks whether injected recall is actually used, to adapt the recall gate. */ private readonly _effectivenessTracker; /** Memory providers registered by extensions via pi.registerMemoryProvider, applied on (re)init. */ private _pendingMemoryProviders; /** Context-memory providers registered by extensions via pi.registerContextMemoryProvider. */ private _pendingContextMemoryProviders; /** Serializes provider write hooks without delaying the foreground turn. */ private _lifecycleTail; private _shutdownPromise; private readonly deps; constructor(deps: MemoryControllerDeps); /** The live memory manager. Callers reach prefetch / tool-definitions / markers / shutdown through it. */ getMemoryManager(): MemoryManager; /** Queue one completed turn for provider-owned durable synchronization. Raw tool output is excluded by the caller. */ scheduleTurnSync(userText: string, assistantText: string): void; /** Wait for prior turn writes, then collect one bounded provider handoff for the whole compaction run. */ onPreCompress(): Promise; /** Flush write-side lifecycle hooks before releasing provider resources. Idempotent per session. */ shutdown(): Promise; /** * Fixed path for this slice's local Pi OKF memory documents, shared across sessions * under this agentDir (not session-scoped, unlike tool-artifacts/context-gc, since OKF * memory represents durable cross-session knowledge, not a per-session capture). Not * yet user-configurable -- see the memory-retrieval settings doc comment. */ private _memoryOkfDir; /** * Session-scoped, read-only local OKF memory provider. Lazily created ONLY when memory * retrieval is enabled (see `runMemoryRetrieval`) -- never force-created, so a session * with the setting off never touches `_memoryOkfDir()` at all (no directory access, no * creation; `createOkfMemoryProvider` itself never writes/mkdirs either way). */ private _getMemoryOkfProvider; private _getFileStoreMemoryProvider; private _getLocalGraphProvider; private _memoryBudget; private _shouldQueryFileStoreFallback; /** * Observe-only local memory retrieval (see context/memory-retrieval.ts and * context/okf-memory-provider.ts): default-on, but settings-gated. When disabled, * never constructs built-in context-memory providers (no directory access under * `_memoryOkfDir()` at all) and returns an empty report -- fully fail-closed. When enabled, * queries local, read-only providers with the latest user message text (empty if there is * none, e.g. a goal-continuation turn) under `DEFAULT_LOCAL_MEMORY_EGRESS_POLICY`. * Retrieved items are only ever stored in the report; nothing here touches `messages`, * the transcript, or the provider-visible prompt. Never throws into a live turn: any * failure (including a provider search error) degrades to an empty report. */ runMemoryRetrieval(messages: AgentMessage[]): Promise; /** Read-only inspection of the latest memory-retrieval report, for tests/debugging. */ getMemoryRetrievalReport(): MemoryRetrievalReport; private _candidateForContextItem; private _memoryCandidates; /** * Bounded prompt-surfacing for local memory evidence (see context/memory-tier-composer.ts): * default-on, but gated on TWO settings (`enabled` AND `includeInPrompt`) plus at least one * current-work, standing, or retrieved memory candidate -- the first * two are belt-and-suspenders on top of the fact that `runMemoryRetrieval` already * leaves `contextItems` empty whenever `enabled` is false, regardless of * `includeInPrompt`. Reuses the `report` this pass's `runMemoryRetrieval` call already * computed -- never re-queries the provider here. * * Appends exactly one ephemeral `custom`/"memory_evidence" message wrapped by * `wrapUntrustedText` (the same nonce-fenced boundary + always-on system-prompt rule * used for other untrusted content) to the END of `messages`. This is purely additive * (never mutates an existing message) and purely transient: `messages` here is the * array about to be sent to the provider, not `this.agent.state.messages` or anything * persisted via `sessionManager` -- so the injected message can never reach the * transcript, regardless of how many times this pass runs. * * Also records a `MemoryPromptInclusionReport` (context/memory-diagnostics.ts) at each * branch below, for context_audit's diagnostic surface only -- this is pure bookkeeping * alongside the existing branches, not a new branch/condition: the messages returned * are unchanged by this recording. */ maybeAppendMemoryEvidenceBlock(messages: AgentMessage[], report: MemoryRetrievalReport): AgentMessage[]; /** Read-only inspection of the latest memory-prompt-inclusion decision, for tests/debugging and context_audit. */ getMemoryPromptInclusionReport(): MemoryPromptInclusionReport; /** * Combines the already-stored, no-arg latest reports (never re-queries the provider or * touches the OKF directory) into the safe, allow-list-projected shape context_audit * exposes. See context/memory-diagnostics.ts for why this projection is allow-list * based rather than a spread-then-delete of the raw report. */ getMemoryAuditDiagnostics(): { retrieval: MemoryRetrievalDiagnostics; promptInclusion: MemoryPromptInclusionReport; }; /** * Zero-I/O gate for cross-session recall (R3): skip trivial turns (short acks, slash commands) so * recall only runs when it could plausibly help. The provider's similarity cutoff is the real * filter — this just avoids the index query on turns that obviously don't warrant it. */ shouldAttemptRecall(text: string): boolean; /** Legacy recall prefetch with the same hard-off and explicit external-egress policy as context retrieval. */ prefetchRecall(query: string): Promise; /** Fresh bounded OKF snapshot for reflection's confront-before-write pass. */ getFreshOkfMemoryForReflection(): string; /** Bounded, read-only memory view for an explicitly authorized delegated worker. */ readMemoryForLane(query: string): Promise; /** Parent reflection's only structured-memory mutation port. Workers never receive this capability. */ applyStructuredReflectionWrite(write: StructuredReflectionWrite, signal?: AbortSignal): Promise; /** Parent-owned inverse for an audited structured reflection write. */ rollbackStructuredReflectionWrite(rollback: StructuredReflectionRollback, signal?: AbortSignal): Promise; /** R4: score whether the agent actually used an injected recall page, so the recall gate can adapt. */ recordRecallOutcome(recallText: string, queryText: string, responseText: string): void; /** * (Re)build the memory subsystem: a fresh MemoryManager (reload-safe), register the bundled * file-store + any extension-contributed providers, initialize, then surface the memory tools and * the frozen system-prompt block. Best-effort: never throws into the session lifecycle. */ initialize(): Promise; /** Register a memory provider contributed by an extension; applied on the next memory (re)init. */ registerMemoryProvider(provider: MemoryProvider): void; /** Register a retrieval-style context memory provider contributed by an extension. */ registerContextMemoryProvider(provider: ContextMemoryProvider): void; createReloadSnapshot(): MemoryControllerReloadSnapshot; restoreReloadSnapshot(snapshot: MemoryControllerReloadSnapshot): void; /** Reload starts memory providers fresh; loaded extensions re-register before the next `initialize()`. */ clearPendingProviders(): void; } //# sourceMappingURL=memory-controller.d.ts.map