/**
 * resolveTurnNumber — which turn of this conversation is about to happen?
 *
 * A memory entry's id is turn-stamped (`msg-{turn}-{index}`, `snap-{turn}`,
 * `beat-{turn}-{index}`), so the turn number is not a label: it is the KEY
 * two consecutive turns must not share. Get it wrong and every turn
 * overwrites the previous one — a conversation memory that silently holds
 * exactly one exchange no matter how large the window says it is. That is
 * the bug this function exists to make impossible (9.6.0).
 *
 * **Why the host's own counter is not enough.** A host that runs one Agent
 * instance for a whole conversation can count turns in memory. The shape
 * seen in a production field deployment cannot: it builds a FRESH agent per
 * turn (new process, new instance, same `conversationId`, same store), so
 * anything counted in a variable is back to 1 on every request. The only
 * thing that remembers how far the conversation has got is the STORE.
 *
 * **The rule** — `max(hostTurn, maxStoredTurn + 1)`:
 *   - Hosts that track the turn honestly keep their numbering (`hostTurn: 5`
 *     → turn 5; gaps preserved — an ordinal, not a count).
 *   - A host whose counter is stale still gets a fresh, ordered turn: the
 *     second turn of a conversation whose store already holds turn 1 is
 *     turn 2, never turn 1 again.
 *   - The two sources compose: whichever knows more wins, and neither can
 *     drag the conversation backwards.
 *
 * The rule is the one `writeSnapshot` has applied to causal snapshots since
 * 9.1 — this is that carve-out generalised so every memory kind shares one
 * definition of "which turn is this", resolved ONCE per run (in the Agent's
 * seed stage) rather than re-derived per write stage. Re-deriving per stage
 * is not equivalent and is why this is a shared helper: `writeMessages`
 * stamps turn N, and a scan taken after it would read N and answer N+1 — so
 * beats written later in the same turn would carry a turn number no message
 * of theirs has, and their `msg-{turn}-{index}` references would point at
 * entries that do not exist.
 *
 * Cost: one paged `list()` per store per run, on the store the memory was
 * already going to talk to. Bounded by {@link MAX_SCAN_PAGES}.
 *
 * @see ../stages/writeMessages.ts   the id format this protects
 * @see ../causal/writeSnapshot.ts   the same rule, kept as self-defense for
 *                                   hand-composed (non-Agent) pipelines
 */
import type { MemoryEntry } from '../entry/index.js';
import type { MemoryIdentity } from '../identity/index.js';
import type { MemoryStore } from '../store/index.js';
export interface MaxStoredTurnOptions {
    /**
     * Which entries count. Default: every entry that carries
     * `source.turn`. `writeSnapshot` narrows this to its own `snap-{n}` ids
     * so that its self-defense stays stable no matter what else shares the
     * namespace.
     */
    readonly turnFor?: (entry: MemoryEntry<unknown>) => number;
}
/**
 * The highest turn already stored in this identity's namespace — 0 when the
 * conversation has never been written to.
 *
 * Only LIVE entries are seen: `store.list` drops TTL-expired ones, the same
 * as every read path, so an expired turn 4 does not hold the numbering open.
 */
export declare function maxStoredTurn(store: MemoryStore, identity: MemoryIdentity, options?: MaxStoredTurnOptions): Promise<number>;
export interface ResolveTurnNumberOptions {
    /**
     * The durable stores this conversation is written to. Every one is
     * consulted and the highest turn wins, so two memories sharing a
     * conversation agree on which turn it is even when they keep their
     * entries in different backends.
     *
     * Duplicates (the usual case — one store, several memories) are scanned
     * once.
     */
    readonly stores: readonly MemoryStore[];
    /** The conversation namespace to scan. */
    readonly identity: MemoryIdentity;
    /**
     * What the host believes the turn is — a FLOOR, never the last word. The
     * Agent derives it from the conversation it was handed (how many user
     * turns are already in the history), which is right for a followed-up
     * conversation and stale for a fresh agent per turn. Default 1.
     */
    readonly hostTurn?: number;
}
/**
 * Resolve the turn number this run should stamp on everything it writes.
 *
 * Returns at least 1, always. A store that throws is NOT swallowed: a memory
 * whose store is unreachable is going to fail on the next read anyway, and a
 * turn number quietly guessed here is how entries overwrite each other.
 */
export declare function resolveTurnNumber(options: ResolveTurnNumberOptions): Promise<number>;
/** A host turn below 1 (or not a number at all) means "I do not know" → 1. */
export declare function normalizeHostTurn(hostTurn: number | undefined): number;
//# sourceMappingURL=resolveTurnNumber.d.ts.map