@nhtio/adk/batteries/context/thrift/relevance
Relevance-based history-turn selection — the companion to subtractToFit that decides WHICH prior turns are worth replaying at all, before the subtractive pass ever runs.
Remarks
@nhtio/adk/batteries/context/thrift/subtractive_pass!subtractToFit sheds a working set's OLDEST turns first once the budget is blown — a purely recency-based (FIFO) policy. This module is a smarter alternative for the turn-selection step upstream of that: instead of "the last N turns," walk the ENTIRE history (no turn-count cap) and keep any turn whose content is LEXICALLY RELEVANT to the current query, regardless of how old it is, while always keeping the most recent keepRecent turns verbatim (coreference — "it", "that file" — needs the immediately preceding turns present no matter what).
This is a genuine head-to-head-evaluated alternative to naive recency, not a hypothetical: in the flagship reference agent this battery was extracted from, selectRelevantTurns was the TREATMENT arm and selectNaiveTurns was the BASELINE arm of the same evaluation the battery barrel documents. Use selectRelevantTurns when you want the evaluated win; selectNaiveTurns remains exported as an honest, drop-in comparison baseline (or for a caller who simply wants FIFO).
Zero imports, same as every module in this battery — token measurement is via an injected EstimateTokensFn, never a bundled tokenizer.
Interfaces
| Interface | Description |
|---|---|
| HistoryTurn | One grouped conversation turn: the messages from a user message through the next assistant message (inclusive), plus any tool calls that occurred during it, and qa — the turn's full combined text (every message's content plus every tool call's name args fragment) used for relevance scoring. |
| RelevanceMessage | The minimal structural shape of a conversation message this module groups into turns. createdAt is a lexicographically-sortable timestamp string (e.g. ISO-8601) — turns and tool calls are ordered by string comparison (localeCompare), not parsed into a Date, so any consistently-formatted sortable string works. |
| RelevanceToolCall | The minimal structural shape of a tool call this module attaches to the turn it occurred in. |
| SelectNaiveTurnsOptions | Options for selectNaiveTurns. |
| SelectRelevantTurnsOptions | Options for selectRelevantTurns. |
Variables
| Variable | Description |
|---|---|
| RELEVANCE_FLOOR_CURVE | The exponent shaping how the relevance floor scales between RELEVANCE_FLOOR_MIN and RELEVANCE_FLOOR_MAX as window utilization rises from 0 to 1 (see scaledRelevanceFloor). |
| RELEVANCE_FLOOR_MAX | The relevance floor's upper bound — the minimum shared-content-word fraction required when the window is nearly full (strict: only keep turns with strong, unambiguous overlap). |
| RELEVANCE_FLOOR_MIN | The relevance floor's lower bound — the minimum fraction of the current query's content words a turn must share to be kept, used when the window is nearly empty (permissive: keep almost anything that shares ANY real overlap). |
Functions
| Function | Description |
|---|---|
| argText | Render a tool call's arguments into a short text fragment for inclusion in a turn's relevance text (see groupHistoryIntoTurns) — best-effort JSON.stringify, truncated, empty on failure (e.g. circular structures) or absent args. |
| contentTokens | Extract the "content word" tokens of a string for lexical overlap scoring: lowercased alphanumeric runs of length >= 4, deduplicated into a set. Deliberately crude (no stemming, no stopword list beyond the length-4 floor) — this is a cheap, zero-model-call, zero-dependency relevance signal, not a semantic one; the calibration in RELEVANCE_FLOOR_MIN/RELEVANCE_FLOOR_MAX was run against exactly this scoring function, so changing it invalidates those constants. |
| groupHistoryIntoTurns | Group a flat message history (plus its tool calls) into HistoryTurns: a new turn starts at each message that begins a fresh exchange and closes at the next 'assistant'-role message (inclusive); every message up to the first turn boundary that has no preceding messages also starts a turn. Tool calls are attributed to the LATEST turn whose first message precedes the call's timestamp. |
| relevanceToQuery | What fraction of the QUERY's content words appear in text — the relevance of a prior turn to the CURRENT query (not the reverse: a turn need not share all its own content, only enough of the query's). |
| scaledRelevanceFloor | Scale the relevance floor between RELEVANCE_FLOOR_MIN (empty window, permissive) and RELEVANCE_FLOOR_MAX (full window, strict) by a convex curve on window utilization — see RELEVANCE_FLOOR_CURVE for why convex. |
| selectNaiveTurns | The recency (FIFO) baseline: keep the newest turns, oldest-first-dropped, until historyBudget is exhausted — walking backward from the newest turn and stopping (WITHOUT including) the first turn that would push the running total over budget. The single newest turn is always kept even if it alone exceeds historyBudget. |
| selectRelevantTurns | Select which turns to replay by RELEVANCE to the current query: always keep the most recent keepRecent turns, and among the OLDER turns keep any whose relevanceToQuery score against the query's content words clears a floor that scales with how much of the older-history budget is already spoken for (see scaledRelevanceFloor). Walks the ENTIRE history — there is no turn-count cap — so a turn from far in the past survives if it is genuinely relevant, which a recency-only policy (see selectNaiveTurns) can never do. |
References
EstimateTokensFn
Re-exports EstimateTokensFn