/**
 * window/toolNames — which tools spoke in a stretch of the window.
 *
 * Pattern: Pure functions over messages (no scope, no I/O, no clock).
 * Role:    core/ layer. One implementation of "what is this tool result's
 *          tool called", used by the two places that need the answer for
 *          different reasons:
 *
 *            • the drop notice, which tells the MODEL whose results left, so
 *              it calls the tool again instead of reconstructing an id from
 *              memory (9.57.0);
 *            • `WindowRecord.droppedObservations`, which tells the READER the
 *              same thing, uncapped and unsanitized.
 * Emits:   N/A.
 *
 * ## Why the name is not simply `msg.toolName`
 *
 * It usually is: every path in `stages/toolCalls.ts` that appends a result
 * stamps `toolName` beside `toolCallId`. But `LLMMessage.toolName` is
 * OPTIONAL on the adapter type, so a window seeded from outside this run — a
 * restored conversation written by an older release, a hand-built fixture, a
 * host that speaks the wire shape and nothing more — can carry a result whose
 * only identity is the `toolCallId` it answers. The assistant turn that asked
 * for it names the tool, so the name is recoverable; that recovery is here,
 * once, rather than guessed twice.
 *
 * A result whose name cannot be recovered either way contributes NOTHING. It
 * is not called `'unknown'` and it is not counted: a notice that says a tool
 * called `unknown` lost its result teaches the model a tool name that does
 * not exist, which is the exact failure this file exists to prevent.
 *
 * ## A settled message is not a result at all (9.113.0)
 *
 * When a batch of calls pauses, the resume answers each call after the paused
 * one with a fixed sentence and never runs it (`../stages/toolCalls.ts` ·
 * "── The batch settlement (9.113.0)"). That message has `role: 'tool'` and a
 * `toolName`, and no tool produced it: `LLMMessage.notDispatched` says so, and
 * this file reads that marker rather than the role. So it names nothing, and
 * every reader of the name asks the right question for free: the
 * `'last-tool-result'` pin (`lastToolResult.ts` · `toolResultPinsOf`) is not
 * moved off a tool's real result onto the sentence, the drop notice and
 * `WindowRecord.droppedObservations` do not report a result that never
 * existed, and the closure check (`../stages/callLLM.ts`) does not count the
 * sentence as a re-fetched ground.
 */
import type { LLMMessage } from '../../../provider-contract/types.js';
/**
 * The tool a `role: 'tool'` message came from, or `undefined`. A settled
 * message (`notDispatched`) came from no tool, so it is `undefined` too.
 *
 * @param msg     the message to name
 * @param context where to look for the assistant turn that asked, when the
 *   message does not name the tool itself. Usually the whole window.
 */
export declare function toolNameOfMessage(msg: LLMMessage, context: readonly LLMMessage[]): string | undefined;
/**
 * The tools whose results are in `span`, in FIRST-APPEARANCE order, each named
 * once.
 *
 * First appearance rather than sorted or newest-first because the notice reads
 * as a sentence about what happened, and what happened has an order.
 *
 * @param span    the messages that are leaving
 * @param context where to recover a missing `toolName` from; defaults to the
 *   span itself, which is enough whenever the pair left together (it always
 *   does — a turn is the removal unit, and the pair is one turn)
 */
export declare function droppedToolNames(span: readonly LLMMessage[], context?: readonly LLMMessage[]): readonly string[];
