import type { BrainRetryErrClass, BrainStatus } from "../core/types.js";
import type { ReasoningWireFacts } from "./reasoning.js";
/** Run `fn` with a per-task brain-status sink in scope. ALS propagates it through the async brain calls
 *  inside `fn` (the harness's prompt → brain.stream → connect/retry loop), so {@link emitBrainStatus}
 *  reaches THIS task's sink and nothing else. */
export declare function runWithStatusSink<T>(emit: (s: BrainStatus) => void, fn: () => Promise<T>): Promise<T>;
/**
 * Report a brain-layer liveness status to the active per-task sink, if any. A no-op outside a
 * {@link runWithStatusSink} scope (e.g. compaction's `complete`, or a brain used standalone).
 *
 * HRD-BRN-6: swallow-guarded, like its sibling {@link emitBrainTelemetry} — an ADVISORY frame must never
 * change a brain call's outcome. It could: the emit forwards straight into deployment-supplied code, and
 * the circuit breaker's fast-fail emits the `circuit_open` frame from a void-ed async IIFE BEFORE the
 * error terminal is pushed, so a throwing sink took the whole call down (`result()` pending forever plus
 * an unhandled rejection) instead of costing one status frame. `stream-engine.ts` already wrapped its own
 * call site for this exact reason and states the contract ("an advisory frame must never break a settled
 * call"); the guard belongs HERE so every call site inherits it rather than each remembering.
 */
/**
 * #530 — bind the ACTIVE sink now, for an emit that will happen from a timer callback later. The
 * async-local store propagates through Node's timers, but not through every timer implementation a
 * process may run under (fake clocks in tests replace `setTimeout` outright and run callbacks from
 * their own stack, where `getStore()` is empty). A frame scheduled inside the sink's scope must reach
 * that sink whichever clock fires it, so the scheduler captures the store here and the callback emits
 * through the bound function. Same swallow guard and the same retryAtMs stamp as {@link emitBrainStatus};
 * a no-op function when no sink is active.
 */
export declare function bindBrainStatusEmitter(): (status: BrainStatus) => void;
export declare function emitBrainStatus(status: BrainStatus): void;
/**
 * Silent-fallback telemetry (C1/C4/C5/C6) — the brain→runner TELEMETRY channel, a
 * SECOND ALS sink parallel to the status one. Statuses are user-facing liveness frames (wire
 * `status` events); telemetry is operator-facing fallback accounting the Runner bridges to trace
 * events (`brain.failover` / `breaker.transition` / `brain.retry` / `vision.placeholder` / `brain.echo_dropped`). Kept
 * separate so widening telemetry never bloats the shell-visible status vocabulary. Same contract:
 * fire-and-forget, no-op outside a {@link runWithBrainTelemetry} scope, MUST NOT throw.
 */
