import { z } from "zod";
import * as smoltalk from "smoltalk";
import type { SmolConfig } from "smoltalk";
import { type MemoryConfig, type MemoryStore as MemoryStoreType } from "./types.js";
import { MemoryGraph } from "./graph.js";
import type { ExtractionResult } from "./extraction.js";
import { type LogLevel } from "../../logger.js";
import type { StatelogClient } from "../../statelogClient.js";
import type { LLMClient } from "../llmClient.js";
/**
 * A pluggable reference to the active memoryId.
 *
 * Per resolved decision #1, in production this is backed by
 * `stateStack.other.memoryId` so it survives interrupt/resume. For tests
 * an in-memory ref is used.
 */
export type MemoryIdRef = {
    get(): string;
    set(id: string): void;
};
export type MemoryManagerOptions = {
    store: MemoryStoreType;
    config: MemoryConfig;
    /** The runtime-wide LLMClient (`SmoltalkClient`, `DeterministicClient`,
     *  or whatever the user registered via `setLLMClient`). MemoryManager
     *  uses it directly so registering a custom client takes effect for
     *  memory's text + embed calls too. */
    llmClient: LLMClient;
    /** Default `SmolConfig` overrides (api keys, provider, etc.). Merged
     *  into every text and embed call. */
    smoltalkDefaults?: Partial<SmolConfig>;
    source?: string;
    memoryIdRef?: MemoryIdRef;
    /** Statelog client used to emit `llmCall`/`embedding` spans and
     *  `promptCompletion`/`embedCompletion` events for memory's
     *  internal LLM/embed calls. Optional so tests can construct
     *  managers without one; production wires the per-execCtx
     *  client through `context.ts`. When absent, every statelog hook
     *  is a no-op. */
    statelogClient?: StatelogClient;
    /** Threshold for the manager's internal logger. The manager
     *  creates one logger per instance via `createLogger(logLevel)`;
     *  every line is `[memory]`-prefixed so users can grep/filter. */
    logLevel?: LogLevel;
};
/**
 * Plan describing how the caller should reshape its message thread
 * after compaction. The MemoryManager returns indices, not message
 * instances, so the caller can rebuild the thread from its own
 * smoltalk.Message instances and preserve identity (===). That keeps
 * any caller-side maps keyed on message identity (e.g. trace
 * correlations) valid across compaction.
 */
