import type { Agent } from '../agent/index.js';
import type { AgentThreadSubscription } from '../agent/types.js';
import type { RequestContext } from '../request-context/index.js';
import type { PublicSchema } from '../schema/index.js';
import type { TaskItemSnapshot } from './tools.js';
import type { HarnessDisplayState, HarnessEvent, HarnessMessage, HarnessMode, HarnessRequestState, HarnessThread, TokenUsage, ToolCategory } from './types.js';
/**
 * Minimal persistence surface the Session uses to read and write per-thread
 * settings (mode id, per-mode model id, …). The Harness backs this with thread
 * metadata; when no storage is configured it is absent and the Session keeps
 * its state purely in memory.
 */
export interface ThreadSettingsStore {
    /** Read a setting for the active thread, or undefined when unset/unavailable. */
    get(key: string): Promise<unknown>;
    /** Persist a setting for the active thread (no-op when storage is unavailable). */
    set(key: string, value: unknown): Promise<void>;
}
/**
 * Owns the session's identity: the memory `resourceId` and the active
 * `threadId` this session reads and writes under. Together they form the memory
 * binding (`{ thread, resource }`) every run uses. In a multi-user host one
 * Harness serves many sessions, so this identity — "whose session is this, and
 * which thread is it on" — belongs to the Session, not the Harness.
 *
 * `defaultResourceId` is the resourceId the session started with; switching to a
 * different resource (e.g. impersonation, or browsing another user's threads)
 * updates the current resourceId while the default is retained so the session
 * can return to its own identity.
 *
 * The active thread the session is bound to lives on {@link SessionThread}, not
 * here — identity is the stable "who", the thread is the navigational "where".
 */
export declare class SessionIdentity {
    #private;
    constructor({ resourceId }: {
        resourceId: string;
    });
    /** The resourceId the session currently reads/writes under. */
    getResourceId(): string;
    /** The resourceId the session started with. */
    getDefaultResourceId(): string;
    /** Point the session at a different resourceId (the default is unchanged). */
    setResourceId({ resourceId }: {
        resourceId: string;
    }): void;
}
/**
 * The shared-host storage surface the Session's thread domain leverages to read
 * and write threads. The Harness backs this with its memory storage (mapping raw
 * storage rows to {@link HarnessThread}/{@link HarnessMessage}); when no storage
 * is configured the handle is absent and the data methods degrade gracefully
 * (empty lists, undefined settings, no-op writes).
 *
 * This is a gateway to shared infrastructure — not a callback into Harness
 * orchestration. The Session owns the thread-domain logic; the host owns the DB.
 */
export interface ThreadDataStore {
    /** List threads for a resource (or all resources), already mapped + filtered of forked subagents unless asked. */
    listThreads(input: {
        resourceId?: string;
        includeForkedSubagents?: boolean;
    }): Promise<HarnessThread[]>;
    /** Fetch a single thread by id, or null when it doesn't exist. */
    getById(input: {
        threadId: string;
    }): Promise<HarnessThread | null>;
    /** List messages for a thread, newest-`limit` (returned oldest-first) or all. */
    listMessages(input: {
        threadId: string;
        limit?: number;
    }): Promise<HarnessMessage[]>;
    /** The first user message for each given thread id. */
    firstUserMessages(input: {
        threadIds: string[];
    }): Promise<Map<string, HarnessMessage>>;
    /** Read a value from a thread's metadata. */
    getMetadata(input: {
        threadId: string;
        key: string;
    }): Promise<unknown>;
    /** Write a value into a thread's metadata. */
    setMetadata(input: {
        threadId: string;
        key: string;
        value: unknown;
    }): Promise<void>;
    /** Delete a value from a thread's metadata. */
    deleteMetadata(input: {
        threadId: string;
        key: string;
    }): Promise<void>;
}
/**
 * Owns the session's thread domain: the navigational binding (which thread the
 * session is currently on) plus the data reads/queries scoped to it. `null`
 * until the session is bound (a thread is created, switched to, or reacquired on
 * startup); switching/deleting updates it.
 *
 * In the multi-user model each session has its own current thread and reads its
 * own threads, while the Harness host shares storage, the thread lock, and the
 * event bus. So the binding + data queries are per-session and live here; the
 * session leverages the host's storage via an injected {@link ThreadDataStore}.
 * Lifecycle *transitions* (create/switch/clone/delete) remain host machinery
 * because they drive the shared event bus and rebind the shared agent stream.
 */
