{"version":3,"file":"subtractive_pass.cjs","names":[],"sources":["../../../../src/batteries/context/thrift/subtractive_pass.ts"],"sourcesContent":["/**\n * The subtractive pass — the whole Token Thrift thesis, in code.\n *\n * @module @nhtio/adk/batteries/context/thrift/subtractive_pass\n *\n * @remarks\n * A context window is NOT a chat history. It is just what you send for ONE dispatch. So: hold a\n * large WORKING set (messages, memories, retrievables, thoughts, an image, tools), then SUBTRACT it\n * down to the high-signal slice that fits the active model's window — focus, don't accumulate.\n *\n * This module is the model-facing plane only. Where the human-facing chat history lives (a SQLite\n * store, an in-memory array, anything else) is entirely the caller's concern — this battery never\n * touches it. Everything here is window-agnostic: the same function runs at `contextWindow: 4096`\n * and `contextWindow: 1_000_000` — the span is a parameter, not a rewrite.\n *\n * This is a direct extraction of the flagship reference agent's production subtractive pass\n * (evaluated head-to-head across five models — see the battery barrel's TSDoc for the results),\n * retargeted at the local structural contracts in\n * {@link @nhtio/adk/batteries/context/thrift/contracts} so it couples to nothing in `@nhtio/adk`\n * core — every value it reads is duck-typed, and its one true dependency (token estimation) is an\n * injected function, never a bundled tokenizer.\n */\n\nimport { E_CONTEXT_RESOLVER_MISSING } from '../exceptions'\nimport type {\n  EstimateTokensFn,\n  ContentLike,\n  WorkingMessage,\n  WorkingMemory,\n  WorkingRetrievable,\n  WorkingThought,\n  WorkingTool,\n  WorkingToolRegistry,\n  WorkingToolCall,\n  WorkingImage,\n  RenderToolsFn,\n  ShedRankFn,\n  IsEphemeralMessageFn,\n  IsSummaryMessageFn,\n} from './contracts'\n\n// Re-exported so a consumer of this module doesn't need a second import from `./contracts` for the\n// types that appear directly in this module's own public signatures.\nexport type {\n  WorkingToolCall,\n  WorkingImage,\n  WorkingMessage,\n  WorkingMemory,\n  WorkingRetrievable,\n  WorkingThought,\n  WorkingTool,\n  WorkingToolRegistry,\n  RenderToolsFn,\n  ShedRankFn,\n  IsEphemeralMessageFn,\n  IsSummaryMessageFn,\n  EstimateTokensFn,\n}\n\n/**\n * The token encoding this battery measures under, by default.\n *\n * @remarks\n * `'cl100k_base'` — a widely-available, model-agnostic tiktoken encoding — is the default because\n * this battery is core-agnostic: unlike the flagship reference agent it was extracted from (which\n * hard-codes the `gemma` encoding because its engine IS Gemma via LiteRT-LM), this battery has no\n * opinion on which model you run. `cl100k_base` is a reasonable, broadly-supported baseline for a\n * caller who hasn't thought about encodings yet; a caller running Gemma, Claude, or any other model\n * with a distinct tokenizer should pass their own `encoding` (and a matching {@link EstimateTokensFn})\n * so the budget math agrees with what their model/battery actually counts. The encoding identifier is\n * an opaque string as far as this module is concerned — it is never validated or interpreted here,\n * only threaded through to the injected {@link EstimateTokensFn}.\n */\nexport const DEFAULT_ENCODING = 'cl100k_base'\n\n/**\n * Fallback output reserve, as a fraction of the window, used ONLY when the exact max-output budget is\n * unknown.\n *\n * @remarks\n * Prefer passing the caller's actual generation `maxTokens` as `outputReserve` — reserving a flat\n * fraction of the window when the model can emit at most, say, 2048 tokens throws away real input\n * budget (RAG chunks, history) for output that can never be produced. This fraction is the calibrated\n * value from the flagship reference agent (0.35 of the window), kept as the default for a caller who\n * genuinely doesn't know their generation cap yet.\n */\nexport const DEFAULT_RESERVE_FRACTION = 0.35\n\n/**\n * How many of the NEWEST this-turn tool-result bodies to protect from budget-shedding as a\n * last-resort backstop, by default.\n *\n * @remarks\n * A normal read→answer turn produces 1–2 this-turn results, so `N = 3` leaves the common case\n * untouched; a deep read-loop (several searches/reads in one turn) that piles up more can shed its\n * OLDEST bodies past this cap (the model has moved past them by the time it has made this many\n * calls). The single newest this-turn result is always kept regardless of this cap — see\n * {@link subtractToFit}'s step 3b.\n */\nexport const DEFAULT_THIS_TURN_RESULT_KEEP = 3\n\n/** A line in the \"what got cut\" trace — one bucket's before/after token weight. */\nexport interface BucketTrace {\n  /** The bucket's name (e.g. `'thoughts'`, `'tools'`, `'image'`, `'toolCalls'`, `'retrievables'`,\n   *  `'memories'`, `'messages'`, `'thoughts-shed'`, `'tools-shed'`) — one entry per step of the pass. */\n  bucket: string\n  /** This bucket's measured token weight before this step ran. */\n  beforeTokens: number\n  /** This bucket's measured token weight after this step ran. */\n  afterTokens: number\n  /** How many items this bucket held before this step ran. */\n  beforeCount: number\n  /** How many items this bucket held after this step ran. */\n  afterCount: number\n  /** A short human-readable rationale for what this step did (or didn't do), for diagnostics/tracing. */\n  note?: string\n  /** Item identifiers affected by this bucket, when the working items expose ids. */\n  ids?: string[]\n}\n\n/** The full record of one subtractive pass — before/after weights per bucket, and whether the\n *  dispatch ultimately fits the budget. */\nexport interface ThriftTrace {\n  /** The active model's context window this pass was run against. */\n  contextWindow: number\n  /** Tokens held back for the model's own output (see {@link resolveBudget}). */\n  reserve: number\n  /** The INPUT token budget — `contextWindow - reserve`. */\n  budget: number\n  /** Total measured token weight BEFORE any shedding (the \"everything reasonable\" starting point). */\n  totalBefore: number\n  /** Total measured token weight AFTER every shedding step ran. */\n  totalAfter: number\n  /** Whether `totalAfter` fits within `budget`. */\n  fits: boolean\n  /** The dispatch should be refused: `!fits` — even after every possible shed, the irreducible floor\n   *  (system prompt + standing instructions + newest turn + output reserve) still exceeds the window. */\n  refused: boolean\n  /** One entry per step of the pass, in the order the steps ran, for diagnostics/tracing. */\n  buckets: BucketTrace[]\n}\n\n/** The mutable working set a dispatch starts from — the \"everything reasonable\" set this pass\n *  subtracts down to what fits. Every field is a local structural type from\n *  {@link @nhtio/adk/batteries/context/thrift/contracts} — nothing here requires a core ADK value. */\nexport interface WorkingSet {\n  /** The dispatch's system prompt. Measured ctx-resolved (see {@link subtractToFit}'s `renderCtx`\n   *  option) to match what a caller's own overflow guard counts. */\n  systemPrompt: ContentLike | string\n  /**\n   * Durable directives the caller renders into every dispatch (the caller's battery counts these\n   * too). They are a FIXED cost like the system prompt — never shed — so the pass only ADDS them to\n   * the running total, never trims them. Omit (or pass an empty array) when the caller uses none. A\n   * consumer that DOES render standing instructions must pass them here or thrift would undercount\n   * relative to the caller's own guard.\n   */\n  standingInstructions?: Array<ContentLike | string>\n  /** The conversation history this dispatch would replay — sheds stale ephemeral control messages\n   *  first (step 6), then the oldest turns (step 7); the newest turn is always kept. */\n  messages: WorkingMessage[]\n  /** Durable memories available to this dispatch — sheds lowest-`importance` first (step 5). */\n  memories: WorkingMemory[]\n  /** Retrieved (RAG) passages available to this dispatch — sheds the tail of the ranking (lowest\n   *  `score`) first (step 4), keeping the best-ranked chunks. */\n  retrievables: WorkingRetrievable[]\n  /** Model-internal guidance content (plans, per-iteration nudges, and — unless\n   *  `stripPriorTurnThoughts` is disabled — prior-turn chain-of-thought, dropped in step 1). Surviving\n   *  thoughts are sheddable oldest-first as a last resort (step 8), except any ids named in\n   *  `protectThoughtIds`. */\n  thoughts: WorkingThought[]\n  /** The tool registry this dispatch draws visible tools from — mutated via `setHidden` as tools are\n   *  shed (steps 2 and 9). */\n  tools: WorkingToolRegistry\n  /**\n   * Prior-turn (and this-turn) tool calls whose RENDERED RESULTS the caller puts in the prompt. Omit\n   * (or pass an empty array) when the caller doesn't measure them — the pass then treats tool-result\n   * weight as `0`.\n   */\n  toolCalls?: WorkingToolCall[]\n  /** Optional image (or other flat-cost media) attachment. The single biggest token hog. */\n  image?: WorkingImage\n}\n\n/**\n * Options shared by every entry point in this module that needs to measure a value's token cost —\n * the injected estimator plus the encoding it measures under.\n */\nexport interface EstimatorOptions {\n  /**\n   * REQUIRED. Measures a rendered string's token cost under `encoding`, optionally resolved against\n   * a live dispatch context. There is no default — this battery ships with no bundled tokenizer, so\n   * a caller who omits this gets a clear thrown error naming the option, not a silent guess.\n   */\n  estimateTokens: EstimateTokensFn\n  /** The encoding to measure under. Default: {@link DEFAULT_ENCODING}. */\n  encoding?: string\n}\n\n/**\n * Options accepted by {@link subtractToFit}. `estimateTokens` (via {@link EstimatorOptions}) is the\n * only option with no default; every other field is a calibrated default, documented on its own\n * declaration below, that a caller can override.\n *\n * @remarks\n * Earlier positional-argument forms of this function (as it existed in the flagship reference agent\n * this battery was extracted from) took `outputReserve`, `keepThoughtIds`, `renderTools`,\n * `protectThoughtIds`, `renderCtx`, and `protectedToolNames` as seven trailing positional parameters.\n * They are collected here into one options object to keep the call site legible and to give each a\n * documented default — the mapping from the old positional order to these keys is: position 4 →\n * `outputReserve`, 5 → `keepThoughtIds`, 6 → `renderTools`, 7 → `protectThoughtIds`, 8 → `renderCtx`,\n * 9 → `protectedToolNames`.\n */\nexport interface SubtractToFitOptions extends EstimatorOptions {\n  /**\n   * The EXACT number of tokens to hold back for the model's own output — pass the generation\n   * `maxTokens` the model is configured with. When omitted, falls back to\n   * {@link DEFAULT_RESERVE_FRACTION} of the window (a guess, for callers that don't know the cap).\n   * Clamped so the reserve never exceeds the window. Forwarded to {@link resolveBudget}.\n   */\n  outputReserve?: number\n  /**\n   * The fallback reserve fraction used when `outputReserve` is omitted. Default:\n   * {@link DEFAULT_RESERVE_FRACTION}. Forwarded to {@link resolveBudget}.\n   */\n  reserveFraction?: number\n  /**\n   * Whether to apply the prior-turn thought strip (step 1) at all. Default `true`.\n   *\n   * @remarks\n   * The default is driven by Gemma's model card §3, \"No Thinking Content in History\": thoughts from\n   * previous model turns must not be re-added before the next user turn. This is also pure thrift —\n   * prior-turn reasoning is the highest-volume, lowest-reuse content there is, Gemma or not — so the\n   * default stays `true` even for callers on a different model family; a caller whose model\n   * genuinely benefits from replaying its own prior chain-of-thought (uncommon) can set this `false`\n   * to skip the strip entirely and let every thought flow into the later per-thought budget shed\n   * (step 8) instead.\n   */\n  stripPriorTurnThoughts?: boolean\n  /**\n   * Thought ids to PRESERVE through the prior-turn strip (step 1) — e.g. a planner's synthetic\n   * THIS-TURN plan thought, which is fresh guidance generated for the current request (not prior-turn\n   * chain-of-thought, and not subject to the §3 policy above). Everything else is dropped when\n   * stripping is enabled. Omit to drop every thought when stripping is enabled.\n   */\n  keepThoughtIds?: ReadonlySet<string>\n  /**\n   * The caller's tool-declaration renderer. When supplied, the tools bucket is measured against the\n   * REAL rendered tool-definitions block (e.g. full JSON-Schema per tool) instead of a\n   * `name: description` proxy — the proxy can undercount a schema-heavy tool block by an order of\n   * magnitude relative to what actually gets dispatched. Omit to fall back to the proxy (keeps this\n   * battery usable standalone, without a real tool-rendering pipeline, e.g. in tests).\n   */\n  renderTools?: RenderToolsFn\n  /**\n   * Thought ids that must NEVER be shed for budget (step 8) even when the dispatch is over — the\n   * this-turn scaffolding the model needs to answer at all (e.g. a plan thought + a citation\n   * reinforcement thought). Everything else in the surviving keep-set (per-iteration nudge thoughts,\n   * older synthetic guidance) is sheddable oldest-first when the dispatch still doesn't fit. This is\n   * a SUBSET of `keepThoughtIds`: `keepThoughtIds` decides what survives the prior-turn strip (step\n   * 1); `protectThoughtIds` decides what additionally survives the budget shed (step 8). Omit to make\n   * every surviving thought sheddable.\n   */\n  protectThoughtIds?: ReadonlySet<string>\n  /**\n   * The live dispatch context, so a DYNAMIC (evaluatable) value's token count reflects the string it\n   * will resolve to for THIS dispatch — forwarded as the `ctx` argument to `estimateTokens`. Without\n   * it, a dynamic value is measured at its no-`ctx` fallback size, and the budget can disagree with\n   * what the caller's own battery ships (an under-count, since evaluated content is typically LARGER\n   * than its static form — e.g. an interpolated system prompt). Optional; static content measures\n   * identically with or without it.\n   */\n  renderCtx?: unknown\n  /**\n   * Tool names the caller's CURRENT PLAN has committed to that have NOT yet been called this turn.\n   * These are UNSHEDDABLE by the last-resort tool shed (step 9) until every other tool has already\n   * shed — removing a plan-committed tool from the visible set leaves the model instructed to call a\n   * tool it can no longer see. The protection is bounded: once the tool HAS been called (its result\n   * is already in context) it should be dropped from this set by the caller, so it is never a\n   * permanent floor. Omit to make every visible tool sheddable on equal footing.\n   */\n  protectedToolNames?: ReadonlySet<string>\n  /**\n   * Ranks a tool by last-resort shed priority for step 9 (lower sheds first). Default: a single\n   * generic tier — every tool ranks equally, so the shed proceeds in the order `relevantToolNames`\n   * listed them (a stable sort preserves input order when every rank ties). This battery has no\n   * domain knowledge of which of a caller's tools are cheap-to-lose \"gather\" tools versus\n   * load-bearing \"delivery\" tools, so it does not guess a tiering. A caller WHO DOES have that\n   * knowledge (as the flagship reference agent does — it ranks ~90 known tool names into seven\n   * tiers, sheds its `provide_answer` tool before its core artifact readers, etc.) should inject a\n   * `ShedRankFn` that encodes it; see {@link ShedRankFn} for the contract.\n   */\n  shedRank?: ShedRankFn\n  /**\n   * Decides whether a message is an ephemeral control message (step 6) — re-derived fresh every\n   * dispatch iteration, never persisted, so only the LATEST surviving copy carries live information.\n   * Default: `(m) => m.id.startsWith('__eph-')`, the flagship reference agent's own convention. A\n   * caller with a different (or no) ephemeral-message convention should override this; the default\n   * simply never matches when a caller's ids don't use that prefix, degrading step 6 to a no-op.\n   */\n  isEphemeralMessage?: IsEphemeralMessageFn\n  /**\n   * Decides whether a message is a summarizing strategy's load-bearing running summary (step 7) —\n   * content that stands in for every older turn that strategy folded away, and so must never be shed\n   * like an ordinary old turn even though it renders as the chronologically oldest message. Default:\n   * `(m) => m.id === '__compact-summary'`, the flagship reference agent's own convention for its\n   * paired summarizing (\"compact\") strategy. Callers who never run a summarizing strategy alongside\n   * this battery can ignore this option entirely — the default predicate simply never matches.\n   */\n  isSummaryMessage?: IsSummaryMessageFn\n  /**\n   * How many of the NEWEST this-turn tool-result bodies the newest-N backstop (step 3b) protects\n   * from shedding once ordinary prior-turn shedding is exhausted and the dispatch still doesn't fit.\n   * Default: {@link DEFAULT_THIS_TURN_RESULT_KEEP}.\n   */\n  thisTurnResultKeep?: number\n}\n\nconst defaultIsEphemeralMessage: IsEphemeralMessageFn = (m) => m.id.startsWith('__eph-')\nconst defaultIsSummaryMessage: IsSummaryMessageFn = (m) => m.id === '__compact-summary'\n/** The generic default {@link ShedRankFn}: every tool ranks equally (a single tier), so the\n *  last-resort tool shed (step 9) proceeds in whatever order it is handed — no domain knowledge\n *  assumed. See the `shedRank` option on {@link SubtractToFitOptions}. */\nconst defaultShedRank: ShedRankFn = () => 0\n\nconst renderContent = (v: ContentLike | string): string => {\n  if (typeof v === 'string') return v\n  // Reject the specific failure mode where an opaque object is coerced through the default\n  // Object.prototype renderer. Custom toString implementations remain fully valid, including\n  // ones whose intentional text happens to look like an object tag.\n  const toString = v.toString\n  if (typeof toString !== 'function' || toString === Object.prototype.toString) {\n    throw new TypeError('ContentLike must provide an explicit string renderer')\n  }\n  const rendered = toString.call(v)\n  if (typeof rendered !== 'string') {\n    throw new TypeError('ContentLike renderer must return a string')\n  }\n  return rendered\n}\n\n/**\n * Resolve the per-dispatch INPUT token budget from the ACTIVE model's window: the window minus the\n * room held back for the model's own output. The same call works for a 4K model and a 1M model.\n *\n * @param contextWindow - The active model's context window (input + output share it).\n * @param outputReserve - The EXACT number of tokens to hold back for output — pass the generation\n *   `maxTokens` the model is configured with. When omitted, falls back to `reserveFraction` of the\n *   window (a guess, for callers that don't know the cap). Clamped so the reserve never exceeds the\n *   window.\n * @param reserveFraction - The fallback fraction used when `outputReserve` is omitted. Default:\n *   {@link DEFAULT_RESERVE_FRACTION}.\n */\nexport const resolveBudget = (\n  contextWindow: number,\n  outputReserve?: number,\n  reserveFraction: number = DEFAULT_RESERVE_FRACTION\n): number => {\n  const reserve =\n    outputReserve === undefined\n      ? Math.ceil(contextWindow * reserveFraction)\n      : Math.min(contextWindow, Math.max(0, Math.ceil(outputReserve)))\n  return Math.max(0, contextWindow - reserve)\n}\n\n/**\n * Gemma model card §3 — \"No Thinking Content in History\": thoughts from previous model turns MUST\n * NOT be re-added before the next user turn. Enforced here as a standalone, callable step (not a\n * silent battery-wide flag), because it is also pure thrift: prior-turn reasoning is the\n * highest-volume, lowest-reuse content a working set carries.\n *\n * @remarks\n * `keepIds` is an allow-list of thought ids to PRESERVE — used for e.g. a planner's synthetic\n * THIS-TURN plan thought, which is fresh guidance generated for the current request (NOT prior-turn\n * chain-of-thought, and NOT subject to the §3 policy): it must survive into the next dispatch's\n * prompt so the model follows the plan. Everything else is dropped.\n *\n * `subtractToFit` calls this internally as step 1 (gated by its `stripPriorTurnThoughts` option,\n * default `true`); it is also exported standalone for a caller who wants the strip without running\n * the rest of the pass.\n *\n * @param ws - A working set exposing (at least) a mutable `thoughts` array; mutated in place.\n * @param options - The estimator used to measure the tokens reclaimed by dropped thoughts.\n * @param keepIds - Thought ids to preserve.\n * @returns How many thoughts were dropped, and how many tokens that reclaimed.\n */\nexport const stripPriorTurnThoughts = (\n  ws: Pick<WorkingSet, 'thoughts'>,\n  options: EstimatorOptions,\n  keepIds?: ReadonlySet<string>\n): { dropped: number; tokens: number } => {\n  const encoding = options.encoding ?? DEFAULT_ENCODING\n  const tok = (s: string): number => options.estimateTokens(s, encoding)\n  const kept = keepIds && keepIds.size > 0 ? ws.thoughts.filter((t) => keepIds.has(t.id)) : []\n  const removed = ws.thoughts.filter((t) => !kept.includes(t))\n  const tokens = removed.reduce((n, t) => n + tok(renderContent(t.content)), 0)\n  ws.thoughts = kept\n  return { dropped: removed.length, tokens }\n}\n\n// #region shed\n/**\n * The subtractive pass. Start wide; measure every bucket; then shed lowest-signal first until the\n * dispatch fits the active window's budget — the image (the single biggest hog) goes first when it\n * doesn't fit, then tools the turn doesn't need, the tail of the retrieval ranking, low-value\n * memories, the oldest conversation turns. Each cut is by EVIDENCE (a measured bucket), never a\n * guess. If even the floor (system prompt + newest turn) won't fit, the dispatch REFUSES (`fits:\n * false`) — a bounded refusal beats a truncated, incoherent dispatch.\n *\n * @remarks\n * `options.estimateTokens` is REQUIRED — this battery ships with no bundled tokenizer, so a missing\n * estimator throws {@link @nhtio/adk/batteries/context/exceptions!E_CONTEXT_RESOLVER_MISSING}\n * immediately (naming the option) rather than silently guessing at token counts.\n *\n * @param ws - The working set to subtract in place. Mutated: `thoughts`, `retrievables`,\n *   `memories`, `messages`, `toolCalls`, `image.kept`, and the visible/hidden state of `tools` may\n *   all change.\n * @param contextWindow - The active model's context window.\n * @param relevantToolNames - The names (from `ws.tools.all()`) that should start VISIBLE for this\n *   turn — every other registered tool starts hidden (0 schema tokens, still callable via a\n *   catalog). The last-resort shed (step 9) may hide some of these too.\n * @param options - See {@link SubtractToFitOptions}.\n * @throws {@link @nhtio/adk/batteries/context/exceptions!E_CONTEXT_RESOLVER_MISSING} When\n *   `options.estimateTokens` is not a function.\n */\nexport const subtractToFit = (\n  ws: WorkingSet,\n  contextWindow: number,\n  relevantToolNames: string[],\n  options: SubtractToFitOptions\n): ThriftTrace => {\n  if (typeof options?.estimateTokens !== 'function') {\n    throw new E_CONTEXT_RESOLVER_MISSING(['subtractToFit', 'estimateTokens'])\n  }\n  // Exclude unmeasurable handle-mode retrievables before ANY bucket measurement. In particular,\n  // this must precede ragBefore and the first total() call below: a finite synthetic estimate\n  // cannot be safe for an unbounded artifact, and Infinity would poison total() globally.\n  const unknownRetrievables = ws.retrievables.filter((r) => r.sizeUnknown === true)\n  if (unknownRetrievables.length > 0) {\n    ws.retrievables = ws.retrievables.filter((r) => r.sizeUnknown !== true)\n  }\n\n  const encoding = options.encoding ?? DEFAULT_ENCODING\n  const estimateTokens = options.estimateTokens\n  const renderCtx = options.renderCtx\n  const doStripPriorTurnThoughts = options.stripPriorTurnThoughts ?? true\n  const shedRank = options.shedRank ?? defaultShedRank\n  const isEphemeral = options.isEphemeralMessage ?? defaultIsEphemeralMessage\n  const isCompactSummary = options.isSummaryMessage ?? defaultIsSummaryMessage\n  const thisTurnResultKeep = options.thisTurnResultKeep ?? DEFAULT_THIS_TURN_RESULT_KEEP\n\n  // Use the plain estimator for one-off measurements of rendered strings (tool declarations,\n  // message bodies) that don't carry their own `estimateTokens`. Everything the model sees is\n  // either an `Estimable`/`ContentLike` value or a string produced by the caller's own render*\n  // functions, so this measures the ACTUAL dispatched string, not a proxy.\n  const tok = (s: string): number => estimateTokens(s, encoding)\n\n  // Measure a retrievable the way a caller's own overflow guard does (tally its rendered content\n  // string) but SYNCHRONOUSLY: use the retrievable's OWN `estimateTokens(enc)` when present, which\n  // for an inline-text passage (the common RAG case) resolves immediately. The pass is synchronous\n  // end-to-end, so a reader-backed artifact's async estimate would surface as a Promise here; guard\n  // that (rare for RAG passages, which are inline text) by falling back to the coerced string.\n  const rTok = (r: WorkingRetrievable): number => {\n    if (typeof r.estimateTokens !== 'function')\n      return tok(renderContent(r.content as ContentLike | string))\n    const est = r.estimateTokens(encoding)\n    return typeof est === 'number' ? est : tok(renderContent(r.content as ContentLike | string))\n  }\n\n  // Count a thought's tokens against the live ctx (dynamic content resolves per-ctx; static is\n  // unchanged).\n  const thoughtTok = (t: WorkingThought): number => tokTok(t.content)\n  // Count a `ContentLike`-backed bucket the SAME way a caller's own overflow guard does: resolve it\n  // against the live ctx (`estimateTokens(enc, ctx)`) when the value exposes that method, not its\n  // no-ctx `.toString()` fallback. An EVALUATABLE value (e.g. a system prompt that interpolates\n  // against ctx) expands to a LARGER string at render than its static form, so measuring the static\n  // form under-counts vs. the guard — the pass would then report \"fits\" while the caller's battery\n  // throws on the ctx-resolved prompt. A plain string / value with no `estimateTokens` counts via the\n  // plain `tok()` measurement of its rendered text, unaffected by `ctx`.\n  function tokTok(v: ContentLike | string | undefined | null): number {\n    if (v === undefined || v === null) return tok('')\n    if (typeof v === 'string') return tok(v)\n    if (typeof v.estimateTokens === 'function') return v.estimateTokens(encoding, renderCtx)\n    return tok(v.toString())\n  }\n\n  const budget = resolveBudget(contextWindow, options.outputReserve, options.reserveFraction)\n  const reserve = contextWindow - budget\n  const buckets: BucketTrace[] = []\n\n  const measure = (\n    bucket: string,\n    before: { tokens: number; count: number },\n    after: { tokens: number; count: number },\n    note?: string,\n    ids?: string[]\n  ): void => {\n    buckets.push({\n      bucket,\n      beforeTokens: before.tokens,\n      afterTokens: after.tokens,\n      beforeCount: before.count,\n      afterCount: after.count,\n      note,\n      ids,\n    })\n  }\n\n  // Measured ctx-resolved (tokTok) to match a caller's own overflow guard: the system prompt is\n  // often an EVALUATABLE value (it interpolates against ctx), so its static rendered form under-counts\n  // vs. what the guard sees.\n  const sysTokens = tokTok(ws.systemPrompt)\n  // Standing instructions are a FIXED cost (durable directives, never shed) the guard also counts —\n  // measured once and folded into the total alongside the system prompt so thrift and the guard agree.\n  const siTokens = (ws.standingInstructions ?? []).reduce((n, si) => n + tokTok(si), 0)\n\n  // 1. Thoughts — the prior-turn strip (Gemma §3 + thrift): drop all prior-turn thinking, unless the\n  //    caller has opted out via `stripPriorTurnThoughts: false`.\n  const thoughtsBefore = {\n    tokens: ws.thoughts.reduce((n, t) => n + thoughtTok(t), 0),\n    count: ws.thoughts.length,\n  }\n  const thoughtsDropped = doStripPriorTurnThoughts\n    ? stripPriorTurnThoughts(ws, { estimateTokens, encoding }, options.keepThoughtIds).dropped\n    : 0\n  measure(\n    'thoughts',\n    thoughtsBefore,\n    {\n      tokens: ws.thoughts.reduce((n, t) => n + thoughtTok(t), 0),\n      count: ws.thoughts.length,\n    },\n    !doStripPriorTurnThoughts\n      ? 'prior-turn thought strip disabled by caller (stripPriorTurnThoughts: false)'\n      : thoughtsDropped > 0\n        ? 'dropped prior-turn thinking (kept thoughts preserved)'\n        : 'no prior-turn thinking in history'\n  )\n\n  // 2. Tools — hide everything except the turn's shortlist. Hidden = callable, 0 schema tokens.\n  const allTools = ws.tools.all()\n  // Measure the ACTUAL dispatched tool block: when the caller's renderer is injected, render the\n  // filtered set as ONE block and count that; otherwise fall back to the cheap `name: description`\n  // proxy (can undercount a schema-heavy tool by an order of magnitude vs. what is actually sent).\n  const toolTokens = (names: Set<string>): number => {\n    const subset = allTools.filter((t) => names.has(t.name))\n    if (subset.length === 0) return 0\n    if (options.renderTools) return tok(options.renderTools(subset))\n    return subset.reduce((n, t) => n + tok(`${t.name}: ${t.description ?? ''}`), 0)\n  }\n  // `visibleTools` is MUTABLE — step 2 hides everything except the shortlist, but the LAST-RESORT\n  // tool shed (step 9 below) may hide shortlist tools too when even the leanest context won't fit, so\n  // this set shrinks. `visibleToolTokens()` reads it live, so the running total reflects the current\n  // visible set.\n  const visibleTools = new Set(relevantToolNames)\n  const toolsBefore = {\n    tokens: toolTokens(new Set(allTools.map((t) => t.name))),\n    count: allTools.length,\n  }\n  ws.tools.setHidden(...allTools.map((t) => t.name).filter((n) => !visibleTools.has(n)))\n  measure(\n    'tools',\n    toolsBefore,\n    { tokens: toolTokens(visibleTools), count: visibleTools.size },\n    'hidden tools stay callable via the catalog'\n  )\n\n  // Running total against the budget.\n  const imgTokens = (): number => (ws.image && ws.image.kept !== false ? ws.image.tokenCost : 0)\n  const memTokens = (): number => ws.memories.reduce((n, m) => n + tokTok(m.content), 0)\n  const ragTokens = (): number => ws.retrievables.reduce((n, r) => n + rTok(r), 0)\n  // NOTE: `m.content` already holds the FULL rendered message body — including any artifact-handle /\n  // response-envelope text the caller's battery stored as the content string — so this counts the\n  // real dispatched string, not a proxy. Do NOT \"fix\" this to render handles separately; that would\n  // double-count. Measured ctx-resolved (tokTok) to match the caller's own guard.\n  const msgTokens = (): number => ws.messages.reduce((n, m) => n + tokTok(m.content), 0)\n  const visibleToolTokens = (): number => toolTokens(visibleTools)\n  // Prior-turn (and this-turn) tool RESULTS the caller's battery renders into the prompt.\n  // Pre-measured by the caller so the pass stays synchronous. Historically the single biggest\n  // multi-turn undercount when omitted: accumulated search results / artifact handles push the true\n  // prompt far past what an unmeasured pass would report.\n  const toolCallTokens = (): number => (ws.toolCalls ?? []).reduce((n, c) => n + c.tokenCost, 0)\n  // The SURVIVING thoughts (the guidance keep-set after the step-1 strip) ARE rendered into the\n  // dispatched prompt and counted by a caller's own overflow guard. They MUST be in the running\n  // total, or thrift optimises against a smaller number than the guard checks and reports \"fits\"\n  // while the guard throws.\n  const thoughtTokens = (): number => ws.thoughts.reduce((n, t) => n + thoughtTok(t), 0)\n  const total = (): number =>\n    sysTokens +\n    siTokens +\n    imgTokens() +\n    memTokens() +\n    ragTokens() +\n    msgTokens() +\n    visibleToolTokens() +\n    toolCallTokens() +\n    thoughtTokens()\n\n  const imgBefore = { tokens: ws.image ? ws.image.tokenCost : 0, count: ws.image ? 1 : 0 }\n  const tcBefore = { tokens: toolCallTokens(), count: (ws.toolCalls ?? []).length }\n  const memBefore = { tokens: memTokens(), count: ws.memories.length }\n  const ragBefore = { tokens: ragTokens(), count: ws.retrievables.length }\n  const msgBefore = { tokens: msgTokens(), count: ws.messages.length }\n  if (unknownRetrievables.length > 0) {\n    measure(\n      'retrievables-size-unknown',\n      { tokens: 0, count: unknownRetrievables.length },\n      { tokens: 0, count: 0 },\n      'unmeasurable handle-mode retrievables excluded before ranking or token totals',\n      unknownRetrievables.map((r) => r.id).filter((id): id is string => id !== undefined)\n    )\n  }\n  // The surviving guidance thoughts AFTER the step-1 strip — the starting point for the budget shed\n  // below.\n  const thoughtsShedBefore = { tokens: thoughtTokens(), count: ws.thoughts.length }\n\n  // 3. Image — the biggest single hog. If the set is over budget, drop the image first: media is\n  //    expensive, and thrift weighs it before anything else.\n  if (ws.image && total() > budget) {\n    ws.image.kept = false\n  } else if (ws.image) {\n    ws.image.kept = true\n  }\n  measure(\n    'image',\n    imgBefore,\n    { tokens: imgTokens(), count: ws.image && ws.image.kept !== false ? 1 : 0 },\n    'media is the biggest token hog — weighed and shed first'\n  )\n\n  // 3b. Shed PRIOR-TURN tool results (OLDEST first). Across a multi-turn session these accumulate\n  //     the fastest — every search returns a blob, every catalog/read leaves an artifact handle — and\n  //     a stale prior-turn result is low-reuse: the model already acted on it. Shed oldest→newest\n  //     while over budget.\n  if (ws.toolCalls && ws.toolCalls.length > 0) {\n    // A THIS-turn result is the model's active working set — evicting one it just fetched makes it\n    // re-request the same call (an identical-search loop), so this-turn results are protected FIRST.\n    // Shed oldest PRIOR-turn results (the model already acted on those). Rebuild `ws.toolCalls` =\n    // surviving-prior-turn + kept-this-turn.\n    const thisTurn = ws.toolCalls\n      .filter((c) => c.thisTurn)\n      .sort((a, b) => a.createdAtMs - b.createdAtMs)\n    const priorTurn = ws.toolCalls\n      .filter((c) => !c.thisTurn)\n      .sort((a, b) => a.createdAtMs - b.createdAtMs)\n    while (total() > budget && priorTurn.length > 0) {\n      priorTurn.shift()\n      ws.toolCalls = [...priorTurn, ...thisTurn]\n    }\n    ws.toolCalls = [...priorTurn, ...thisTurn]\n\n    // N-CAP BACKSTOP. If prior-turn results are exhausted and the dispatch STILL won't fit, the\n    // unsheddable mass is accumulated THIS-turn result bodies — a deep read-loop turn (several\n    // searches/reads) piles up real token weight per inlined body. Protecting ALL of them can exceed\n    // the whole window. So cap the protected set to the NEWEST N this-turn results and shed the\n    // OLDEST beyond N, oldest-first — the model has almost certainly moved past the oldest reads, and\n    // the newest (its current focus) is always kept. Never drop the single newest this-turn result:\n    // if even that + the floor won't fit, the dispatch legitimately refuses (window too small).\n    if (total() > budget && thisTurn.length > thisTurnResultKeep) {\n      // thisTurn is oldest→newest; shed from the front (oldest) while over budget and above the keep\n      // floor.\n      while (total() > budget && thisTurn.length > thisTurnResultKeep) {\n        thisTurn.shift()\n        ws.toolCalls = [...priorTurn, ...thisTurn]\n      }\n      ws.toolCalls = [...priorTurn, ...thisTurn]\n    }\n    measure(\n      'toolCalls',\n      tcBefore,\n      { tokens: toolCallTokens(), count: ws.toolCalls.length },\n      'oldest PRIOR-turn results shed first; this-turn results capped to newest N (oldest beyond N shed)'\n    )\n  }\n\n  // 4. Shed the RAG tail (lowest-reranked first — keep the head, the best chunks).\n  const retrievableIdsBefore = ws.retrievables\n    .map((r) => r.id)\n    .filter((id): id is string => id !== undefined)\n  ws.retrievables.sort((a, b) => (b.score ?? 0) - (a.score ?? 0))\n  while (total() > budget && ws.retrievables.length > 0) ws.retrievables.pop()\n  const retrievableIdsAfter = new Set(ws.retrievables.map((r) => r.id))\n  const shedRetrievableIds = retrievableIdsBefore.filter((id) => !retrievableIdsAfter.has(id))\n  measure(\n    'retrievables',\n    ragBefore,\n    { tokens: ragTokens(), count: ws.retrievables.length },\n    'tail of the ranking sheds first; the best chunks stay',\n    shedRetrievableIds\n  )\n\n  // 5. Shed low-value memories next.\n  ws.memories.sort((a, b) => (b.importance ?? 0) - (a.importance ?? 0))\n  while (total() > budget && ws.memories.length > 0) ws.memories.pop()\n  measure('memories', memBefore, { tokens: memTokens(), count: ws.memories.length })\n\n  // 6. Shed the OLDEST EPHEMERAL messages first — per-iteration control-gate directives that are\n  //    re-derived fresh every loop and never persisted. During a multi-iteration turn these pile up\n  //    and are a dominant runaway growth; dropping the stale ones (keep only the LATEST, which\n  //    carries the active directives) is pure win — it reclaims budget without losing real\n  //    conversation. Sort oldest→newest and shed oldest ephemerals while over budget, always keeping\n  //    the most recent ephemeral.\n  ws.messages.sort((a, b) => a.createdAt.toMillis() - b.createdAt.toMillis())\n  let lastEphIdx = -1\n  for (let i = ws.messages.length - 1; i >= 0; i--) {\n    if (isEphemeral(ws.messages[i])) {\n      lastEphIdx = i\n      break\n    }\n  }\n  for (let i = 0; i < ws.messages.length && total() > budget; ) {\n    if (isEphemeral(ws.messages[i]) && i !== lastEphIdx) {\n      ws.messages.splice(i, 1)\n      if (i < lastEphIdx) lastEphIdx-- // index shifted left by the removal\n    } else {\n      i++\n    }\n  }\n  // 7. Then shed the OLDEST conversation turns (keep the newest — always keep >=1). EXCEPT a\n  //    summarizing strategy's running-summary message (see `isSummaryMessage`): such a message is\n  //    often stamped at the epoch so it RENDERS at the head of history, which also makes it the\n  //    \"oldest\" turn — so a naive oldest-first shift would evict it FIRST. That is wrong: the summary\n  //    is load-bearing compaction context (it stands in for every older turn that strategy folded\n  //    away), unsheddable like the system prompt. Dropping it would silently degrade a summarizing\n  //    strategy to \"recent-verbatim-only\", which is not compaction at all. Protect it: shed the\n  //    oldest NON-summary turn instead. (A no-op when the caller runs no summarizing strategy — the\n  //    default `isSummaryMessage` never matches.)\n  //\n  //    ws.messages is sorted oldest→newest. Shed the OLDEST turn each pass, but NEVER the protected\n  //    summary and NEVER the single newest turn. So: consider only NON-summary turns; keep the last\n  //    (newest) of them; shed the oldest of the rest while over budget. When only [summary, newest]\n  //    remain, stop shedding — and if that STILL exceeds budget, the summary is not dropped. The\n  //    total is allowed to stay over budget: step 9 (tools) still runs, then `subtractToFit` returns\n  //    `fits: false` / `refused: true` and the caller's own turn-failure path takes over. That is the\n  //    faithful compaction contract: an unfittable summary should surface as a refusal, not silently\n  //    degrade to summary-less context.\n  while (total() > budget) {\n    const nonSummary = ws.messages.map((m, i) => ({ m, i })).filter((x) => !isCompactSummary(x.m))\n    if (nonSummary.length <= 1) break // only [summary (+ newest)] left — never shed further; refuse instead\n    ws.messages.splice(nonSummary[0].i, 1) // drop the OLDEST non-summary turn\n  }\n  measure(\n    'messages',\n    msgBefore,\n    { tokens: msgTokens(), count: ws.messages.length },\n    'stale ephemeral directives shed first, then oldest turns; protected summary + newest always kept'\n  )\n\n  // 8. Shed surviving GUIDANCE THOUGHTS as a last resort. These are the this-turn keep-set\n  //    (plan/cite + per-iteration nudge thoughts) that survived the step-1 strip — high-signal, so\n  //    shed only after messages. During a multi-iteration livelock the nudge thoughts accumulate here\n  //    and are the tail-end runaway; each is re-derived every iteration, so dropping the OLDEST\n  //    superseded ones is pure win. `protectThoughtIds` (the thoughts the model needs to answer at\n  //    all) is never shed; everything else goes oldest→newest, always keeping the most recent (the\n  //    active nudge). This is the bucket a caller's own guard counts that an earlier, less complete\n  //    pass could be blind to — the accounting that lets thrift actually honour \"the dispatched\n  //    prompt fits\" for thoughts.\n  const isProtectedThought = (t: WorkingThought): boolean =>\n    !!options.protectThoughtIds && options.protectThoughtIds.has(t.id)\n  ws.thoughts.sort((a, b) => a.createdAt.toMillis() - b.createdAt.toMillis())\n  let lastSheddableThoughtIdx = -1\n  for (let i = ws.thoughts.length - 1; i >= 0; i--) {\n    if (!isProtectedThought(ws.thoughts[i])) {\n      lastSheddableThoughtIdx = i\n      break\n    }\n  }\n  for (let i = 0; i < ws.thoughts.length && total() > budget; ) {\n    if (!isProtectedThought(ws.thoughts[i]) && i !== lastSheddableThoughtIdx) {\n      ws.thoughts.splice(i, 1)\n      if (i < lastSheddableThoughtIdx) lastSheddableThoughtIdx-- // index shifted left by the removal\n    } else {\n      i++\n    }\n  }\n  measure(\n    'thoughts-shed',\n    thoughtsShedBefore,\n    { tokens: thoughtTokens(), count: ws.thoughts.length },\n    'stale nudge thoughts shed oldest-first; protected thoughts kept, newest nudge kept'\n  )\n\n  // 9. LAST-RESORT: shed VISIBLE TOOLS. Everything cheaper is already gone and the dispatch still\n  //    won't fit — so the tool schemas (the model's ability to ACT) become a sheddable bucket too,\n  //    rather than an unsheddable floor that deadlocks a tight window. Shed by `shedRank` (lower\n  //    ranks first), keeping `protectedToolNames` to the very end of the queue. A tool shed here is\n  //    HIDDEN (`setHidden` → 0 schema tokens) but stays callable via a catalog if room reappears. Pure\n  //    thrift: shed what does not fit; a caller's own downstream gates (e.g. \"did the required tool\n  //    stay visible?\") yield when their required tool is no longer visible.\n  const toolsShedBefore = { tokens: visibleToolTokens(), count: visibleTools.size }\n  if (visibleTools.size > 0 && total() > budget) {\n    // INVARIANT (the flagship reference agent's own design rule, preserved here as guidance for\n    // callers): a dispatch should overflow ONLY when the irreducible floor (system prompt + newest\n    // turn + output reserve) alone exceeds the window — never because a sheddable tool was left in\n    // place. So the shed drives visible tools toward ZERO. PLANNED-BUT-UNCALLED tools (see\n    // `protectedToolNames`) shed LAST, not never: keeping a plan-required tool visible is preferable\n    // RIGHT UP UNTIL the only alternative is a hard overflow, at which point a degraded-but-delivered\n    // dispatch beats a failed one. Two phases, each rank-ordered: shed non-protected first, then\n    // protected.\n    const nonProtected = [...visibleTools]\n      .filter((n) => !(options.protectedToolNames?.has(n) ?? false))\n      .sort((a, b) => shedRank(a) - shedRank(b))\n    const protectedLast = [...visibleTools]\n      .filter((n) => options.protectedToolNames?.has(n) ?? false)\n      .sort((a, b) => shedRank(a) - shedRank(b))\n    const shedQueue = [...nonProtected, ...protectedLast]\n    const allToolNames = allTools.map((t) => t.name)\n    for (const name of shedQueue) {\n      if (total() <= budget) break\n      visibleTools.delete(name)\n      // setHidden REPLACES the hidden set (any name not passed becomes visible), so pass the\n      // COMPLETE hidden set every time = every registered tool NOT in the surviving visible set.\n      // (visibleToolTokens reads visibleTools, so total() reflects the shed immediately.)\n      ws.tools.setHidden(...allToolNames.filter((n) => !visibleTools.has(n)))\n    }\n  }\n  measure(\n    'tools-shed',\n    toolsShedBefore,\n    { tokens: visibleToolTokens(), count: visibleTools.size },\n    'LAST-RESORT: visible tools shed by rank toward ZERO; protected tools shed last'\n  )\n\n  const totalAfter = total()\n  const fits = totalAfter <= budget\n  const refused = !fits\n\n  return {\n    contextWindow,\n    reserve,\n    budget,\n    totalBefore:\n      sysTokens +\n      siTokens +\n      thoughtsBefore.tokens +\n      toolsBefore.tokens +\n      imgBefore.tokens +\n      tcBefore.tokens +\n      memBefore.tokens +\n      ragBefore.tokens +\n      msgBefore.tokens,\n    totalAfter,\n    fits,\n    refused,\n    buckets,\n  }\n}\n// #endregion shed\n"],"mappings":"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"}