/** * What this session already learned, in the cached prefix. * * THE PROBLEM IS TURNS, NOT TOKENS, and this repository has already measured * that. The `enforce` posture cut nothing and cost 1.471x control, driven * almost entirely by extra turns: 0.90 wasted turns per refused-then-retried * tool call. A turn is worth far more than the tokens in it, so anything that * removes one pays for a great deal of context. * * The knowledge graph knows things that would remove turns -- a command that * failed and why, a path that does not work, a correction a person already * made. Today it reaches the model two ways, and both arrive too late or too * dear: * * SessionStart one shot, chosen from the opening task text. Good, cheap, * and blind to everywhere the session goes afterwards. * PreToolUse an advisory attached to a matching tool call. It arrives * AFTER the model decided to make that call, so acting on it * costs the turn it was supposed to save. * * A finding that would prevent a mistake has to be present BEFORE the decision, * on every turn, which means it has to live in the cached prefix. There it is * billed at 0.1x rather than 1.0x, and it is in front of the model whether or * not the session happens to touch the file it is anchored to. * * BYTE-STABILITY IS THE WHOLE ENGINEERING PROBLEM, and it is easy to get * backwards. Content in the cached prefix must be IDENTICAL every turn or the * cache misses and the injection costs 1.25x on the entire prefix instead of * 0.1x -- far worse than never injecting. So the block is NOT re-selected each * turn against the latest question, however tempting that is: it is computed * once, remembered, and replayed verbatim until a turn on which rewriting the * prefix is already free. `anchor.ts` is what knows when that is. * * THIS IS NOT THE INJECTION WE CRITICISE HEADROOM FOR, and the distinction has * to be real rather than rhetorical. Theirs is MECHANISM: a tool definition and * instructions for redeeming markers, tokens spent to make compression work, * pure overhead on every request. This is PAYLOAD: conclusions that replace * work the model would otherwise redo. It has to earn its place, so it is off * by default, budgeted, and reported as its own line rather than folded into a * compression figure it would flatter nobody by joining. */ import type { EmbeddingCache } from './embedding.js'; import { type ProviderRequest } from './frontier.js'; /** One thing the graph knows, reduced to what the model needs to read. */ export interface Finding { /** The conclusion itself. */ readonly claim: string; /** Stable identifier, used to keep the selection deterministic. */ readonly key?: string; /** `failure`, `decision`, `command`, `finding`, `feedback`, `map`. */ readonly type?: string; /** 0..1. */ readonly confidence?: number; /** `human` outranks `agent`: a person's correction is not a guess. */ readonly origin?: string; /** Explicitly kept in front of the model regardless of relevance. */ readonly pinned?: boolean; /** Withdrawn. Never rendered. */ readonly retired?: boolean; /** `verified` | `probable` | `speculative`, as recorded when written. */ readonly confidenceLabel?: string; /** The anchored code changed after this was written. */ readonly stale?: boolean; /** * `project` | `organization` | `global`, as recorded when written. * * CARRIED BECAUSE A CLAIM'S REACH IS PART OF THE CLAIM. It was dropped in * `loadFindings`, so nothing downstream could tell a lesson that transfers * from one that does not -- and the distinction cannot be recovered by * relevance ranking, because lexical similarity is exactly what makes a * project-specific claim look applicable somewhere it is false. * * Provenance is otherwise implicit: each project keeps its own graph, so a * `project` finding is true of whichever graph holds it. That breaks down for * a SHARED graph -- the unrooted fallback, or one deliberately mounted across * several repositories -- where project claims from one tree are served to * another. Measured on this repository's graph: of 293 findings passing the * quality filter, 221 are `project`, 57 `global`, 15 `organization`. */ readonly scope?: string; } /** * How many characters of findings may sit in the prefix. * * Roughly 500 tokens. It is charged once as a cache write and then read at * 0.1x for the rest of the session, so the recurring cost is around 50 tokens * a turn -- against a wasted turn, which this project measured at far more. * Still a budget rather than a licence: an unbounded block would push the * genuinely relevant findings past the point a model reliably attends to. */ export declare const DEFAULT_BUDGET_CHARS = 2000; export interface KnowledgeOptions { readonly embeddings?: EmbeddingCache; /** * The graph is shared across projects, so `project` claims cannot be trusted. * * Set when the findings came from the unrooted fallback graph or from a graph * deliberately mounted across several repositories. In that case a `project` * finding is a fact about SOME tree, and nothing here can say which -- so it * is excluded rather than ranked, because relevance ranking would actively * promote it: lexical similarity is what makes a project-specific claim look * applicable somewhere it is false. * * Left false for a normal per-project graph, where a `project` finding is * true of exactly the tree being worked on and is the most useful kind there * is. */ readonly sharedGraph?: boolean; } export declare function knowledgeBlock(findings: readonly Finding[], context: string, budgetChars?: number, options?: EmbeddingCache | KnowledgeOptions | undefined): string | null; /** * The text the selection is ranked against: the cached prefix, which is stable. * * Deliberately NOT the most recent turn. That is the question, it changes every * turn, and ranking against it would change the block every turn -- turning a * 0.1x read into a 1.25x write on the whole prefix. */ export declare function stableContext(request: ProviderRequest): string; /** * Puts the block in the request, inside the cached region. * * APPENDED TO `system`, which is the only place guaranteed to sit ahead of * every message and therefore inside whatever the breakpoint covers. Appended * rather than prepended so the host's own system prompt keeps its position -- * that prompt is the most stable text in the request and anything inserted * before it re-prices everything behind it. */ export declare function injectKnowledge(request: ProviderRequest, block: string | null): ProviderRequest; //# sourceMappingURL=knowledge.d.ts.map