export declare class SessionThread {
    #private;
    constructor(getResourceId: () => string);
    /**
     * Attach the shared-host storage gateway the thread domain reads/writes
     * through. The Harness calls this once storage is available; without it the
     * data methods degrade gracefully.
     */
    connect(store: ThreadDataStore | undefined): void;
    /** The active thread id, or null when the session is not bound to a thread. */
    getId(): string | null;
    /** Whether the session is currently bound to a thread. */
    isSet(): boolean;
    /** The active thread id, throwing when the session is not bound to a thread. */
    requireId(): string;
    /** Bind the session to a thread. */
    set({ threadId }: {
        threadId: string;
    }): void;
    /** Clear the session's thread binding. */
    clear(): void;
    /** List this session's threads (its own resource by default, or all resources). */
    list(options?: {
        allResources?: boolean;
        includeForkedSubagents?: boolean;
    }): Promise<HarnessThread[]>;
    /** Fetch a single thread by id, or null when it doesn't exist / no storage. */
    getById({ threadId }: {
        threadId: string;
    }): Promise<HarnessThread | null>;
    /** List messages for a thread (newest-`limit`, returned oldest-first), or all. */
    listMessages({ threadId, limit }: {
        threadId: string;
        limit?: number;
    }): Promise<HarnessMessage[]>;
    /** List messages for the session's active thread (empty when not bound). */
    listActiveMessages({ limit }?: {
        limit?: number;
    }): Promise<HarnessMessage[]>;
    /** The first user message for a single thread, or null. */
    firstUserMessage({ threadId }: {
        threadId: string;
    }): Promise<HarnessMessage | null>;
    /** The first user message for each given thread id. */
    firstUserMessages({ threadIds }: {
        threadIds: string[];
    }): Promise<Map<string, HarnessMessage>>;
    /** Read a setting (metadata value) for the active thread. */
    getSetting({ key }: {
        key: string;
    }): Promise<unknown>;
    /** Persist a setting (metadata value) for the active thread. */
    setSetting({ key, value }: {
        key: string;
        value: unknown;
    }): Promise<void>;
    /** Delete a setting (metadata value) for the active thread. */
    deleteSetting({ key }: {
        key: string;
    }): Promise<void>;
}
/**
 * Owns the session's live subscription to the active thread's agent event
 * stream. A subscription is created per `(agent, resource, thread)` and reused
 * while that triple is unchanged (tracked by {@link key}); switching threads or
 * agents tears the old one down and opens a new one.
 *
 * The Session owns the subscription *handle* and its dedup key plus the
 * mechanical lifecycle (reuse check, teardown, identity check, run-id read).
 * The Harness still owns *how* a subscription is produced (calling the agent)
 * and *how* its stream is consumed, passing the resolved handle in via
 * {@link attach}.
 */
export declare class SessionStream {
    #private;
    /** Build the dedup key identifying a subscription to `threadId` for `agent`. */
    static keyFor({ agent, resourceId, threadId }: {
        agent: Agent;
        resourceId: string;
        threadId: string;
    }): string;
    /** Whether the open subscription already targets `key` (so it can be reused). */
    matches({ key }: {
        key: string;
    }): boolean;
    /** Adopt `subscription` as the live one, recording its dedup `key`. */
    attach({ subscription, key }: {
        subscription: AgentThreadSubscription<any>;
        key: string;
    }): void;
    /** Whether a subscription is currently open. */
    isOpen(): boolean;
    /** Whether `subscription` is the one currently adopted (identity check). */
    isCurrent({ subscription }: {
        subscription: AgentThreadSubscription<any>;
    }): boolean;
    /** The run id the live subscription reports as active, or null when none/idle. */
    activeRunId(): string | null;
    /** Whether the live subscription currently has a run in flight. */
    isActive(): boolean;
    /** Abort the live subscription's in-flight run, if any. Swallows errors. */
    abort(): void;
    /** Detach the live subscription without aborting (e.g. on stream error). */
    detach(): void;
    /** Fully tear down the live subscription: abort, unsubscribe, and clear. */
    cleanup(): void;
}
/** A tool call parked awaiting a resume, keyed in {@link SessionSuspensions}. */
export interface PendingSuspension {
    /** The run id to resume when this tool call is answered. */
    runId: string;
    /** The suspended tool's name (e.g. `ask_user`, `submit_plan`). */
    toolName: string;
}
/**
 * Owns the session's parked tool suspensions: tool calls paused via the native
 * tool-suspension primitive (e.g. `ask_user` / `request_access` / `submit_plan`)
 * that are awaiting a resume, keyed by `toolCallId`. Each entry records the run
 * id to resume and the tool name. A Map (rather than single fields) lets several
 * tools — e.g. parallel `ask_user` calls in one step — stay suspended and be
 * resumed independently.
 *
 * This is the resume *data* the Harness reads to drive a resume. The richer
 * per-suspension UI snapshot lives on the Harness display state; the Session
 * owns only what's needed to resume.
 */
