/**
 * window/lastToolResult — the last thing each tool said, and why the window
 * keeps it.
 *
 * Pattern: One pure function over the window (no scope, no I/O, no clock).
 * Role:    core/ layer. Feeds the refusal engine, which is what actually
 *          keeps these turns in the window (see turns.ts,
 *          `'last-tool-result'`). Sibling of currentRequest.ts, and kept
 *          apart from it for the same reason: "what did the person ask for"
 *          and "what has the agent just seen" are different questions.
 * Emits:   N/A.
 *
 * ## Why this exists
 *
 * Measured, in a context-gap audit over real recorded runs. An agent drove a
 * screen through tools. A `whats_here` result — about 5,800 characters —
 * carried the list of valid ids it had to act on. Under
 * `slidingWindow({ keepRecentTurns: 2 })` that result survived roughly two
 * iterations, because segmentation makes each assistant/tool_result PAIR one
 * turn. The 9.55.0 anchor kept the REQUEST undroppable, so the model still
 * knew what it had been asked to do — and no longer had the evidence to do
 * it. It assembled a plausible id out of an entity name it remembered plus
 * the shape of an id it had used earlier, and was refused. In one archived
 * run the final answer to the person named a host that appears in no tool
 * result at all.
 *
 * The framework evicted the evidence and kept the task. This is the other
 * half of 9.55.0: **for each tool the agent is using, keep that tool's most
 * recent result** — until the agent calls that tool again, or the person asks
 * something new.
 *
 * ## What is pinned, exactly, and why it cannot grow
 *
 * One pin per tool NAME, always the LATEST result, superseded the moment that
 * tool answers again. So the candidate space is the TOOL ROSTER, not the
 * transcript: a loop that calls three tools forty times has three candidates,
 * not forty. Three further bounds compose on top:
 *
 *   • **deduped by turn** — a parallel batch answered in one assistant turn is
 *     ONE turn, so it costs one slot however many tools were in it;
 *   • **capped** — `keepLastToolResults` (default 2) is the ceiling, applied
 *     in `planRemoval` where the keep window is known, so a pin that is
 *     already inside `keepRecentTurns` costs nothing at all;
 *   • **anchored** — nothing at or before the CURRENT REQUEST is pinnable, so
 *     a new user turn releases the whole previous loop for free.
 *
 * Incompressible floor: 1 request + N pins + `keepRecentTurns` turns,
 * independent of tool count, iteration count and run length.
 *
 * ## What it deliberately gets wrong
 *
 * The pin is CONTENT-BLIND. It keeps a tool's LAST result, which may be a
 * one-word acknowledgement while the load-bearing screen dump was the call
 * before. Two slots absorb the common case; nothing eliminates it. That is
 * the honest price of a bound that is a fact about the tool roster rather
 * than a guess about content — and a guess about content is what this library
 * refuses to make everywhere else.
 *
 * Nor does the framework truly know "the tool the model is driving". This
 * approximates it with "every tool that has spoken since the request, latest
 * result each, newest first under a cap". A heuristic that PINS bills its
 * error every iteration, which is why the cap is small and the record names
 * what it kept.
 */
import type { LLMMessage } from '../../../provider-contract/types.js';
import type { Turn } from './turns.js';
/** One turn the pin holds, and what holding it costs. */
export interface ToolResultPin {
    /** The tool whose latest result is in this turn. */
    readonly toolName: string;
    /** Index of the turn in this iteration's segmentation. */
    readonly turnIndex: number;
    /** Index of the turn's first message in the window. */
    readonly messageIndex: number;
    /**
     * Content characters of the WHOLE turn — the assistant's call and its
     * results leave together, so the turn is what the pin actually holds.
     */
    readonly chars: number;
}
/**
 * The turns holding each tool's most recent result, NEWEST FIRST.
 *
 * Newest first because that is the order the ceiling is spent in: when more
 * tools have spoken than there are slots, the ones the agent used most
 * recently keep theirs.
 *
 * @param turns   the window's turn segmentation
 * @param history the window itself, for recovering a name from the assistant
 *   call when a result does not carry one
 * @param after   index of the CURRENT REQUEST, or `-1` when the window holds
 *   none. Nothing at or before it is pinnable: results gathered for an
 *   earlier request are ordinary history, and this is what makes a new user
 *   turn release the whole previous loop without a line of code
 */
export declare function toolResultPinsOf(turns: readonly Turn[], history: readonly LLMMessage[], after?: number): readonly ToolResultPin[];