export type CompactionPlan = {
    /** Indices in the original messages array to keep at the head, in order.
     *  Excludes any prior summary message — that gets replaced, not stacked. */
    systemPrefixIndices: number[];
    /** Indices in the original messages array to keep verbatim at the tail,
     *  in order. These are the most recent messages preserved across the split. */
    tailIndices: number[];
    /** Full content for the new summary system message (already includes the
     *  SUMMARY_MESSAGE_PREFIX so callers can pass it straight to systemMessage). */
    summaryMessageContent: string;
};
export declare class MemoryManager {
    private store;
    private config;
    private llmClient;
    private smoltalkDefaults;
    private source;
    private memoryIdRef;
    /** Optional — every call site uses `?.` so the absence of a
     *  statelog client (e.g. in unit tests) is a clean no-op. */
    private statelogClient?;
    /** Built once in the constructor from `options.logLevel`. Each line
     *  emitted by the manager is prefixed `[memory]` so users can
     *  filter on the prefix from stderr. */
    private logger;
    private cache;
    constructor(options: MemoryManagerOptions);
    /**
     * Run a single-prompt text completion through the registered
     * LLMClient. We always go through `llmClient.text` (not directly
     * to smoltalk) so a custom client registered via `setLLMClient`
     * — including the `DeterministicClient` used in tests — controls
     * memory's text calls too.
     *
     * Wrapped in an `llmCall` span + `promptCompletion` event so the
     * call shows up in the trace viewer alongside agency-driven LLM
     * calls. Errors emit a statelog `error` event before being
     * re-thrown so a failed memory call is visible even though the
     * post-turn hook in `prompt.ts` swallows it to keep the agent
     * running.
     */
    private _text;
    /** Same routing as _text(), but for embeddings. Returns a single
     *  vector (the LLMClient.embed protocol accepts string|string[]; we
     *  always pass one string here so the response is one vector).
     *
     *  Wrapped in an `embedding` span + `embedCompletion` event. The
     *  span type is distinct from `llmCall` so the viewer can render
     *  cost/latency for embeddings separately. */
    private _embed;
    getMemoryId(): string;
    setMemoryId(id: string): void;
    isInitialized(): boolean;
    /**
     * Returns the graph for the active memoryId. Throws if the cache
     * has not been loaded yet (call init() or any async operation first).
     */
    getGraph(): MemoryGraph;
    init(): Promise<void>;
    private getEntry;
    private model;
    /**
     * Build the extraction prompt for a single user message. Stdlib
     * agency code calls this, hands the result to `llm()` with a typed
     * `ExtractionResult`, and then calls `applyExtractionFromLLM` —
     * keeping the LLM call itself in the agency runPrompt pipeline so
     * tracing, cost/token accounting, and the structured-output Zod
     * schema all flow through the standard path.
     */
    buildExtractionPromptFor(content: string): Promise<string>;
    /**
     * Apply a typed extraction result to the active graph. Used by the
     * agency-side `remember` after it gets a structured result from
     * `llm(...)`.
     *
     * Wrapped in a `memoryRemember` umbrella span so the agency-side
     * call shape (`buildExtractionPromptFor` → `llm` → `applyExtractionFromLLM`)
     * still nests its embedding work under one parent in the viewer.
     */
    applyExtractionFromLLM(result: ExtractionResult): Promise<void>;
    /**
     * Convenience wrapper used by tests that want the whole extraction
     * round-trip in one call. The agency runtime path goes through
     * `buildExtractionPromptFor` + `applyExtractionFromLLM` instead.
     *
     * Opens its own `memoryRemember` span — the nested
     * `applyExtractionFromLLM` opens a child of the same type, which
     * is acceptable: the viewer will see two adjacent rows for the
     * same logical operation. We could short-circuit the inner call,
     * but the duplication is harmless and avoids coupling the two
     * methods through a flag.
     */
    remember(content: string): Promise<void>;
    private tier1And2;
    recall(query: string, options?: {
        model?: string;
    }): Promise<string>;
    recallForInjection(query: string): Promise<string>;
    /**
     * Slice the recall result down to `DEFAULT_RECALL_K`, resolve each
     * id to its entity (dropping ids that no longer exist), and render
     * the final user-visible string. Shared tail for `recall` (Tier
     * 1+2+3) and `recallForInjection` (Tier 1+2 only).
     */
    private formatTopK;
    /**
     * Build the forget prompt for a query against the active graph.
     * Same split-pattern as extraction (see `buildExtractionPromptFor`):
     * stdlib agency code calls this, hands it to `llm()` with a typed
     * `ForgetResult`, then calls `applyForgetFromLLM`.
     */
    buildForgetPromptFor(query: string): Promise<string>;
    /**
     * Apply a typed forget result to the active graph. Substring match,
     * case-insensitive (resolved decision #7).
     *
     * Wrapped in a `memoryForget` umbrella span so the agency-side call
     * shape (`buildForgetPromptFor` → `llm` → `applyForgetFromLLM`)
     * groups its writes under one parent in the viewer.
     */
    applyForgetFromLLM(parsed: ForgetResult): Promise<void>;
    /**
     * Convenience wrapper used by tests that want the whole forget
     * round-trip in one call. The agency runtime path goes through
     * `buildForgetPromptFor` + `applyForgetFromLLM` instead.
     */
    forget(query: string): Promise<void>;
    onTurn(messages: smoltalk.Message[]): Promise<void>;
    compactIfNeeded(messages: smoltalk.Message[]): Promise<CompactionPlan | null>;
    /** Persist all cached memoryIds to disk. */
    save(): Promise<void>;
    private autoExtract;
    private generateEmbeddings;
    /**
     * Build the per-line "id: name (type) — facts" candidate index
     * fed to the Tier-3 filter prompt. Including the entity's current
     * observations lets the LLM judge relevance without us having to
     * dump the full graph; using stable ids (not names) makes the
     * response unambiguous and lets us reject hallucinated ids.
     */
    private buildCandidateIndex;
    private embeddingRecallEntityIds;
    /**
     * Tier 3: ask the LLM to pick the relevant entities from a fixed
     * candidate list (the union of Tier 1 + Tier 2 hits, or the whole
     * graph on the small-graph fallback). Returns ids in the order the
     * LLM emitted, filtered to the offered set so a hallucinated id is
     * silently dropped instead of crashing the recall.
     */
    private llmFilterCandidates;
}
declare const ForgetResultSchema: z.ZodObject<{
    observations: z.ZodArray<z.ZodObject<{
        entityName: z.ZodString;
        observationContent: z.ZodString;
    }, z.core.$strip>>;
    relations: z.ZodArray<z.ZodObject<{
        fromName: z.ZodString;
        toName: z.ZodString;
        type: z.ZodString;
    }, z.core.$strip>>;
}, z.core.$strip>;
export type ForgetResult = z.infer<typeof ForgetResultSchema>;
export {};