export declare class SessionSuspensions {
    #private;
    /** Park `toolCallId` as awaiting a resume on `runId` for `toolName`. */
    register({ toolCallId, runId, toolName }: {
        toolCallId: string;
        runId: string;
        toolName: string;
    }): void;
    /** The parked suspension for `toolCallId`, or undefined when none. */
    get({ toolCallId }: {
        toolCallId: string;
    }): PendingSuspension | undefined;
    /** Whether `toolCallId` is currently parked. */
    has({ toolCallId }: {
        toolCallId: string;
    }): boolean;
    /** Drop `toolCallId` from the parked set (e.g. once resumed). */
    delete({ toolCallId }: {
        toolCallId: string;
    }): void;
    /** Drop all parked suspensions (e.g. on abort or thread switch). */
    clear(): void;
    /** Whether any tool calls are parked awaiting a resume. */
    hasPending(): boolean;
    /**
     * Resolve which parked suspension to act on. With an explicit `toolCallId` it
     * must match a parked suspension; without one it returns the single parked
     * suspension (or undefined when there are zero or several).
     */
    resolveToolCallId(toolCallId?: string): string | undefined;
}
/** A message queued to send once the active run finishes, held in {@link SessionFollowUps}. */
export interface FollowUp {
    /** The message text to send. */
    content: string;
    /** Optional request context to apply when the queued message is sent. */
    requestContext?: RequestContext;
}
/**
 * Owns the session's follow-up queue: messages a user submits while a run is in
 * progress, held FIFO until the active run finishes and the queue is drained.
 *
 * This owns the queue *data* (enqueue/dequeue/requeue/clear/count). The Harness
 * still drives draining — sending each message and emitting `follow_up_queued`
 * as the count changes — and keeps the display-state mirror (`queuedFollowUps`).
 */
export declare class SessionFollowUps {
    #private;
    /** Number of messages currently queued. */
    count(): number;
    /** Whether the queue is empty. */
    isEmpty(): boolean;
    /** Append a follow-up to the back of the queue. */
    enqueue(followUp: FollowUp): void;
    /** Remove and return the next follow-up, or undefined when empty. */
    dequeue(): FollowUp | undefined;
    /** Put a follow-up back at the front (e.g. when draining it failed). */
    requeue(followUp: FollowUp): void;
    /** Drop all queued follow-ups (e.g. on steer or thread switch). */
    clear(): void;
}
/** The decision a user returns to resolve a parked tool-approval gate. */
export interface ApprovalDecision {
    /** Whether to run the gated tool or reject it. */
    decision: 'approve' | 'decline';
    /** Optional request context to apply when the gated tool resumes. */
    requestContext?: RequestContext;
}
/**
 * A user's response to a parked approval. `always_allow_category` approves the
 * tool and additionally grants its category for the rest of the session.
 */
export interface ApprovalResponse {
    decision: 'approve' | 'decline' | 'always_allow_category';
    requestContext?: RequestContext;
}
/**
 * Owns the session's interactive tool-approval gate: when a tool requires user
 * approval, the run parks on a promise here until the UI responds approve or
 * decline. Holds the pending resolver and the name of the tool being gated.
 *
 * At most one approval is in flight at a time. The Session owns the gate
 * mechanics (arm / resolve / clear); the Harness still maps a decision to its
 * effects (running vs declining the tool, and any "always allow" grant), since
 * those touch config-derived tool categories.
 */
