/**
 * Thinking templates — chat-bubble surface (separate from commentary).
 *
 * Audience split:
 *   • COMMENTARY (`commentaryTemplates`)  — third-person, every moment,
 *                                            shown in Lens panel. Audience:
 *                                            developer / observer.
 *   • THINKING (this file)                — first-person, mid-call only,
 *                                            shown in chat bubble. Audience:
 *                                            end user chatting with the agent.
 *
 * The thinking surface is a tiny finite state machine driven purely by
 * the event log:
 *
 *      ┌──────────┐  llm.start, no tools yet
 *  ────┤  idle    ├────────────────────────────► "Thinking…"
 *      └──────────┘
 *
 *      ┌──────────┐  stream.token chunks accumulate
 *  ────┤streaming ├────────────────────────────► "{{partial}}"
 *      └──────────┘
 *
 *      ┌──────────┐  tool.start, no tool.end yet
 *  ────┤   tool   ├────────────────────────────► "Working on `weather`…"
 *      └──────────┘                               (or per-tool override)
 *
 *      ┌──────────┐  tool_progress, still no tool.end
 *  ────┤   tool   ├────────────────────────────► "Looking at your screen…"
 *      └──────────┘  (same state, newer line)     (or the generic report)
 *
 *      ┌──────────┐  pause.request, no resume yet
 *  ────┤  paused  ├────────────────────────────► "Waiting on you: …"
 *      └──────────┘
 *
 *      (null)        run done / between calls   → bubble hidden
 *
 * The selector returns the CURRENT state by walking the event log;
 * the renderer maps state → final string by looking up the template.
 *
 * Per-tool templates: consumers can ship `tool.<toolName>` keys
 * (e.g. `tool.weather: 'Looking up the weather…'`) which the renderer
 * prefers over the generic `tool` template. Lets each tool have its
 * own first-person status without per-tool plumbing.
 *
 * MID-CALL REPORTS (9.54.0). `ctx.progress(payload)` files
 * `stream.tool_progress` from inside a still-running tool call. Through
 * 9.53.0 that event reached the record and stopped there: nothing
 * projected it onto the surface a person watches, so consumers hand-rolled
 * a side channel for the live middle of a long call. The `tool` state now
 * consumes it — same state, newer line — and the DISPLAY CONTRACT is
 * deliberately narrow, because `payload` is author-defined `unknown`:
 *
 *   · a top-level string field named `message` is shown VERBATIM
 *     (trimmed; cut at {@link PROGRESS_MESSAGE_LIMIT} characters, and the
 *     cut is always stated). `message` is the word MCP's own progress
 *     notification uses, so a tool already speaking that protocol needs no
 *     second vocabulary.
 *   · anything else — no `message`, a non-string one, an empty one — gets
 *     the generic line: the tool's name, that it reported, and how many
 *     times. NEVER a pretty-printed dump of the author's payload: a status
 *     line is prose, and prose that quotes a JSON blob is the field-dump
 *     law broken in public.
 *
 * The structured payload rides on to the record untouched either way. One
 * `ctx.progress` call, two honest faces.
 */
import type { AgentfootprintEvent } from '../../../events/registry.js';
/** The four mid-call states a chat bubble might render. */
export type StatusKind = 'idle' | 'tool' | 'streaming' | 'paused';
/**
 * What the selector returns. The chat-bubble consumer feeds this into
 * the renderer to get the final string.
 */
export interface StatusState {
    readonly state: StatusKind;
    /** Vars for `{{name}}` substitution in the matched template. */
    readonly vars: Readonly<Record<string, string>>;
    /** When `state === 'tool'`, the resolving toolName. The renderer
     *  uses this to look up `tool.<toolName>` before the generic `tool`. */
    readonly toolName?: string;
}
/** Flat template map. Keys: state kinds + per-tool overrides. */
export type StatusTemplates = Readonly<Record<string, string>>;
/** Render context — what the consumer's app config injects. */
export interface StatusContext {
    /** Active actor's name. Substituted as `{{appName}}` in templates. */
    readonly appName: string;
}
/**
 * Bundled English defaults. Override in the agent config via
 * `.thinkingTemplates({...})`. Per-tool overrides go via
 * `tool.<toolName>` keys.
 */
export declare const defaultStatusTemplates: StatusTemplates;
/**
 * How much of a tool author's `message` one status line carries before it is
 * cut. A status line lives in a chat bubble; past ~120 characters it stops
 * being a status and starts being a paragraph.
 *
 * Truncation is always STATED, never silent — the line says how much it cut,
 * the same rule the analyst-view humanizer keeps. A message that legitimately
 * ends in an ellipsis must stay distinguishable from one we shortened.
 */
