@nhtio/adk/batteries/context/thrift/contracts
Structural contracts for the Token Thrift subtractive-pass battery — every shape it reads off a caller's objects, and every capability it invokes via an injected function.
Remarks
This module has zero imports — not even a type-only import from @nhtio/adk core. Every type below is a local structural (duck-typed) declaration of the minimum shape the subtractive pass actually reads, derived field-by-field from the production algorithm this battery was extracted from (the flagship agent's agent_subtractive_pass.ts). A core Message, Memory, Retrievable, Thought, Tool, or ToolRegistry instance satisfies these interfaces structurally — you never need to import the core classes to call this battery, and the battery never needs to import them to accept your objects. This is the "surface, don't impose" contract in its most literal form: the battery imposes a SHAPE, never a CLASS.
Two kinds of decoupling happen here:
- Structural types for the read-only working-set items (messages, memories, retrievables, thoughts, tool calls, tools, a tool registry) — the battery only ever reads the handful of fields/methods declared here, never the full core class surface.
- Injected resolver functions for capabilities the battery cannot perform itself — most importantly token estimation (EstimateTokensFn), since this battery ships with no tokenizer of its own and must never guess at one.
Interfaces
| Interface | Description |
|---|---|
| ContentLike | A Tokenizable-like value: renders to a string and (usually) knows its own token cost. Every content field the working set carries (system prompt, standing instructions, message/thought content) is either a plain string or a value shaped like this. |
| Estimable | Anything that can estimate its own rendered token cost under a named encoding — the structural shape the battery expects from a Tokenizable-like value (system prompt, standing instruction, message content, thought content). Mirrors core's Tokenizable public surface, minimally. |
| MillisTimestamp | Anything with a .toMillis() — the structural shape the battery needs from a timestamp field (a core DateTime satisfies this; so does a plain { toMillis: () => number } test double). |
| WorkingImage | An image (or other flat-cost media) attachment in the working set — the single biggest token hog, shed first when the dispatch is over budget. |
| WorkingMemory | The structural shape of a memory the working set carries. Only content (measured) and importance (sort key — low-importance memories shed first) are read. |
| WorkingMessage | The structural shape of a conversation message the working set carries. Only the fields the pass actually reads: id (for ephemeral/summary predicate matching and identity-stable tracing), content (measured, and — for messages with no content — treated as empty/attachments-only), and createdAt (for oldest-first shedding order). |
| WorkingRetrievable | The structural shape of a retrieved passage (RAG chunk) the working set carries. estimateTokens mirrors a core Retrievable's own method, which MAY resolve asynchronously (a reader-backed artifact's estimate can be a Promise) — the battery treats a non-number return as "measure the rendered string instead" (see @nhtio/adk/batteries/context/thrift/subtractive_pass!subtractToFit's rTok helper), since this pass is synchronous end-to-end and never awaits. |
| WorkingThought | The structural shape of a "thought" (model-internal guidance/scratchpad content, e.g. a plan or a per-iteration nudge) the working set carries. Read for identity (id, matched against keepThoughtIds/protectThoughtIds), measurement (content), and shed ordering (createdAt). |
| WorkingTool | The structural shape of a tool declaration the working set's tool registry carries. Only name (identity, shed-rank lookup) and description (the fallback name: description measurement proxy used when no RenderToolsFn is injected) are read. |
| WorkingToolCall | A prior-turn (or this-turn) tool call in the working set, carrying the PRE-COMPUTED token cost of its rendered result — the pass never renders a tool result itself (it would need to await an artifact reader, breaking synchrony), so the caller measures the result via its own renderer and hands the cost here. |
| WorkingToolRegistry | The MINIMAL tool-registry surface the pass needs — not the full core ToolRegistry class. Only all() (enumerate every registered tool, to compute the tools bucket's "before" weight) and setHidden(...names) (replace the entire hidden set — the mechanism by which a shed tool becomes invisible to the model while remaining callable via a catalog) are invoked. |
Type Aliases
| Type Alias | Description |
|---|---|
| EstimateTokensFn | Estimate the token cost of a rendered string under a named encoding, optionally resolved against a live dispatch context. |
| IsEphemeralMessageFn | Decide whether a message is an EPHEMERAL control message — one that is re-derived fresh every dispatch iteration and never persisted, so only the LATEST surviving copy carries live information and every older one is pure waste. Injectable so a caller's own id-tagging scheme (or a caller with no such concept at all) can plug in; see the isEphemeralMessage option on @nhtio/adk/batteries/context/thrift/subtractive_pass!subtractToFit for the calibrated default (id.startsWith('__eph-'), the flagship agent's own convention). |
| IsSummaryMessageFn | Decide whether a message is the load-bearing "running summary" a compacting/summarizing strategy maintains — content that stands in for every older turn that strategy folded away, and so must never be shed like an ordinary old turn even though it is chronologically the oldest message in the working set. Injectable; see the isSummaryMessage option on @nhtio/adk/batteries/context/thrift/subtractive_pass!subtractToFit for the calibrated default (id === '__compact-summary'). Callers who never run a summarizing strategy alongside thrift can ignore this entirely — the default predicate simply never matches their messages. |
| RenderToolsFn | Renders a set of tools into the EXACT prompt text a caller's LLM battery will send to the model (e.g. a <tool_definitions> block with full JSON-Schema per tool), so the tools bucket is measured against the REAL dispatched size rather than a cheap name: description proxy. Injecting this is the difference between an accurate budget and one that silently undercounts by an order of magnitude for schema-heavy tools — see the calibration note on @nhtio/adk/batteries/context/thrift/subtractive_pass!subtractToFit. Optional: when omitted, the pass falls back to the name: description proxy (keeps the battery usable standalone/in tests without a real tool-rendering pipeline). |
| ShedRankFn | Ranks a tool by last-resort shed priority: LOWER rank sheds FIRST. Ties are broken by encounter order (a stable sort), so two tools ranked equally shed in whatever order the caller's relevantToolNames listed them. |