export declare class SessionApproval {
    #private;
    /**
     * Park a new approval for `toolName` and return a promise that resolves once
     * {@link resolve} is called with the user's decision. The caller awaits this
     * while the run is suspended on the gate.
     */
    arm({ toolName }: {
        toolName: string;
    }): Promise<ApprovalDecision>;
    /** Whether an approval is currently parked awaiting a decision. */
    isArmed(): boolean;
    /**
     * Apply a user's {@link ApprovalResponse} to the parked gate. A no-op when
     * nothing is armed. `always_allow_category` runs `onAlwaysAllow` with the
     * gated tool name (so the caller can grant the tool's category — a lookup that
     * needs Harness config) and then approves; `approve`/`decline` resolve as-is.
     */
    respond({ decision, requestContext, onAlwaysAllow, }: ApprovalResponse & {
        onAlwaysAllow?: (toolName: string) => void;
    }): void;
    /**
     * Release a parked gate without a user decision — used when the run is
     * aborted. Resolves the awaiting producer as a `decline` so the gated tool is
     * rejected (not run) and the run can finalize. A no-op when nothing is armed.
     */
    cancel(): void;
    /** Clear the gated tool name once a parked approval has been consumed. */
    clearToolName(): void;
}
/**
 * Owns the session's transient run identity and abort control: the id of the
 * run currently streaming on the active thread, its trace id, a monotonic
 * operation counter bumped each time a new operation starts, and the
 * AbortController/abort-requested flag governing cancellation. All of this is
 * per-run scratch state — it is never persisted and resets between runs.
 *
 * The live agent subscription itself lives on {@link SessionStream}
 * (`session.stream`); this holds the last run id observed on a chunk so callers
 * have a stable value once the subscription has settled.
 */
export declare class SessionRun {
    #private;
    /** The current run id (null when idle). */
    getRunId(): string | null;
    /** Set the current run id. */
    setRunId({ runId }: {
        runId: string | null;
    }): void;
    /** The current trace id (null when unset). */
    getTraceId(): string | null;
    /** Set the current trace id. */
    setTraceId({ traceId }: {
        traceId: string | null;
    }): void;
    /**
     * Clear all run state (run id, trace id, abort controller + requested flag)
     * when a run ends or is reset. Does not touch the operation counter.
     */
    reset(): void;
    /** Bump and return the operation counter at the start of a new operation. */
    nextOperation(): number;
    /**
     * Lazily create (if needed) and return the AbortController for the current
     * run. Callers pass its `.signal` into the underlying stream.
     */
    ensureAbortController(): AbortController;
    /** Signal for the current run's AbortController, or undefined when none is armed. */
    getAbortSignal(): AbortSignal | undefined;
    /**
     * Whether a run is currently in progress. A run is armed with an
     * AbortController for its duration, so the presence of one is what "running"
     * means; this is the semantic accessor callers should use.
     */
    isRunning(): boolean;
    /**
     * Whether an AbortController is currently armed. Equivalent to
     * {@link isRunning} today; kept for callers that assert on the controller's
     * lifecycle specifically (e.g. that it was cleared after an abort).
     */
    hasAbortController(): boolean;
    /** Clear the abort-requested flag at the start of a fresh run. */
    clearAbortRequested(): void;
    /** Whether an abort has been requested for the current run. */
    isAbortRequested(): boolean;
    /**
     * Request an abort: mark the run as aborting and fire the AbortController (if
     * armed), then drop the controller. Leaves the requested flag set so the
     * run-end path can resolve its reason as 'aborted'; {@link reset} clears it.
     */
    requestAbort(): void;
}
/**
 * Owns the session's currently-selected model. Source of truth for "which model
 * is active", plus the per-mode model memory persisted to the thread-settings
 * store (so each mode remembers the model it was last used with).
 */
