/** * Named memory strategies — what each one does, which TYPES accept it, and * what the host must supply before it can run. * * `MEMORY_STRATEGIES` is a const of seven bare strings. A string is enough to * WRITE `strategy: { kind: … }` and not nearly enough to OFFER the choice: a * host rendering a strategy picker off that const offers seven options, and * learns which of them this deployment can actually run by calling * `defineMemory` and reading the exception. That is a selector that discovers * its own capabilities by failing. * * So each strategy declares itself, and `listMemoryStrategies()` enumerates * the declarations. The shape mirrors the influence exemplar in this same * package (`listInfluenceStrategies()` → `{ name, description, requirements, * scorer }`), with two deliberate differences: * * • the id is `kind`, not `name` — it is the value the caller writes into * `strategy.kind`, so a picker's option value IS the id; * • there is no `scorer`, because a memory strategy is not a function the * host calls; what it needs instead is `types` — the memory TYPES that * accept it, which is the other half of "can I offer this?" (`decay` on a * SEMANTIC store is refused however good the host's credentials are). * * `requirements` is what a host must SUPPLY (an embedder, an LLM, a store * that can search). Empty means the strategy runs anywhere, at $0. * * Pattern: declared capability descriptors + the two guards that enforce * them — SHAPE first (`assertStrategyShape`: is this even a * strategy?), REQUIREMENTS after (`assertStrategyRequirements`: can * this deployment run it?). * Role: memory/ layer-1, beside the const it describes. * Emits: N/A — build-time only. * * @see ./define.types.ts for `MEMORY_STRATEGIES` and the strategy union * @see ../lib/influence-core/strategies.ts for the exemplar this follows */ import { type DefineMemoryOptions, type MemoryStrategyKind, type MemoryType } from './define.types.js'; /** * What a strategy needs the host to supply before it can run. A picker greys * out (or refuses to offer) strategies whose requirements it cannot meet. * * Three well-known values ship; the type stays open so a consumer's own * strategy descriptor can name something else: * * - `'embedder'` — an `Embedder` that turns text into a vector. * - `'vector-store'` — a store that implements `search()`. Not the same * requirement as an embedder: the embedder makes the * query vector, the store is what ranks against it, * and a deployment can easily have one without the * other (`RedisStore` is a full memory store with no * `search()` at all). * - `'llm'` — a chat provider the strategy calls on the host's * behalf. * - `'model'` — the model id that provider is called WITH. Its own * requirement rather than part of `'llm'`, because a * deployment can hold a provider and still have no * answer for which model compression should run on — * and a library that picked one for you would be * picking your invoice (9.14.0). */ export type MemoryStrategyRequirement = 'embedder' | 'vector-store' | 'llm' | 'model' | (string & Record); /** * A memory strategy, described: enough for a host to render it in a picker * and know, before it offers the option, whether this deployment can run it. */ export interface MemoryStrategyInfo { /** The value written as `strategy.kind` — a member of `MEMORY_STRATEGIES`. */ readonly kind: MemoryStrategyKind; /** One-or-two-sentence plain description, current-truth caveats included. */ readonly description: string; /** What the host must supply. Empty = runs anywhere, no dependency, $0. */ readonly requirements: readonly MemoryStrategyRequirement[]; /** The memory TYPES that accept this strategy. Any other pair is refused. */ readonly types: readonly MemoryType[]; } /** * Every memory strategy, described — cheapest first, in the order the docs * teach them. Frozen: a host renders its picker straight off this. * * @example Offer only what this deployment can actually run * ```ts * import { listMemoryStrategies } from 'agentfootprint/memory'; * * const available = new Set(embedder ? ['embedder', 'vector-store'] : []); * const offerable = listMemoryStrategies().filter( * (s) => s.types.includes('episodic') && s.requirements.every((r) => available.has(r)), * ); * // → window, budget, decay, hybrid — the four that cost nothing to run. * ``` */ export declare function listMemoryStrategies(): readonly MemoryStrategyInfo[]; /** * One strategy's description by `kind`, or `undefined` for a string that is * not a strategy at all. */ export declare function memoryStrategyInfo(kind: string): MemoryStrategyInfo | undefined; /** * Refuse a strategy whose SHAPE is wrong, before anything reads into it. * * WHY it runs FIRST, ahead of both the pipeline dispatch and the * requirements walk: those two read FIELDS off the strategy * (`strategies[0]`, `s.embedder`, `for (const sub of strategy.strategies)`), * and a field read off a shape that never had it is a `TypeError` with the * library's internals in the text — `Cannot read properties of undefined * (reading '0')` for `{ kind: 'hybrid', size: 5 }`, which names neither the * option the caller got wrong nor the one they meant. A caller cannot act on * that. This guard turns every such read into a refusal that names the * field, shows the line that would have worked, and points at the catalogue. * * It checks SHAPE only — is this an object, does it carry a `kind`, does a * `hybrid` carry the array that makes it a hybrid. It deliberately does NOT * judge whether the kind is real or legal for the type: the dispatch refuses * those and names the alternative for that type, which is the better message. * * @param strategy the strategy exactly as the caller wrote it — `unknown`, * because the whole point is that it may not be a `Strategy`. * @param site the call to name in the message, e.g. `defineMemory[chat]`. */ export declare function assertStrategyShape(strategy: unknown, site: string): void; /** * Refuse a config whose strategy declares a requirement the caller did not * supply — by name, at BUILD, with the fix in the message. * * WHY it runs LAST, after the pipeline dispatch rather than before it: the * dispatch's own refusals know more than this one does. `defineMemory`'s * TOP_K arm knows about the `ranksBy: 'server-text'` exemption AND about the * write half it takes away; the CAUSAL arm knows that exemption does not * apply to it; the EXTRACT arm knows the `llm` matters only for * `extractor: 'llm'`. Speaking first would replace those messages with a * blunter one. This is the BACKSTOP: it says something only when nothing * better already did, and its job is that no declared requirement can go * unchecked — the failure it exists to prevent is a missing dependency * surfacing as a `TypeError` from five frames inside a stage, halfway * through a paid run. * * @param options the config as written by the caller. * @param site the call to name in the message, e.g. `defineMemory[chat]`. */ export declare function assertStrategyRequirements(options: DefineMemoryOptions, site: string): void; //# sourceMappingURL=strategies.d.ts.map