import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type * as MnemopiNs from "@oh-my-pi/pi-mnemopi"; import type { MemoryFacadeStats, Mnemopi, RecallResult, RememberFacadeOptions, RememberInput } from "@oh-my-pi/pi-mnemopi"; import type * as MnemopiCoreNs from "@oh-my-pi/pi-mnemopi/core"; import type { MemoryPromptPreparation } from "../memory-backend/types.js"; import type { AgentSession } from "../session/agent-session.js"; import type { AgentSessionHandle } from "../session/agent-session-handle.js"; import { type MnemopiBackendConfig } from "./config.js"; /** * Lazily load `@oh-my-pi/pi-mnemopi` (memoized) and route fastembed loads * through the machine-shared embedding server. The override is installed once * — before any consumer gets the chance to call `embed()` — so * `onnxruntime-node`'s NAPI constructor + finalizer never run inside the * agent's address space (issue #3031). Test seams that swap the initializer * with `setLocalModelInitializerForTests` still win because both go through * the same module-level slot. */ export declare function loadMnemopi(): Promise; /** Lazily load `@oh-my-pi/pi-mnemopi/core` (memoized). */ export declare function loadMnemopiCore(): Promise; /** Sync access for code below an async boundary that already awaited {@link loadMnemopi}. */ export declare function requireMnemopi(): typeof MnemopiNs; /** Sync access for code below an async boundary that already awaited {@link loadMnemopiCore}. */ export declare function requireMnemopiCore(): typeof MnemopiCoreNs; interface MnemopiScopedMemory { bank: string; memory: Mnemopi; } /** What `Mnemopi.remember` stores. */ export type MnemopiRememberInput = string | RememberInput; /** How `Mnemopi.remember` stores it. */ export type MnemopiRememberOptions = RememberFacadeOptions; /** A scoped bank by name; the state owning the bank resolves the name to its live store. */ export interface MnemopiBankTarget { readonly bank: string; } /** `Mnemopi.getStats()` of one scoped bank. */ export interface MnemopiBankStats { bank: string; stats: MemoryFacadeStats; } /** Options of {@link MnemopiSessionState.consolidate}. */ export interface MnemopiConsolidateOptions { full?: boolean; extract?: boolean; sleep?: boolean; retain?: boolean; } export type MnemopiMemoryEditOperation = "update" | "forget" | "invalidate"; export interface MnemopiMemoryEditOptions { content?: string; importance?: number; replacementId?: string; } export interface MnemopiMemoryEditResult { status: "updated" | "deleted" | "invalidated" | "not_found" | "not_editable"; bank?: string; store?: MnemopiMemoryStore; } /** Which mnemopi table a resolved memory id lives in. `fact` rows are * read-only projections of fact extraction (issue #4725): resolvable for * reads, never editable. */ export type MnemopiMemoryStore = "working" | "episodic" | "fact"; /** * Full-row lookup result produced by {@link MnemopiSessionState.getScopedMemory}. * Mirrors the shape stored in mnemopi's working/episodic tables, tagged with * the scoped bank that actually held the row so callers can render it with * meaningful context. */ export interface MnemopiScopedMemoryHit { bank: string; store: MnemopiMemoryStore; /** Retired by `memory_edit invalidate` (superseded, or past its `valid_until`): recall skips it. */ invalidated: boolean; row: { id: string; content: string; source: string | null; timestamp: string | null; importance: number | null; veracity: string | null; created_at: string | null; session_id: string | null; memory_type: string | null; metadata: unknown; }; } /** Mnemopi state tagged on `session`; any session handle may be scanned (only local sessions carry the tag). */ export declare function getMnemopiSessionState(session: AgentSessionHandle | undefined): MnemopiSessionState | undefined; export declare function setMnemopiSessionState(session: AgentSession, state: MnemopiSessionState | undefined): MnemopiSessionState | undefined; export interface MnemopiSessionStateOptions { sessionId: string; config: MnemopiBackendConfig; session: AgentSession; aliasOf?: MnemopiSessionStateApi; lastRetainedTurn?: number; hasRecalledForFirstTurn?: boolean; } /** * What subagent aliases and the backend's `primary` reads use on a parent state: its * identity, config, and every scoped-bank operation. A subagent worker holds a remote * implementation whose banks are main's live stores. */ export interface MnemopiSessionStateApi { readonly sessionId: string; readonly config: MnemopiBackendConfig; readonly hasRecalledForFirstTurn: boolean; readonly lastRecallSnippet?: string; readonly aliasOf?: MnemopiSessionStateApi; getScopedRetainTarget(): MnemopiBankTarget; getScopedRecallTargets(): readonly MnemopiBankTarget[]; getGlobalRetainTarget(): MnemopiBankTarget; getScopedMemory(id: string): MnemopiScopedMemoryHit | null; editScopedMemory(op: MnemopiMemoryEditOperation, id: string, options?: MnemopiMemoryEditOptions): MnemopiMemoryEditResult; collectScopedRecallResults(query: string): Promise; recallResultsScoped(query: string): Promise; formatScopedRecallContext(results: readonly RecallResult[], format?: "bullet" | "json"): string | undefined; rememberScoped(memory: MnemopiRememberInput, options?: MnemopiRememberOptions, target?: MnemopiBankTarget): string; getScopedStats(): MnemopiBankStats[]; consolidate(options?: MnemopiConsolidateOptions): Promise; } export declare class MnemopiSessionState implements MnemopiSessionStateApi { #private; sessionId: string; readonly config: MnemopiBackendConfig; readonly session: AgentSession; readonly aliasOf?: MnemopiSessionStateApi; lastRetainedTurn: number; hasRecalledForFirstTurn: boolean; lastRecallSnippet?: string; unsubscribe?: () => void; constructor(options: MnemopiSessionStateOptions); /** Retain-bank store; only on the thread that owns the banks. */ get memory(): Mnemopi; /** Shared-bank store under `per-project-tagged` scoping; only on the thread that owns the banks. */ get globalMemory(): Mnemopi | undefined; setSessionId(sessionId: string): void; resetConversationTracking(): void; getScopedRecallTargets(): readonly MnemopiScopedMemory[]; getScopedRetainTarget(): MnemopiScopedMemory; /** Stats of the retain and recall banks, deduplicated by bank. */ getScopedStats(): MnemopiBankStats[]; /** * Bank for `scope: "global"` writes: the retain bank under `global` scoping, the shared bank * under `per-project-tagged`. Throws under `per-project`, which has no bank every project recalls. */ getGlobalRetainTarget(): MnemopiBankTarget; /** * Read counterpart to {@link editScopedMemory}: fetch a memory row by id * from any bank this session recalls from (retain, recall, global). First * hit wins in the same order {@link editScopedMemory} would touch, so the * shape matches what an `update`/`forget`/`invalidate` on the same id will * see. Returns `null` when the id is not found anywhere in scope. * * Backs the coding-agent `memory://` URL so agents can inspect the * FULL content of a recall preview (recall clips content — see * {@link RecallResult.truncated}) before issuing a wholesale * `memory_edit update` that would otherwise overwrite unseen bytes * (issue #4443). */ getScopedMemory(id: string): MnemopiScopedMemoryHit | null; editScopedMemory(op: MnemopiMemoryEditOperation, id: string, options?: MnemopiMemoryEditOptions): MnemopiMemoryEditResult; formatScopedRecallWithIds(results: readonly RecallResult[]): string; collectScopedRecallResults(query: string): Promise; recallResultsScoped(query: string): Promise; formatScopedRecallContext(results: readonly RecallResult[], format?: "bullet" | "json"): string | undefined; formatContextScoped(results: readonly RecallResult[], format?: "bullet" | "json"): string; /** Background write: a failed write is logged and returns `undefined` instead of throwing. */ rememberInScope(memory: MnemopiRememberInput, options?: MnemopiRememberOptions): string | undefined; /** * Explicit write: throws the storage error, so the caller can report why nothing was stored. * `target` defaults to the retain bank; pass {@link getGlobalRetainTarget} for a global write. */ rememberScoped(memory: MnemopiRememberInput, options?: MnemopiRememberOptions, target?: MnemopiBankTarget): string; recallForContext(query: string, signal?: AbortSignal): Promise; /** * Cuts a recall block to what the prompt carries next to the memory instructions: the * canonical prompt budget (`mnemopi.injectionTokenLimit`), keeping a prefix of the block * that ends in "…" when it cut one. */ budgetRecallBlock(block: string): string; /** * A fresh recall is cut by `budget` to the prefix the prompt carries next to the memory * instructions; a reused one is resent exactly as delivered. Memories the delivered block * shows, even in part, are tracked for change reports. */ beforeAgentStartPrompt(promptText: string, signal?: AbortSignal, budget?: (block: string) => string): Promise; recallForCompaction(messages: AgentMessage[], signal?: AbortSignal): Promise; maybeRetainOnAgentEnd(_messages: AgentMessage[]): Promise; forceRetainCurrentSession(options?: { extract?: boolean; }): Promise; retainMessages(messages: Array<{ role: string; content: string; }>, sourceId: string, options?: { extract?: boolean; retainedThroughUserTurn?: number; }): Promise; attachSessionListeners(): void; maybeRecallOnAgentStart(): Promise; /** * Promote age-eligible working-memory rows to episodic once at session start, * before any write can trigger the working-memory TTL trim. * * `remember` runs `trimWorkingMemory` on every write, which deletes * unconsolidated rows older than `workingMemoryTtlHours` (24h). Consolidation * (`sleep`) is age-gated to rows >= 12h old, but otherwise only ran via the * explicit `/memory enqueue` path (`dispose` passes `sleep:false`, #4843), so * `retain`/`learn`/transcript rows that were never manually enqueued were * silently deleted after a >24h session gap (#10770). Running the age-gated * sleep here stamps `consolidated_at` on those rows before the session's first * write, so the `consolidated_at IS NULL` trim filter no longer removes them. * * Bank-global because each bank opens with `sessionId = `, so a single * session-scoped `sleep` covers rows written by every prior session. Cheap * when nothing is old enough — `sleep` short-circuits to a no-op with no * eligible rows — and failures are logged, never thrown, so a consolidation * error cannot make the backend inert. */ promoteEligibleWorkingMemory(): void; /** * Capture the current transcript by default, drain in-flight fact extraction, * and optionally run beam consolidation on every owned bank. * The explicit `/memory enqueue` path * requests retention plus full cross-session consolidation; disposal composes * the lighter configured-retain-and-flush path with closing the DB handles. * * Aliased subagent states share `scoped` (and therefore the actual SQLite * banks) with their parent. `consolidate()` deliberately does NOT * short-circuit on `aliasOf`: `forceRetainCurrentSession` already guards * itself, and an explicit `/memory enqueue` invoked from within a subagent * still needs to flush extractions and sleep the parent's shared banks — * otherwise enqueue would report success while leaving the subagent's * retained memories unconsolidated until a later full consolidation request * (PR #2327 review). * * @param options.full - When true, run `sleepAllSessions` on every owned bank * (the full cross-session consolidation used by `/memory enqueue`). When * false (the default), run only `sleep` on the current session when bank * sleep is enabled. * @param options.sleep - When false, skips the bank sleep step entirely. * Used on the interactive shutdown path so `dispose` does not block on * synchronous consolidation of old working rows from previous sessions. * @param options.extract - When false, any retained transcript is stored but no * LLM fact extraction is scheduled. Used on the interactive shutdown path so * `dispose` does not block on a fresh LLM round-trip. * @param options.retain - When false, skip transcript retention. * Explicit consolidation retains by default; disposal passes the configured * automatic-retention setting. */ consolidate(options?: MnemopiConsolidateOptions): Promise; dispose(options?: { consolidate?: boolean; timeoutMs?: number; retain?: boolean; }): Promise; } export declare function getMnemopiScopedDbPaths(config: MnemopiBackendConfig): readonly string[]; export declare function getMnemopiScopedBanks(config: MnemopiBackendConfig): readonly string[]; /** Identifies the banks and databases a first-turn recall reads, so a persisted recall is only reused for the same ones. */ export declare function getMnemopiRecallScope(config: MnemopiBackendConfig): string; export {};