export declare class SessionModel {
    #private;
    constructor(store: () => ThreadSettingsStore | undefined);
    /** The currently-selected model id ('' when none selected yet). */
    get(): string;
    /** Whether a model is currently selected. */
    hasSelection(): boolean;
    /** Set the in-memory selected model id (no persistence). */
    set({ modelId }: {
        modelId: string;
    }): void;
    /** Persist `modelId` as the last-used model for `modeId`. */
    saveForMode({ modeId, modelId }: {
        modeId: string;
        modelId: string;
    }): Promise<void>;
    /**
     * Resolve the model for `modeId`: the persisted per-mode model if present,
     * else `defaultModelId`, else null.
     */
    resolveForMode({ modeId, defaultModelId, }: {
        modeId: string;
        defaultModelId?: string;
    }): Promise<string | null>;
}
/**
 * Owns the session's currently-selected mode and the logic for switching modes.
 * Holds the active mode id and runs the version-guarded switch sequence —
 * persisting the selection and coordinating the per-mode model with
 * {@link SessionModel}. The Harness still owns the mode *definitions*
 * (`config.modes`); this owns "which mode is active" and how a switch unfolds.
 */
export declare class SessionMode {
    #private;
    constructor(store: () => ThreadSettingsStore | undefined, model: SessionModel);
    /**
     * Attach the resolver that maps a mode id to its definition. The Harness owns
     * the mode catalog (`config.modes`) and injects this once.
     */
    setResolver(resolve: (modeId: string) => HarnessMode | null): void;
    /** The currently-selected mode id. */
    get(): string;
    /**
     * Resolve the currently-selected mode id to its full definition against the
     * host's mode catalog. Throws if the selected mode id isn't in the catalog.
     */
    resolve(): HarnessMode;
    /** Set the currently-selected mode id (on default resolution or hydration). */
    set({ modeId }: {
        modeId: string;
    }): void;
    /**
     * Switch to `modeId`, coordinating the selected model and persistence.
     *
     * The Harness handles aborting in-flight work and emitting events; this owns
     * the version-guarded sequence: remember the outgoing mode's model, persist
     * the new mode, then resolve and apply the incoming mode's model. A newer
     * switch starting mid-flight supersedes this one, which then bails.
     *
     * Returns the resolved model id for the new mode (or null), so the caller can
     * emit `model_changed` after applying it.
     */
    switch({ modeId, defaultModelId, }: {
        modeId: string;
        defaultModelId?: string;
    }): Promise<{
        modelId: string | null;
    }>;
}
interface SessionStateOptions<TState> {
    initialState?: Partial<TState>;
    stateSchema?: PublicSchema<TState, any>;
    emit?: (event: HarnessEvent) => void;
}
/**
 * A Harness session owns the per-conversation runtime state that today lives
 * flattened on the {@link Harness} instance. This class is the seam we extract
 * that state into, one concern at a time, so the Harness can eventually own a
 * `Session` rather than the state itself.
 *
 * Currently owns:
 * - the live Harness state (`session.state`): schema-validated snapshots and
 *   serialized updates that emit `state_changed`. `Harness.getState()` /
 *   `Harness.setState()` are compatibility wrappers over this domain.
 * - session-scoped permission grants — the "allow for this session" approvals a
 *   user makes when a tool or tool category is gated behind the permission check.
 * - the live token-usage counter for the active thread. The Session holds the
 *   in-memory running tally; the Harness remains responsible for persisting it
 *   to (and hydrating it from) thread metadata, because usage is thread-scoped.
 * - the currently-selected mode (`session.mode`) and model (`session.model`).
 *   The Session is the source of truth for which mode/model is active and owns
 *   the mode-switch sequence and per-mode model memory. The Harness still owns
 *   the mode *definitions* (`config.modes`).
 * - transient run identity and abort control (`session.run`): the current run
 *   id, trace id, monotonic operation counter, and the AbortController/
 *   abort-requested flag. This is per-run scratch state and is never persisted.
 * - the live agent thread subscription (`session.stream`): the open
 *   subscription to the active thread's event stream and its dedup key. The
 *   Harness still produces the subscription (calling the agent) and consumes its
 *   stream; the Session owns the handle and its lifecycle.
 * - the parked tool suspensions (`session.suspensions`): tool calls paused via
 *   the native tool-suspension primitive awaiting a resume, keyed by toolCallId.
 *   The Session owns the resume data; the Harness keeps the richer per-suspension
 *   UI snapshot on its display state.
 * - the follow-up queue (`session.followUps`): messages a user submits while a
 *   run is in progress, held FIFO until the run finishes. The Session owns the
 *   queue; the Harness drives draining and keeps the `queuedFollowUps` display
 *   mirror.
 * - the interactive tool-approval gate (`session.approval`): when a tool needs
 *   user approval, the run parks on a promise here until the UI responds. The
 *   Session owns the gate; the Harness maps the decision to its effects (run vs
 *   decline, any "always allow" grant), which touch config-derived categories.
 *
 * It also exposes a couple of accessors that compose `run` and `stream`:
 * {@link getCurrentRunId} (the active run id, preferring the live subscription)
 * and {@link abortRun} (abort the live run and mark it aborting).
 *
 * Mode/model persistence is thread-scoped, so the Session writes through a
 * {@link ThreadSettingsStore} the Harness backs with thread metadata; when no
 * storage is configured the store is absent and state stays in memory.
 */
