/** * Session store — unified persistence layer that composes `SessionTape` * (event replay) and a per-store branch registry (Python parity). Mirrors * `python/src/adk_fluent/_session/`. * * `SessionSnapshot` is the frozen on-disk format; `SessionStore` is the * mutable runtime object. A store can be serialized to a snapshot, * persisted, and hydrated back into a fresh store without losing branch * metadata (parent lineage, messages history, timestamps, arbitrary * metadata bag). * * Why not delegate everything to `ForkManager`? The minimal TS * `ForkManager` in `lifecycle.ts` predates the Python parity push and * only tracks `{name, state, createdAt}`. The Python `Branch` is richer * (messages, parent, metadata, active-branch pointer) and the snapshot * format preserves all of it. This module keeps its own branch registry * keyed by name so snapshots round-trip losslessly; the older * `ForkManager` remains wired in for back-compat wherever it is still * used. */ import { SessionTape, type HarnessEvent } from "./events.js"; import { ForkManager, type ForkBranch } from "./lifecycle.js"; export interface BranchOptions { name: string; state: Record; messages?: ReadonlyArray>; parent?: string | null; createdAt?: number; metadata?: Record; } /** * Immutable record of a named state snapshot. Mirrors Python * `_session._fork.Branch`. * * Branches are constructed via `ForkRegistry.fork()` — instances are * deeply cloned so the owner of the manager cannot mutate the recorded * state after the fact. Fields are public `readonly` so callers can * inspect them without invoking getters. */ export declare class Branch { readonly name: string; readonly state: Readonly>; readonly messages: ReadonlyArray>; readonly parent: string | null; readonly createdAt: number; readonly metadata: Readonly>; constructor(options: BranchOptions); /** Plain-dict representation suitable for `SessionSnapshot` payloads. */ toDict(): Record; static fromDict(data: Record): Branch; } export type MergeStrategy = "union" | "intersection" | "prefer"; export interface ForkOptions { messages?: ReadonlyArray>; parent?: string | null; metadata?: Record; } export interface MergeOptions { strategy?: MergeStrategy; prefer?: string; } export interface ForkDiff { onlyA: Record; onlyB: Record; different: Record; same: string[]; } /** * Internal branch manager used by `SessionStore`. Mirrors Python * `_session._fork.ForkManager` feature-for-feature: branch lineage, * merge strategies, diff, delete, active-pointer, and callback * factories. * * Kept local to this module to avoid breaking the pre-parity * `ForkManager` exported from `lifecycle.ts` — callers that want the * rich API go through `SessionStore`. */ export declare class ForkRegistry { readonly maxBranches: number; private readonly branches; private activeName; constructor(opts?: { maxBranches?: number; }); /** Create a named branch from `state`. */ fork(name: string, state: Record, opts?: ForkOptions): Branch; /** Return a deep clone of `name`'s state and mark it active. */ switch(name: string): Record; get(name: string): Branch; has(name: string): boolean; delete(name: string): void; /** * Merge state from multiple branches. * * - `union` (default): combine all keys; last branch wins on conflict. * - `intersection`: keep only keys present in every branch; use last * branch's values. * - `prefer`: start with union, then overlay `prefer` branch's values. */ merge(branchNames?: string[], opts?: MergeOptions): Record; diff(branchA: string, branchB: string): ForkDiff; /** Return an array of `{name, parent, keys, messages, active, ...metadata}`. */ listBranches(): Array>; /** Raw insertion-ordered branch list for snapshot serialisation. */ all(): Branch[]; get active(): string | null; set active(name: string | null); get size(): number; clear(): void; /** * Build an `afterAgent`-style callback that auto-forks the active * state into `branchName` after every agent run. */ saveCallback(branchName: string): (ctx: unknown) => void; /** * Build a `beforeAgent`-style callback that restores state from * `branchName` into the active context. */ restoreCallback(branchName: string): (ctx: unknown) => void; } export interface SessionSnapshotData { version: number; activeBranch: string | null; events: ReadonlyArray>; branches: Readonly>>; } /** * Frozen, serialisable bundle of tape events + branches. Round-trips * losslessly through `toDict()` / `fromDict()` and `save()` / `load()`. * * The dict format is deliberately snake-case (`active_branch`, * `created_at`) so snapshots are portable across the Python and TS * runtimes. */ export declare class SessionSnapshot { readonly version: number; readonly activeBranch: string | null; readonly events: ReadonlyArray>; readonly branches: Readonly>>; constructor(data?: Partial); /** Snake-cased dict payload mirroring the Python shape. */ toDict(): Record; static fromDict(data: Record): SessionSnapshot; /** Persist the snapshot to a JSON file. */ save(path: string): void; /** Load a snapshot previously written by `save()`. */ static load(path: string): SessionSnapshot; get eventCount(): number; get branchCount(): number; } export interface SessionStoreOptions { tape?: SessionTape; forks?: ForkRegistry; /** Optional legacy `ForkManager` from `lifecycle.ts`. Unused by new code. */ legacyForks?: ForkManager; activeBranch?: string | null; maxBranches?: number; } /** * Session-scoped container for tape + fork registry. One object, one * lifetime, one snapshot artifact. Matches Python * `_session._store.SessionStore` feature for feature. */ export declare class SessionStore { readonly tape: SessionTape; readonly forks: ForkRegistry; /** Back-compat legacy manager, exposed for callers that still use it. */ readonly legacyForks: ForkManager; constructor(opts?: SessionStoreOptions); /** Record a harness event into the tape. */ recordEvent(event: HarnessEvent): void; /** Create a named branch. */ fork(name: string, state: Record, opts?: ForkOptions): Branch; /** Switch to a named branch. */ switch(name: string): Record; get activeBranch(): string | null; /** Produce a frozen snapshot of the whole store. */ snapshot(): SessionSnapshot; /** Rehydrate a store from a snapshot, preserving branch metadata. */ static fromSnapshot(snapshot: SessionSnapshot): SessionStore; /** `afterAgent` callback that snapshots state to `branchName`. */ autoFork(branchName: string): (ctx: unknown) => void; /** `beforeAgent` callback that restores state from `branchName`. */ autoRestore(branchName: string): (ctx: unknown) => void; /** Quick-glance summary of tape + fork state. */ summary(): { eventCount: number; branchCount: number; activeBranch: string | null; tape: { size: number; }; }; /** Drop everything. Tape events and branches are both wiped. */ clear(): void; } export interface SessionPluginOptions { /** Branch name format. Defaults to `auto:`. */ branchNamer?: (agentName: string) => string; } /** * Session-scoped plugin that auto-forks after every agent run. Use as a * thin wrapper around a `SessionStore` — the plugin exposes * `afterAgent(ctx, agentName)` to be wired into the agent lifecycle. * * We do not subclass ADK's `BasePlugin` here because the TS ADK runtime * surface differs from Python. The plugin is intentionally a plain * object so it can be adapted to whichever plugin layer the caller is * running against. */ export declare class SessionPlugin { readonly store: SessionStore; private readonly branchNamer; constructor(store: SessionStore, options?: SessionPluginOptions); /** Invoke after every agent run to capture its state into a branch. */ afterAgent(ctx: unknown, agentName: string): void; /** Invoke before every agent run to restore a previously captured branch. */ beforeAgent(ctx: unknown, agentName: string): void; } export type { ForkBranch }; //# sourceMappingURL=session-store.d.ts.map