/**
 * LLMCall — the leaf primitive for a single LLM invocation (no tools).
 *
 * Pattern: Builder (GoF) → produces a Runner backed by a footprintjs FlowChart.
 *
 * Chart shape — outer client wrapper around an inner llm-subflow:
 *
 *     Client → sf-llm-call → loopTo(client)
 *
 *   Outer `Client` stage:
 *     - First visit: receives args, writes userMessage to scope.
 *     - Second visit (after the loop completes): $break()s with
 *       scope.answer as the chart's TraversalResult.
 *
 *   Inner `sf-llm-call` subflow (drill-down view):
 *     Initialize → sf-system-prompt → sf-messages → call-llm
 *          → [sf-thinking if handler]  → extract-final
 *
 *   NO `sf-tools` slot — LLMCall has no tools by design (that's Agent's
 *   territory). Atomic LLMCall's lens chart is a clean 3-node top-level
 *   view (Client + LLM + loop edge) that drills into the real flowchart
 *   below.
 *
 *   Loop semantics: LLMCall is one-shot. The loop fires once; the
 *   second Client visit immediately breaks. The shape is identical to
 *   chat-mode (future): swap `$break()` for `pause()` and the same
 *   chart supports multi-turn conversation.
 *
 * Slot subflows write convention-keyed injections observed by
 * ContextRecorder. The call-llm stage typedEmits stream.llm_start
 * and stream.llm_end observed by StreamRecorder. When a
 * `ThinkingHandler` resolves for the provider, `sf-thinking` mounts
 * automatically (auto-wired by provider.name — same convention Agent
 * uses).
 *
 * Emits (through internally-attached recorders):
 *     agentfootprint.stream.llm_start / llm_end
 *     agentfootprint.context.injected / slot_composed
 *     agentfootprint.stream.thinking_end (when sf-thinking mounted)
 */