/**
 * Owns the session's canonical display state — the projection a UI renders from
 * instead of folding raw events itself. The Session holds the snapshot and the
 * reducer ({@link apply}) that keeps it in sync with every Harness event; the
 * Harness still owns the event bus and dispatches `display_state_changed` to
 * listeners after applying.
 *
 * The reducer needs a few read-only host/session facts it doesn't own: the live
 * token-usage tally, a subagent display-name lookup (Harness config), and the
 * active thread id (to decide whether a `thread_deleted` clears the view). Those
 * are injected at construction so the reducer stays self-contained.
 */
export declare class SessionDisplayState {
    #private;
    private readonly deps;
    constructor(deps: {
        /** The session's live token-usage tally, mirrored into the view on usage/thread events. */
        getTokenUsage: () => TokenUsage;
        /** Resolve a subagent's display name from Harness config, or undefined when unnamed. */
        getSubagentDisplayName: (agentType: string) => string | undefined;
        /** The active thread id, used to gate `thread_deleted` resets. */
        getThreadId: () => string | null;
        /** Clear the session's follow-up queue when thread-scoped display state resets. */
        clearFollowUps: () => void;
    });
    /**
     * A read-only snapshot of the canonical display state. UIs should render from
     * this instead of building state up from raw events.
     */
    get(): Readonly<HarnessDisplayState>;
    /**
     * Drop the display mirror of every parked tool suspension. Used on abort,
     * which abandons the run's parked suspensions; the caller dispatches
     * `display_state_changed`.
     */
    clearPendingSuspensions(): void;
    /**
     * Clear the modified-files tally without touching the rest of the snapshot.
     * Used after a clone, which starts the cloned thread with a clean working set
     * while the surrounding UI reset handles tasks/tools explicitly.
     */
    clearModifiedFiles(): void;
    /**
     * Drop the display mirror of a single parked tool suspension once it has been
     * resumed, so the UI stops rendering only the resolved prompt while any other
     * parked suspensions stay visible.
     */
    deletePendingSuspension(toolCallId: string): void;
    /**
     * Restore task display state after a UI replays persisted task-tool history.
     * Updates the snapshot without emitting a live `task_updated` event, since no
     * task tool just ran. The caller dispatches `display_state_changed`.
     */
    restoreTasks(tasks: TaskItemSnapshot[]): void;
    /**
     * Reset display fields scoped to a thread. Called on thread switch/creation.
     * Also clears the session's follow-up queue (mirrored by `queuedFollowUps`).
     */
    resetThread(): void;
    /**
     * Apply a display-state update based on an incoming event. The centralized
     * state machine that keeps {@link HarnessDisplayState} in sync with every
     * event the Harness emits.
     */
    apply(event: HarnessEvent): void;
}
export declare class Session<TState = unknown> {
    #private;
    /** The session's currently-selected model (source of truth) + per-mode memory. */
    readonly model: SessionModel;
    /** The session's currently-selected mode and switch sequence. */
    readonly mode: SessionMode;
    /** Transient run identity (run id, trace id, operation counter) for the active run. */
    readonly run: SessionRun;
    /** Live subscription to the active thread's agent event stream. */
    readonly stream: SessionStream;
    /** Tool calls parked awaiting a resume (the resume data, keyed by toolCallId). */
    readonly suspensions: SessionSuspensions;
    /** Messages queued to send after the active run finishes. */
    readonly followUps: SessionFollowUps;
    /** The interactive tool-approval gate the current run parks on. */
    readonly approval: SessionApproval;
    /** The session's identity: the memory resourceId it reads/writes under. */
    readonly identity: SessionIdentity;
    /** The session's thread domain: current binding + reads scoped to it. */
    readonly thread: SessionThread;
    /** The canonical display state a UI renders, plus the reducer that maintains it. */
    readonly displayState: SessionDisplayState;
    /** The session-owned Harness state domain. */
    readonly state: HarnessRequestState<TState>;
    constructor({ resourceId, state }: {
        resourceId: string;
        state?: SessionStateOptions<TState>;
    });
    /**
     * Attach the thread-settings store the Session persists mode/model through.
     * The Harness calls this once storage is available; without it, mode/model
     * state lives purely in memory.
     */
    setStore(store: ThreadSettingsStore | undefined): void;
    /**
     * Attach the tool→category resolver used when a user picks "always allow
     * category". The category map is Harness config, so the Harness injects this
     * once; without it, an "always_allow_category" decision simply approves.
     */
    setCategoryResolver(resolveCategory: (toolName: string) => ToolCategory | null): void;
    /**
     * Attach the subagent display-name resolver the display-state reducer uses to
     * label active subagents. The subagent catalog is Harness config, so the
     * Harness injects this once; without it, subagents render without a name.
     */
    setSubagentNameResolver(resolveSubagentName: (agentType: string) => string | undefined): void;
    /**
     * The id of the run currently active on this session: the live subscription's
     * active run id when it is streaming, falling back to the last run id the run
     * tracker observed. Null when the session is idle.
     */
    getCurrentRunId(): string | null;
    /**
     * Abort the session's active run: drop any parked tool suspensions, abort the
     * live subscription's in-flight run, and mark the run as aborting so the
     * run-end path resolves its reason as 'aborted'.
     *
     * Dropping the parked suspensions matters because a run sitting in a tool
     * `suspend()` (e.g. `ask_user` / `request_access`) is not actively streaming,
     * so aborting the controller alone would leave it orphaned. The Harness still
     * clears its own display-state mirror of those suspensions separately.
     *
     * Releasing a parked tool-approval gate matters for the same reason: a run
     * awaiting `approval.arm()` is not streaming, so we resolve it as a decline so
     * the gated tool is rejected and the run can finalize rather than hang.
     */
    abortRun(): void;
    /**
     * Respond to the parked tool-approval gate with the user's decision. A no-op
     * when nothing is awaiting approval. "always_allow_category" grants the gated
     * tool's category for the rest of the session (resolved via the injected
     * {@link setCategoryResolver}) and then approves; "approve"/"decline" release
     * the run as-is.
     */
    respondToToolApproval({ decision, requestContext, }: {
        decision: 'approve' | 'decline' | 'always_allow_category';
        requestContext?: RequestContext;
    }): void;
    /** Grant a tool category "allow" for the remainder of the session. */
    grantCategory(category: ToolCategory): void;
    /** Grant an individual tool "allow" for the remainder of the session. */
    grantTool(toolName: string): void;
    /** Whether the given tool category has been granted for the session. */
    hasCategoryGrant(category: ToolCategory): boolean;
    /** Whether the given tool has been granted for the session. */
    hasToolGrant(toolName: string): boolean;
    /** Snapshot of all session-scoped grants. */
    getGrants(): {
        categories: ToolCategory[];
        tools: string[];
    };
    /** A copy of the running token-usage tally for the active thread. */
    getTokenUsage(): TokenUsage;
    /**
     * Replace the running tally, e.g. when hydrating from persisted thread
     * metadata on thread switch.
     */
    setTokenUsage(usage: TokenUsage): void;
    /** Reset the running tally to zero, e.g. on a new/empty thread. */
    resetTokenUsage(): void;
    /** Fold a single step's usage into the running tally. */
    addUsage(stepUsage: TokenUsage): void;
}
export {};
//# sourceMappingURL=session.d.ts.map