export declare const PROGRESS_MESSAGE_LIMIT = 120;
/**
 * The tool author's `message`, ready to show — or `null` when this report had
 * nothing sayable and the generic line should stand instead.
 *
 * Deliberately strict, and the strictness is the contract:
 *
 *   · the payload must be a plain object with a top-level `message` STRING.
 *     A bare string payload is not a `message` — `ctx.progress('…')` is a
 *     valid report, but it is the author's data, not a sentence they asked us
 *     to show a person. Wrapping it (`ctx.progress({ message: '…' })`) is the
 *     one-word opt-in, and it keeps a single rule to document.
 *   · an empty or whitespace-only `message` is not a sentence. It falls to the
 *     generic line rather than blanking the bubble mid-call.
 *
 * Nothing here reads any other field. Guessing at `done`/`total`/`percent`
 * would put words in the tool's mouth: one tool's `total` is hops, the next
 * one's is bytes, and a status line that says "3 of 12" about the wrong unit
 * is worse than one that says nothing.
 */
export declare function progressMessageOf(payload: unknown): string | null;
/**
 * Derive the current thinking state from the event log.
 *
 * Single forward walk that tracks "active" state for each domain:
 *   • pause       — set on pause.request, cleared on pause.resume
 *   • tool calls  — a call joins the in-flight map on tool.start and leaves
 *                   it on ITS OWN tool.end (matched by `toolCallId`), so two
 *                   parallel calls cannot close each other. Each in-flight
 *                   call also carries its own progress tally (9.54.0).
 *   • llm         — set on llm.start, cleared on llm.end
 *
 * Priority order (highest first):
 *
 *   1. ACTIVE PAUSE wins. When the agent is waiting on the human,
 *      that's what the chat should show — not the underlying tool
 *      that triggered the pause.
 *   2. AN IN-FLIGHT TOOL CALL — the LLM said "use a tool" and the tool is
 *      running. Show "Working on `<toolName>`…", or, once that call has
 *      reported, what it reported.
 *   3. ACTIVE LLM — call in flight. Show streaming tokens if any
 *      arrived, otherwise "Thinking…".
 *   4. Otherwise null (bubble hidden).
 *
 * WHICH CALL THE LINE IS ABOUT, when several run in parallel: the one with
 * the most recent `tool_progress`, and only if none of them has reported, the
 * most recently STARTED. A report is the newest evidence of what is actually
 * happening, and a surface that showed a silent call while a reporting one
 * had something to say would be choosing the less informative truth. Two
 * chatty parallel calls therefore alternate on the line, each verbatim, in the
 * order their reports landed — which is what a person watching them wants.
 *
 * Pure projection. Forward walk is O(n); a closing event correctly
 * cancels its matching opener so a completed tool.start/tool.end
 * pair leaves the state quiescent.
 */
export declare function selectStatus(events: readonly AgentfootprintEvent[]): StatusState | null;
/**
 * Resolve the matched template + substitute vars.
 *
 * Each state resolves a LADDER of candidate keys, most specific first, and
 * takes the first one the merged template map defines:
 *
 *   | the state                          | ladder                                                              |
 *   |------------------------------------|---------------------------------------------------------------------|
 *   | tool, reported with a `message`    | `tool.<name>.progress` → `tool.progress` → `tool.<name>` → `tool`     |
 *   | tool, reported without one         | `tool.<name>.progress.generic` → `tool.progress.generic` → `tool.<name>` → `tool` |
 *   | tool, no report yet                | `tool.<name>` → `tool`                                                |
 *   | anything else                      | the state's own name                                                  |
 *
 * The ladder falls THROUGH to the plain tool keys on purpose. A consumer who
 * shipped a curated `tool.weather` line and does not want it interrupted
 * deletes `tool.progress.generic` from their map and keeps it; a consumer who
 * ships a partial map that predates 9.54.0 keeps rendering exactly what it
 * rendered before, mid-call reports and all. Nothing here can blank a bubble
 * that used to have a line in it.
 *
 * Missing template keys return null rather than the empty string —
 * keeps the contract honest (consumer can detect "no template" and
 * fall back to its own default).
 */
export declare function renderStatusLine(state: StatusState | null, ctx: StatusContext, templates?: StatusTemplates): string | null;