import { type FlowchartCheckpoint, type StructureRecorder } from 'footprintjs';
import type { RunOptions } from './runner.js';
import type { GroupMetadata, GroupTranslator } from './translator.js';
import type { RunnerPauseOutcome } from './pause.js';
import type { LLMProvider, PricingTable } from '../provider-contract/types.js';
import { RunnerBase } from './RunnerBase.js';
export interface LLMCallOptions {
    readonly provider: LLMProvider;
    /** Human-friendly name shown in events/metrics. Default: 'LLMCall'. */
    readonly name?: string;
    /** Stable id used for topology + events. Default: 'llm-call'. */
    readonly id?: string;
    /** Model to request from the provider. */
    readonly model: string;
    /** Optional sampling temperature. */
    readonly temperature?: number;
    /** Optional max output tokens. */
    readonly maxTokens?: number;
    /**
     * Per-slot context budgets, in characters (8.11.0). The LLMCall twin of
     * `AgentOptions.contextBudget` — two slots here, since an LLMCall has no
     * tools slot.
     *
     * Each slot warns (and emits `agentfootprint.context.budget_pressure`) when
     * it composes over its budget. **Nothing is truncated** — the full content
     * still reaches the LLM; the budget is a signal, not a limiter. Defaults:
     * `systemPrompt` 4000, `messages` 10000.
     */
    readonly contextBudget?: {
        readonly systemPrompt?: number;
        readonly messages?: number;
    };
    /**
     * Record the ASSEMBLED system prompt on the LLM call (9.50.0). The LLMCall
     * twin of `AgentOptions.recordSystemPrompt` — same field, same contract,
     * same default. **Opt-in, default OFF**: when `true`,
     * `agentfootprint.stream.llm_start` carries `systemPromptText`, the joined
     * prompt verbatim as sent. PRIVACY: with the dial on, the full prompt rides
     * into every recorder, sink and persisted recording — off, only
     * `systemPromptChars` (the length) is on the record.
     */
    readonly recordSystemPrompt?: boolean;
    /**
     * Mint a receipt on the call (9.91.0). Default ON — the LLMCall twin of
     * `AgentOptions.recordReceipt`, same field, same contract, same default.
     *
     * A receipt is the fingerprint of what the model was actually handed,
     * committed at the call so a reader can check the rebuilt view against it.
     * `false` declines it, for the reason the agent's switch exists: the mint is
     * a SHA-256 per system piece, per message and per tool schema, plus one
     * commit-log value. Declining does not make the log unreadable — `servedAt`
     * still rebuilds the view; what is gone is the witness, and `servedAt` says
     * so with the same gap a pre-9.88 recording raises.
     *
     * @example decline the receipt in a bulk eval loop
     *   new LLMCall({ provider, model, recordReceipt: false })
     */
    readonly recordReceipt?: boolean;
    /**
     * Pricing adapter. When set, LLMCall emits `agentfootprint.cost.tick`
     * after every LLM response with per-call and cumulative USD. Run-scoped
     * — the cumulative resets on each `.run()`.
     */
    readonly pricingTable?: PricingTable;
    /**
     * Cumulative USD budget per run. When provided along with `pricingTable`,
     * LLMCall emits `agentfootprint.cost.limit_hit` with `action: 'warn'`
     * the first time cumulative USD crosses the budget. Execution continues
     * — consumers choose whether to abort by listening to the event.
     *
     * The object form `{ usd, onExceed }` is accepted for symmetry with `Agent`,
     * but `onExceed` must be `'warn'` here: halting means "stop at the next
     * iteration boundary", and one call has no next boundary. `'halt'` is
     * refused at build rather than silently ignored.
     */
    readonly costBudget?: number | {
        readonly usd: number;
        readonly onExceed: 'warn' | 'halt';
    };
    /**
     * Optional build-time recorders threaded into footprintjs's
     * `flowChart()` factory. Each recorder observes per-node build
     * events (`onStageAdded` / `onSubflowMounted` / etc.) for this
     * LLMCall's internal chart (Initialize + slot mounts + CallLLM). When
     * omitted, no build-time observation is wired up.
     */
    readonly structureRecorders?: readonly StructureRecorder[];
    /**
     * Optional per-COMPOSITION translator (UI-agnostic). See
     * `core/translator.ts`. When attached, `runner.getUIGroup()` invokes
     * it with the LLMCall's `GroupMetadata` (kind `'LLMCall'`, id, name,
     * empty `members[]`, plus `extra.slots` with the three slot ids —
     * `system-prompt`, `messages`, `tools` — so Lens can render the slot
     * cards inside an LLMCall card without inspecting `buildTimeStructure`).
     * Returns `undefined` when omitted.
     */
    readonly groupTranslator?: GroupTranslator;
}
export interface LLMCallInput {
    readonly message: string;
}
export type LLMCallOutput = string;
export declare class LLMCall extends RunnerBase<LLMCallInput, LLMCallOutput> {
    readonly name: string;
    readonly id: string;
    private readonly provider;
    private readonly model;
    private readonly temperature?;
    private readonly maxTokens?;
    private readonly systemPromptValue;
    private readonly pricingTable?;
    /** Normalized at construction: a bare number is `{ usd, onExceed: 'warn' }`. */
    private readonly costBudget?;
    /** Per-slot character budgets (8.11.0). Absent keys keep the slot default. */
    private readonly contextBudget?;
    /** `LLMCallOptions.recordSystemPrompt` (9.50.0) — opt-in, default OFF. */
    private readonly recordSystemPromptValue;
    /** `LLMCallOptions.recordReceipt` (9.91.0) — opt-OUT, default ON. */
    private readonly recordReceiptValue;
    private readonly structureRecorders?;
    private readonly groupTranslator?;
    /** The provider's DECLARED handler, read at construction (same as Agent —
     *  see thinkingHandlerFor). When undefined, sf-thinking is NOT mounted and
     *  the chart has zero thinking overhead (build-time conditional mount). */
    private readonly thinkingHandler?;
    private currentRunContext;
    constructor(opts: LLMCallOptions, systemPromptValue: string);
    static create(opts: LLMCallOptions): LLMCallBuilder;
    protected getGroupTranslator(): GroupTranslator | undefined;
    /** LLMCall has no nested-runner members (slots are subflows of
     *  the LLMCall's own chart, not Runner instances). The slot ids
     *  are surfaced via `extra` so Lens can render the slot cards
     *  inside an LLMCall card without inspecting `buildTimeStructure`.
     *
     *  TWO slots only — LLMCall does not have tools (that's Agent's
     *  affordance). Atomic LLMCall renders as a clean 2-pill card in
     *  collapsed (top-level) view. */
    protected buildUIGroupMetadata(): GroupMetadata;
    run(input: LLMCallInput | string, options?: RunOptions): Promise<LLMCallOutput | RunnerPauseOutcome>;
    resume(checkpoint: FlowchartCheckpoint, input?: unknown, options?: RunOptions): Promise<LLMCallOutput | RunnerPauseOutcome>;
    private createExecutor;
    private finalizeResult;
    private buildChart;
}
/**
 * Tiny fluent builder. Validates required fields at build() time.
 */
export declare class LLMCallBuilder {
    private readonly opts;
    private systemPromptValue;
    /** Whether `.system()` has been called — see the refusal below for why the
     *  flag exists separately from the value. */
    private systemPromptSet;
    constructor(opts: LLMCallOptions);
    /**
     * Set the system prompt. Once per call — a second `.system()` used to
     * REPLACE the first in silence, so the instructions written first were
     * never sent and nothing said so. Join the parts yourself and pass one
     * string.
     */
    system(prompt: string): this;
    build(): LLMCall;
}