export type BrainTelemetry = {
    kind: "failover";
    servedIndex: number;
    total: number;
    errorCode?: string;
} | {
    kind: "breaker";
    key: string;
    phase: "open" | "half-open" | "closed";
    failures: number;
}
/** A retried provider call. `errClass` is the same closed bucket the user-facing status frame carries
 *  (so an operator reading traces and a user reading a progress line agree on why); `nextDelayMs` is
 *  the backoff actually about to be slept — 0 for the immediate re-sends that take no backoff. Both
 *  optional so a caller that has no verdict to report is not forced to invent one. */
 | {
    kind: "retry";
    attempt: number;
    phase: "connect" | "midstream";
    errClass?: BrainRetryErrClass;
    nextDelayMs?: number;
} | {
    kind: "vision_placeholder";
    count: number;
}
/** PDF read: a `document` content block was substituted with a text placeholder because the serving
 *  API/model cannot take native document input (openai brain always; anthropic brain when the model
 *  declares no vision). Silent quality loss → frame (same C4 discipline as vision_placeholder). */
 | {
    kind: "document_placeholder";
    count: number;
}
/** A provider echo field ({@link import("./errors.js").PROVIDER_ECHO_SHAPE}) refused by its shape: the value was dropped
 *  and the field is absent. One event per provider response per field. */
 | {
    kind: "echo_dropped";
    field: "requestId" | "responseModel" | "apiErrorCode";
};
/** Run `fn` with a per-task brain-telemetry sink in scope (Runner-side; compose with runWithStatusSink). */
export declare function runWithBrainTelemetry<T>(emit: (t: BrainTelemetry) => void, fn: () => Promise<T>): Promise<T>;
/** Report a brain-layer fallback/telemetry event to the active per-task sink, if any. */
export declare function emitBrainTelemetry(t: BrainTelemetry): void;
/**
 * Run `fn` with a per-task REASONING-WIRE-FACTS sink in scope — the THIRD brain→runner ALS channel,
 * same decoupling contract as its two siblings (no brain-interface field, no per-call option, no-op
 * outside the scope, an emit must never change a call's outcome).
 *
 * What it carries and WHY it is a channel rather than a runner-side computation: the reporting
 * resolver's cap-wins arm ({@link import("./reasoning.js").budgetCapSkipsThinking}) needs facts that
 * belong to ONE outgoing request — the output cap that actually reached the wire and whether it was a
 * HARD bound. The runner's per-leg eager mint cannot know them without re-deriving the adapter's own
 * cap precedence chain (engine override > caller `options.maxTokens` > `model.maxTokens` >
 * brain-construction default) — a SECOND source of truth that a deployment's own brain, a
 * construction-time default or a per-attempt engine override would silently desync. So the MINTER
 * reports the facts it judged — the law `SSERequest.outputCapTokens` already states for the overflow
 * recovery ("what the adapter actually put on the wire") — and the resolver stays one predicate.
 *
 * REVOKED ON SETTLEMENT, unlike its two siblings, because this sink WRITES to a seat later read into
 * a returned value instead of pushing an advisory frame. `AsyncLocalStorage.run` does not revoke the
 * store from async resources created inside `fn`: a brain call the engine ABANDONED (the guardrail's
 * whole purpose) keeps the scope alive in its own continuation and can call `observe` long after the
 * task settled — mutating a resolution whose `TaskResult` was already assembled and handed back. The
 * scope therefore carries a liveness flag cleared when `fn`'s promise settles, which is also the
 * "freeze before result assembly" boundary: assembly runs after the brain-driving call resolves, so
 * a report that could still land is exactly one that arrives before the freeze.
 *
 * Passing a NO-OP `observe` is the documented way to SHIELD a nested internal brain call (compaction
 * summary, side query): it installs a fresh innermost scope for the duration, so the inner call's
 * reports are swallowed instead of restating the outer leg's posture — the same shape the status sink
 * uses for the same reason ("background/internal brain calls are not surfaced").
 */
export declare function runWithReasoningWireFacts<T>(observe: (f: ReasoningWireFacts) => void, fn: () => Promise<T>): Promise<T>;
/**
 * Report the reasoning wire facts of the request the engine has SELECTED to send, to the active
 * per-task sink, if any.
 *
 * Call it from the adapter's `onCommitted` hook, never from `buildRequest`: the context-overflow
 * recovery builds candidate requests speculatively and may decline them, and a declined candidate's
 * facts would otherwise be reported against a request that was never sent (the exact hazard
 * `onCommitted` exists for).
 *
 * Precisely what that buys, since the hook's own summary ("becomes the one that is sent") is a shade
 * stronger than its position: the engine calls it immediately after choosing a request and BEFORE the
 * attempt loop's abort check and `doFetch`, so a call aborted before its first connect can still have
 * reported. The distinction that matters here is nonetheless the one the hook does guarantee — a
 * DECLINED candidate never reports, so the facts always belong to the request the adapter's decision
 * was made about. The residual (a selected-but-never-connected request on an aborting leg) describes
 * the posture that leg was about to run under, and is not worth moving a hook three adapters share
 * their own diagnostics attribution on.
 *
 * Fire-and-forget and swallow-guarded like its siblings — an observability fact must never turn a
 * settled brain call into a failure — and inert once its scope has settled (see
 * {@link runWithReasoningWireFacts}).
 */
export declare function reportReasoningWireFacts(facts: ReasoningWireFacts): void;
