import type { FlowChartBuilder } from 'footprintjs'; import type { MemoryState } from './types.js'; import { type TokenCounter } from './tokenize.js'; /** * Reusable shape for a **composable pipeline segment** — a function that * appends one or more stages to a builder and returns the builder. This * is the memory layer's convention for packaging multi-stage work * (decider + branches, multi-stage sub-pipelines) as a single unit that * consumers can drop into any flowchart: * * ```ts * let b = flowChart('Seed', seed, 'seed'); * b = pickByBudget(config)(b); // appends a decider + 3 branches * b = b.addFunction('Format', fmt, ...); * ``` * * Generic in `T` so segments targeting the memory layer can be composed * into host flowcharts whose state extends `MemoryState`. Future * segments (NarrativeMemory, SemanticRetrieval, FactExtraction) follow * the same shape for uniform composition ergonomics. */ export type PipelineSegment = (builder: FlowChartBuilder) => FlowChartBuilder; export interface PickByBudgetConfig { /** * Tokens to keep in reserve — not used for memory. Default 256. * Covers system-prompt overhead, new user message headroom, and safety * margin against token-counter approximation error. Tune per model. */ readonly reserveTokens?: number; /** * Hard floor on memory tokens. If the budget minus reserve is less than * this, NO memory is injected (better to skip than inject a fragment). * Default 100 — under 100 tokens of memory is usually worse than none. */ readonly minimumTokens?: number; /** * Pluggable token counter — defaults to `approximateTokenCounter` * (1 token ≈ 4 chars). Swap for a real tokenizer when accuracy matters. */ readonly countTokens?: TokenCounter; /** * Optional cap on the NUMBER of entries, independent of tokens. * Useful when the budget is large enough to include hundreds of * entries but the LLM's "lost-in-the-middle" effect degrades quality * past ~20. Default: no cap (budget is the only limit). */ readonly maxEntries?: number; } /** * Append the pick-by-budget decider + branches to `builder`. Returns * the builder so calls chain naturally: * * ```ts * let b = flowChart('LoadRecent', loadRecent(config), 'load-recent'); * b = pickByBudget(pickConfig)(b); * b = b.addFunction('Format', formatDefault(formatConfig), 'format-default'); * ``` * * Generic in `T` so consumers whose scope extends `MemoryState` (e.g., * an AgentLoopState that embeds memory fields) can compose this into * their own pipeline without casting. */ export declare function pickByBudget(config?: PickByBudgetConfig): PipelineSegment;