import type { Agent } from '../agent/index.js';
import type { AgentSignalAttributes, AgentSignalContents, AgentSignalInput } from '../agent/signals.js';
import type { AgentThreadSubscription, MastraBrowser, SendAgentNotificationSignalOptions, SendAgentNotificationSignalResult, ToolsetsInput } from '../agent/types.js';
import type { MastraModelGatewayInterface } from '../llm/model/gateways/index.js';
import type { MastraModelConfig } from '../llm/model/shared.types.js';
import type { SendNotificationSignalInput } from '../notifications/index.js';
import type { TracingContext, TracingOptions } from '../observability/index.js';
import type { RequestContext } from '../request-context/index.js';
import type { PublicSchema } from '../schema/index.js';
import { Workspace } from '../workspace/index.js';
import { SessionRunEngine } from './session-run-engine.js';
import type { TaskItemSnapshot } from './tools.js';
import type { AgentControllerDisplayState, AgentControllerEvent, AgentControllerEventListener, AgentControllerMessage, AgentControllerMode, AgentControllerOMConfig, AgentControllerRequestState, AgentControllerThread, ModelUseCountTracker, PermissionPolicy, PermissionRules, 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 AgentController 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>;
}
/** Options for {@link Session.sendNotificationSignal}. */
export type SessionSendNotificationSignalOptions = {
    ifActive?: SendAgentNotificationSignalOptions['ifActive'];
    ifIdle?: SendAgentNotificationSignalOptions['ifIdle'];
    tracingContext?: TracingContext;
    tracingOptions?: TracingOptions;
    requestContext?: RequestContext;
};
/**
 * 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
 * AgentController serves many sessions, so this identity — "whose session is this, and
 * which thread is it on" — belongs to the Session, not the AgentController.
 *
 * `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.
 *
 * `id` is the stable identifier for this session (mirrors `SessionRecord.id` in
 * storage) and `ownerId` is the owner of this session (mirrors
 * `SessionRecord.ownerId`). Both are stable for the life of the session and do
 * not change when the resourceId is switched.
 *
 * 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, id, ownerId }: {
        resourceId: string;
        id: string;
        ownerId: string;
    });
    /** The resourceId the session currently reads/writes under. */
    getResourceId(): string;
    /** The resourceId the session started with. */
    getDefaultResourceId(): string;
    /** The stable session identifier for this session. */
    getId(): string;
    /** The stable owner identifier for this session. */
    getOwnerId(): 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 AgentController backs this with its memory storage (mapping raw
 * storage rows to {@link AgentControllerThread}/{@link AgentControllerMessage}); 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 AgentController
 * 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;
        metadata?: Record<string, unknown>;
    }): Promise<AgentControllerThread[]>;
    /** Fetch a single thread by id, or null when it doesn't exist. */
    getById(input: {
        threadId: string;
    }): Promise<AgentControllerThread | null>;
    /** List messages for a thread, newest-`limit` (returned oldest-first) or all. */
    listMessages(input: {
        threadId: string;
        limit?: number;
    }): Promise<AgentControllerMessage[]>;
    /** The first user message for each given thread id. */
    firstUserMessages(input: {
        threadIds: string[];
    }): Promise<Map<string, AgentControllerMessage>>;
    /** 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>;
    /** Whether the host has thread storage configured. When false, lifecycle persistence is a no-op. */
    hasStorage(): boolean;
    /** Persist a new or updated thread row. No-op when storage is unavailable. */
    saveThread(input: {
        thread: AgentControllerThread;
    }): Promise<void>;
    /** Delete a thread row by id. No-op when storage is unavailable. */
    deleteThread(input: {
        threadId: string;
    }): Promise<void>;
    /** Clone a thread (and its messages) via the host's memory, returning the new thread. */
    cloneThread(input: {
        sourceThreadId: string;
        resourceId: string;
        title?: string;
        metadata?: Record<string, unknown>;
    }): Promise<AgentControllerThread>;
    /** Acquire the host thread lock for a thread id. No-op when no lock is configured. */
    acquireLock(threadId: string): Promise<void>;
    /** Release the host thread lock for a thread id. No-op when no lock is configured. */
    releaseLock(threadId: string): Promise<void>;
    /** The host's configured mode ids, used to validate a thread's persisted mode on restore. */
    getModeIds(): string[];
}
/**
 * The AgentController-owned machinery a Session leverages to drive an agent run. In the
 * multi-user host one AgentController serves many sessions; the run loop, run state, and
 * thread stream are per-session (they cannot be shared) and so belong on the
 * Session. But *how* a run is produced — which agent answers, the config-backed
 * run/stream options, the toolset, the request context, the tool-approval
 * policy, usage persistence, id generation — is shared infrastructure the
 * AgentController owns. The AgentController injects this machinery into each Session it
 * constructs (via {@link Session.setMachinery}); the Session calls into it but
 * never reaches back into the AgentController or another session.
 *
 * This is the formalized DI boundary: the Session receives exactly the
 * capabilities it is allowed to use, nothing more.
 */
export interface SessionMachinery {
    /** Resolve the agent that should answer for the session's current mode/model. */
    getAgent(): Agent;
    /** Open a fresh subscription to a thread's agent event stream. */
    subscribeToThread(input: {
        resourceId: string;
        threadId: string;
    }): Promise<AgentThreadSubscription<any>>;
    /** Build the per-call stream options (instructions, memory, toolsets, abort signal, tracing). */
    buildStreamOptions(input: {
        requestContext?: RequestContext;
        tracingContext?: TracingContext;
        tracingOptions?: TracingOptions;
    }): Promise<Record<string, unknown>>;
    /** The run budget every initial stream and resume must carry (maxSteps, provider fallbacks, …). */
    buildSharedRunOptions(): Record<string, unknown>;
    /** Resolve the toolset (built-in controller  tools + user/subagent tools) for a run. */
    buildToolsets(requestContext: RequestContext): Promise<ToolsetsInput>;
    /** Resolve the effective request context for a run, layering controller defaults. */
    buildRequestContext(requestContext?: RequestContext): Promise<RequestContext>;
    /** Persist the session's running token usage to thread metadata. */
    persistTokenUsage(): Promise<void>;
    /** Generate a new id (thread ids, message ids) using the host's id strategy. */
    generateId(): string;
    /**
     * Resolve the mode the session transitions to when a plan is approved: the
     * current mode's `transitionsTo`, else the host's default mode. Returns
     * `undefined` when the host has no default mode. The mode catalog is AgentController
     * config, so this is genuinely host-owned.
     */
    resolveTransitionModeId(): string | undefined;
    /**
     * Persist a system-reminder message to a thread, returning the saved message
     * (or `null` when no storage is configured). Pure host-owned persistence
     * (storage handle + id strategy).
     */
    saveSystemReminder(input: {
        threadId: string;
        resourceId: string;
        message: string;
        reminderType: string;
        role: 'user' | 'assistant' | 'system';
        metadata?: Record<string, unknown>;
    }): Promise<AgentControllerMessage | null>;
}
/**
 * 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 AgentController 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 and the owning session whose subsystems lifecycle transitions
     * orchestrate. The AgentController calls this once during wiring; without a store the
     * data methods degrade gracefully.
     */
    connect(store: ThreadDataStore | undefined, session: Session): 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;
    /** Clear the session's thread binding and release its lock when one is held. */
    clearAndReleaseLock(): Promise<void>;
    /** List this session's threads (its own resource by default, or all resources). */
    list(options?: {
        allResources?: boolean;
        includeForkedSubagents?: boolean;
        metadata?: Record<string, unknown>;
    }): Promise<AgentControllerThread[]>;
    /** Fetch a single thread by id, or null when it doesn't exist / no storage. */
    getById({ threadId }: {
        threadId: string;
    }): Promise<AgentControllerThread | null>;
    /** Clone a detected cross-resource project thread into this session's resource. */
    cloneToCurrentResource({ threadId, expectedResourceId, expectedProjectPath, }: {
        threadId: string;
        expectedResourceId: string;
        expectedProjectPath: string;
    }): Promise<AgentControllerThread>;
    /** List messages for a thread (newest-`limit`, returned oldest-first), or all. */
    listMessages({ threadId, limit }: {
        threadId: string;
        limit?: number;
    }): Promise<AgentControllerMessage[]>;
    /** List messages for the session's active thread (empty when not bound). */
    listActiveMessages({ limit }?: {
        limit?: number;
    }): Promise<AgentControllerMessage[]>;
    /** The first user message for a single thread, or null. */
    firstUserMessage({ threadId }: {
        threadId: string;
    }): Promise<AgentControllerMessage | null>;
    /** The first user message for each given thread id. */
    firstUserMessages({ threadIds }: {
        threadIds: string[];
    }): Promise<Map<string, AgentControllerMessage>>;
    /** 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>;
    /** Tear down the current agent subscription and reset the run tracker. */
    cleanupSubscription(): void;
    /**
     * Ensure the session is subscribed to the given agent/thread stream, opening a
     * fresh subscription (and driving its run loop) when the binding changed.
     */
    ensureSubscription(threadId: string): Promise<void>;
    /** Ensure a subscription for the session's active thread (no-op when unbound). */
    ensureCurrentSubscription(): Promise<void>;
    /** Detach from the current thread: abort the run and tear down the subscription. */
    detachFromCurrent(): void;
    /** Create a new thread, bind the session to it, and rebind the agent stream. */
    create({ title }?: {
        title?: string;
    }): Promise<AgentControllerThread>;
    /** Rename the session's active thread. No-op when unbound or storageless. */
    rename({ title }: {
        title: string;
    }): Promise<void>;
    /** Clone a thread (and its messages), bind the session to the clone, and rebind the stream. */
    clone({ sourceThreadId, title, resourceId, }?: {
        sourceThreadId?: string;
        title?: string;
        resourceId?: string;
    }): Promise<AgentControllerThread>;
    /** Switch the session to an existing thread, hydrating its persisted settings and rebinding the stream. */
    switch({ threadId, emitEvent }: {
        threadId: string;
        emitEvent?: boolean;
    }): Promise<void>;
    /** Delete a thread; when it's the active thread, clear the binding and tear down the run. */
    delete({ threadId }: {
        threadId: string;
    }): Promise<void>;
    /**
     * Hydrate the session's per-thread settings from the active thread's metadata:
     * token usage, the persisted mode (restored first), the per-mode model, and
     * observer/reflector model ids + thresholds. Best-effort: on any failure the
     * token tally is reset and the rest is left at defaults.
     */
    loadMetadata(): 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 AgentController 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;
    waitForTeardown(signal: AbortSignal): Promise<void>;
    /** 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 AgentController reads to drive a resume. The richer
 * per-suspension UI snapshot lives on the AgentController 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 AgentController
 * 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;
    /** Optional context explaining why a tool approval was declined. */
    declineContext?: {
        reason?: string;
        message?: string;
    };
}
/**
 * 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;
    declineContext?: {
        reason?: string;
        message?: string;
    };
}
/**
 * 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 AgentController 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`/`toolCallId` and return a promise that
     * resolves once {@link respond} is called with the user's decision. The caller
     * awaits this while the run is suspended on the gate.
     */
    arm({ toolName, toolCallId }: {
        toolName: string;
        toolCallId?: string;
    }): Promise<ApprovalDecision>;
    /** Id of the tool call currently awaiting approval, or null when none. */
    getToolCallId(): string | null;
    /** 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. When `toolCallId` is supplied it must match the gated
     * call; a mismatch is ignored so a stale/delayed response cannot resolve a
     * different pending gate. `always_allow_category` runs `onAlwaysAllow` with the
     * gated tool name (so the caller can grant the tool's category — a lookup that
     * needs AgentController config) and then approves; `approve`/`decline` resolve as-is.
     */
    respond({ decision, toolCallId, requestContext, declineContext, onAlwaysAllow, }: ApprovalResponse & {
        toolCallId?: string;
        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/call id 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;
    waitForTeardown(signal: AbortSignal): Promise<void>;
    /** 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, bus: SessionBus);
    /**
     * Attach the AgentController-owned dependencies {@link switch} needs: the active-mode
     * accessor and the optional model-use tracker. The AgentController injects these once.
     */
    setResolver(options: {
        getCurrentModeId: () => string;
        trackModelUse?: ModelUseCountTracker;
    }): void;
    /** The currently-selected model id ('' when none selected yet). */
    get(): string;
    /** Whether a model is currently selected. */
    hasSelection(): boolean;
    /**
     * A short display name for the selected model: the last segment of the model
     * id (e.g. `__GATEWAY_ANTHROPIC_MODEL_SONNET__` -> `claude-sonnet-4-6`). Returns
     * `'unknown'` when no model is selected.
     */
    displayName(): string;
    /** 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>;
    /**
     * Switch to a different model at runtime.
     *
     * When `scope` is `'thread'` (the default), the model is persisted as the
     * per-mode model for `modeId` so it's restored when switching back. The
     * in-memory selection only updates when the target mode is the active mode.
     * Reports the selection to the model-use tracker and emits `model_changed`.
     */
    switch({ modelId, scope, modeId, }: {
        modelId: string;
        scope?: 'global' | 'thread';
        modeId?: string;
    }): Promise<void>;
}
/**
 * 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 AgentController 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, bus: SessionBus);
    /**
     * Attach the resolver that maps a mode id to its definition. The AgentController owns
     * the mode catalog (`config.modes`) and injects this once.
     */
    setResolver(resolve: (modeId: string) => AgentControllerMode | 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(): AgentControllerMode;
    /** Set the currently-selected mode id (on default resolution or hydration). */
    set({ modeId }: {
        modeId: string;
    }): void;
    /**
     * Switch to a different mode.
     *
     * Emits `mode_changed`, then runs the version-guarded sequence: remember the
     * outgoing mode's model, persist the new mode, then resolve and apply the
     * incoming mode's model — emitting `model_changed` once applied. A newer
     * switch starting mid-flight supersedes this one, which then bails before
     * emitting `model_changed`.
     */
    switch({ modeId }: {
        modeId: string;
    }): Promise<void>;
}
/** Per-role wiring + state/config keys a {@link SessionOMRole} reads and writes. */
interface SessionOMRoleConfig {
    /** The event `role` and `om_model_changed` discriminator for this role. */
    role: 'observer' | 'reflector';
    /** Session-state / thread-settings key holding this role's model id. */
    modelIdKey: 'observerModelId' | 'reflectorModelId';
    /** Session-state key holding this role's threshold. */
    thresholdKey: 'observationThreshold' | 'reflectionThreshold';
    /** Resolve this role's default model id from `omConfig`. */
    defaultModelId: (omConfig: AgentControllerOMConfig | undefined) => string | undefined;
    /** Resolve this role's default threshold from `omConfig`. */
    defaultThreshold: (omConfig: AgentControllerOMConfig | undefined) => number | undefined;
}
/**
 * One observational-memory role (observer or reflector): its model id, resolved
 * model instance, threshold, and model switch. Reads return the session-state
 * value when set, falling back to the AgentController's `omConfig` defaults. The shared
 * wiring is injected by {@link SessionOM.setResolver}.
 */
declare class SessionOMRole {
    #private;
    constructor(config: SessionOMRoleConfig, bus: SessionBus);
    /** @internal Injected by {@link SessionOM.setResolver}. */
    setWiring(wiring: {
        getState: () => Record<string, unknown>;
        setState: (updates: Record<string, unknown>) => void;
        setSetting: (args: {
            key: string;
            value: unknown;
        }) => Promise<void>;
        omConfig?: AgentControllerOMConfig;
        gateways?: MastraModelGatewayInterface[];
    }): void;
    /** This role's model id from session state, falling back to `omConfig`. */
    modelId(): string | undefined;
    /** This role's threshold from session state, falling back to `omConfig`. */
    threshold(): number | undefined;
    /**
     * Resolve this role's model id to a model instance via the configured
     * gateways, or undefined when unset. The bare model id string is routed
     * through {@link ModelRouterLanguageModel}, which selects the matching
     * gateway (or the built-in defaults) and resolves provider auth.
     */
    resolvedModel(): MastraModelConfig | undefined;
    /** Switch this role's model: update session state, persist, and emit. */
    switchModel({ modelId }: {
        modelId: string;
    }): Promise<void>;
}
/**
 * Owns the session's observational-memory model selection, grouped by role:
 * {@link SessionOM.observer} and {@link SessionOM.reflector}. The AgentController owns
 * `omConfig` and the model resolver, so it injects them — plus the session-state
 * read/write and thread-settings persistence — once via {@link setResolver},
 * which fans the wiring out to both roles.
 */
declare class SessionOM {
    readonly observer: SessionOMRole;
    readonly reflector: SessionOMRole;
    constructor(bus: SessionBus);
    /**
     * Attach the session-state read/write, thread-settings persistence, and the
     * AgentController-owned `omConfig` defaults plus model resolver. The AgentController injects
     * these once; the wiring is shared by both roles.
     */
    setResolver(options: {
        getState: () => Record<string, unknown>;
        setState: (updates: Record<string, unknown>) => void;
        setSetting: (args: {
            key: string;
            value: unknown;
        }) => Promise<void>;
        omConfig?: AgentControllerOMConfig;
        gateways?: MastraModelGatewayInterface[];
    }): void;
}
/**
 * Owns the session's tool-permission rules: the per-category and per-tool
 * approval policies persisted in session state under `permissionRules`. The
 * AgentController injects the session-state read/write once via {@link setResolver}.
 *
 * These are the persisted rules consulted during tool-approval resolution; they
 * are distinct from the in-memory "allow for this session" grants on the
 * Session.
 */
declare class SessionPermissions {
    #private;
    /** Attach the session-state read/write. The AgentController injects these once. */
    setResolver(options: {
        getState: () => Record<string, unknown>;
        setState: (updates: Record<string, unknown>) => Promise<void>;
    }): void;
    /** The current permission rules, or empty rules when none are set. */
    getRules(): PermissionRules;
    /** Set the approval policy for a tool category. Resolves once persisted. */
    setForCategory({ category, policy }: {
        category: ToolCategory;
        policy: PermissionPolicy;
    }): Promise<void>;
    /** Set the approval policy for an individual tool. Resolves once persisted. */
    setForTool({ toolName, policy }: {
        toolName: string;
        policy: PermissionPolicy;
    }): Promise<void>;
}
/**
 * The subagent model selection. Reads prefer the per-`agentType` value and fall
 * back to the global subagent model; writes persist to thread settings and emit
 * a `subagent_model_changed` event. Wiring is injected by
 * {@link SessionSubagents.setResolver}.
 */
declare class SessionSubagentModel {
    #private;
    constructor(bus: SessionBus);
    /** @internal Injected by {@link SessionSubagents.setResolver}. */
    setWiring(wiring: {
        getState: () => Record<string, unknown>;
        setState: (updates: Record<string, unknown>) => void;
        setSetting: (args: {
            key: string;
            value: unknown;
        }) => Promise<void>;
    }): void;
    /**
     * The subagent model id, preferring the `agentType`-specific value when one is
     * given, then the global subagent model, or `null` when neither is set.
     */
    get({ agentType }?: {
        agentType?: string;
    }): string | null;
    /**
     * Set the subagent model id (per-`agentType` when given, otherwise global).
     * Persists to thread settings and emits `subagent_model_changed`.
     */
    set({ modelId, agentType }: {
        modelId: string;
        agentType?: string;
    }): Promise<void>;
}
/**
 * The session's subagent configuration. Currently exposes the subagent model
 * selection under {@link SessionSubagents.model}; grouped under `subagents` to
 * leave room for additional subagent settings. The AgentController injects the
 * session-state read/write, thread-settings persistence, and event emitter once
 * via {@link setResolver}.
 */
declare class SessionSubagents {
    readonly model: SessionSubagentModel;
    constructor(bus: SessionBus);
    /**
     * Attach the session-state read/write and thread-settings persistence. The
     * AgentController injects these once.
     */
    setResolver(options: {
        getState: () => Record<string, unknown>;
        setState: (updates: Record<string, unknown>) => void;
        setSetting: (args: {
            key: string;
            value: unknown;
        }) => Promise<void>;
    }): void;
}
interface SessionStateOptions<TState> {
    initialState?: Partial<TState>;
    stateSchema?: PublicSchema<TState, any>;
}
/**
 * A AgentController session owns the per-conversation runtime state that today lives
 * flattened on the {@link AgentController} instance. This class is the seam we extract
 * that state into, one concern at a time, so the AgentController can eventually own a
 * `Session` rather than the state itself.
 *
 * Currently owns:
 * - the live AgentController state (`session.state`): schema-validated snapshots and
 *   serialized updates that emit `state_changed`.
 * - 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 AgentController 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 AgentController 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
 *   AgentController 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 AgentController 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 AgentController 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 AgentController 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 AgentController 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 AgentController event; the
 * AgentController 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 (AgentController 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 AgentController 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<AgentControllerDisplayState>;
    /**
     * 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 AgentControllerDisplayState} in sync with every
     * event the AgentController emits.
     */
    apply(event: AgentControllerEvent): void;
}
/**
 * A session's event bus. Owns the listener list and the full emit pipeline:
 * fold the event into the canonical display state, dispatch to this session's
 * listeners, then fan out a synthetic `display_state_changed`. Each session
 * has its own bus, so events never cross between sessions. Subsystems hold a
 * reference to their session's bus and call {@link emit} directly.
 */
export declare class SessionBus {
    #private;
    /** Attach the display-state reducer the bus folds events into. Set once by the Session. */
    setDisplayState(displayState: SessionDisplayState): void;
    subscribe(listener: AgentControllerEventListener): () => void;
    emit(event: AgentControllerEvent): 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;
    /** The session's observational-memory model selection (observer/reflector). */
    readonly om: SessionOM;
    /** The session's persisted tool-permission rules (per-category / per-tool). */
    readonly permissions: SessionPermissions;
    /** The session's subagent configuration (currently the subagent model). */
    readonly subagents: SessionSubagents;
    /** 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 AgentController state domain. */
    readonly state: AgentControllerRequestState<TState>;
    browser?: MastraBrowser;
    constructor({ resourceId, state, id, ownerId, tags, workspace, browser, }: {
        resourceId: string;
        state?: SessionStateOptions<TState>;
        id: string;
        ownerId: string;
        tags?: Record<string, string>;
        workspace: Workspace;
        browser?: MastraBrowser;
    });
    /**
     * This session's scoping tags (e.g. `{ projectPath }`), stamped onto every
     * thread it creates. Returns a copy; empty when the session is unscoped.
     */
    getTags(): Record<string, string>;
    /**
     * Subscribe to this session's events. Returns an unsubscribe function.
     * Listeners are scoped to this session: a session never delivers its events
     * to another session's subscribers.
     */
    subscribe(listener: AgentControllerEventListener): () => void;
    /**
     * Emit an event on this session. Delegates to this session's bus, which folds
     * the event into the canonical display state, dispatches to this session's
     * listeners, then fans out a synthetic `display_state_changed`.
     */
    emit(event: AgentControllerEvent): void;
    /**
     * Attach the thread-settings store the Session persists mode/model through.
     * The AgentController 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 AgentController config, so the AgentController 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 AgentController config, so the
     * AgentController injects this once; without it, subagents render without a name.
     */
    setSubagentNameResolver(resolveSubagentName: (agentType: string) => string | undefined): void;
    /**
     * Attach the AgentController-owned run machinery this session leverages to drive agent
     * runs (resolve the agent, build run/stream options + toolsets + request
     * context, persist usage, generate ids). The AgentController injects this once when it
     * constructs the session. The run loop, run state, and thread stream live on
     * the session; this is the narrow set of shared capabilities it reaches back
     * into the host for — see {@link SessionMachinery}.
     */
    setMachinery(machinery: SessionMachinery): void;
    /**
     * The AgentController-owned run machinery injected via {@link setMachinery}, throwing
     * when accessed before wiring (a run can never be driven without it).
     */
    get machinery(): SessionMachinery;
    /** The per-session run engine, throwing when accessed before machinery is wired. */
    get runEngine(): SessionRunEngine;
    /**
     * Consume an agent stream response, folding chunks into this session's display
     * messages and usage and driving tool approval. Delegates to the per-session
     * run engine. Used by the initial run path and tool resume.
     */
    processStream(response: {
        fullStream: AsyncIterable<any>;
    }, requestContext?: RequestContext): Promise<{
        message: AgentControllerMessage;
        suspended?: boolean;
    } | undefined>;
    /**
     * Drive the run loop for a subscribed thread stream: process each run's chunks
     * and finalize it. Delegates to the per-session run engine.
     */
    processSubscribedThreadStream(subscription: AgentThreadSubscription<any>): Promise<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 AgentController 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;
    /**
     * Abort the session's active run and clear the display-state mirror of any
     * parked tool suspensions. {@link abortRun} drops the parked suspensions (so a
     * run sitting in a tool suspend() like ask_user / request_access isn't left
     * orphaned), aborts the live subscription, and marks the run as aborting; this
     * additionally clears the display-state mirror of those suspensions and
     * notifies subscribers so stale suspension UI doesn't linger.
     */
    abort(): void;
    /**
     * Resolve the effective approval policy for a tool: explicit per-tool deny
     * wins, then session-wide yolo, then an explicit per-tool policy, then a
     * session-scoped grant, then the tool's category grant/policy, falling back to
     * "ask". Pure session state plus the injected category resolver.
     */
    resolveToolApproval(toolName: string): PermissionPolicy;
    /**
     * 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, toolCallId, requestContext, declineContext, }: {
        decision: 'approve' | 'decline' | 'always_allow_category';
        toolCallId?: string;
        requestContext?: RequestContext;
        declineContext?: {
            reason?: string;
            message?: string;
        };
    }): void;
    /**
     * Build the agent message input for a user turn, attaching any files as
     * additional message parts (text files inlined as fenced code, binary files
     * as `file` parts). Returns the plain string when there are no files.
     */
    private createMessageInput;
    /**
     * Resolve once this session's stream is fully idle.
     *
     * After `abort()` is called the run's status can still be `'running'` for a
     * few microtasks while the underlying model stream finalizes. Callers that
     * need to send a fresh signal after an abort (e.g. plan approval → mode
     * switch → trigger reminder) should await this before calling `sendSignal`
     * to avoid the new signal being queued onto the dying run, which would then
     * be drained with the previous run's already-aborted abortSignal.
     */
    private waitForStreamIdle;
    /**
     * Send a signal to this session's current agent/thread. Creates a thread when
     * the session is not yet bound. When a run is already active the signal is
     * dispatched onto it; otherwise the signal carries fresh stream options that
     * start a new run.
     */
    sendSignal(input: AgentSignalInput | {
        content: AgentSignalContents;
        ifActive?: {
            attributes?: AgentSignalAttributes;
        };
        ifIdle?: {
            attributes?: AgentSignalAttributes;
        };
        tracingContext?: TracingContext;
        tracingOptions?: TracingOptions;
        requestContext?: RequestContext;
    }): {
        id: string;
        type: AgentSignalInput['type'];
        accepted: Promise<{
            accepted: true;
            runId?: string;
        }>;
    };
    /**
     * Send a notification signal to this session's current agent/thread.
     */
    sendNotificationSignal(input: SendNotificationSignalInput, options?: SessionSendNotificationSignalOptions): Promise<SendAgentNotificationSignalResult>;
    /**
     * Send a message to this session's current agent and await the run. Streams
     * the response and emits events.
     */
    sendMessage({ content, files, tracingContext, tracingOptions, requestContext: requestContextInput, }: {
        content: string;
        files?: Array<{
            data: string;
            mediaType: string;
            filename?: string;
        }>;
        tracingContext?: TracingContext;
        tracingOptions?: TracingOptions;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Steer the agent mid-stream: aborts the current run and sends a new message.
     */
    steer({ content, requestContext }: {
        content: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Queue a follow-up message to be processed after the current run completes,
     * or send it immediately when the session is idle.
     */
    followUp({ content, requestContext }: {
        content: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Send the next queued follow-up message after a run finishes. Called by the
     * run engine when a run ends. Re-queues on failure so the message isn't lost.
     */
    drainFollowUpQueue(options?: {
        tracingContext?: TracingContext;
        tracingOptions?: TracingOptions;
    }): Promise<boolean>;
    /**
     * Persist a system-reminder message to this session's current thread. Returns
     * the saved message, or `null` when the session has no thread or no storage.
     */
    saveSystemReminderMessage({ message, reminderType, role, metadata, }: {
        message: string;
        reminderType: string;
        role?: 'user' | 'assistant' | 'system';
        metadata?: Record<string, unknown>;
    }): Promise<AgentControllerMessage | null>;
    /**
     * Respond to a pending tool suspension. Provides resume data so the suspended
     * tool can continue. `toolCallId` selects which suspended tool to resume —
     * required when more than one is suspended concurrently; when omitted it
     * resolves to the sole pending suspension. `submit_plan` resumes are routed
     * through the plan-approval path (approval switches to the default mode).
     */
    respondToToolSuspension({ resumeData, toolCallId, requestContext, }: {
        resumeData: any;
        toolCallId?: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Respond to a suspended `submit_plan` tool call. Rejections resume the plan
     * tool with feedback. Approvals switch to the transition mode when needed,
     * then resume the same suspended tool so the approved tool result is persisted
     * and the model continues naturally in the target mode.
     */
    private handlePlanApprovalResume;
    /**
     * Approve a parked tool call: drive the agent to execute it. Throws when there
     * is no active run.
     */
    approveToolCall({ toolCallId, requestContext: requestContextInput, }: {
        toolCallId?: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Decline a parked tool call: drive the agent to reject it. Throws when there
     * is no active run.
     */
    declineToolCall({ toolCallId, requestContext: requestContextInput, declineContext, }: {
        toolCallId?: string;
        requestContext?: RequestContext;
        declineContext?: {
            reason?: string;
            message?: string;
        };
    }): Promise<void>;
    private createSubscribedResumeBoundaryWaiter;
    /**
     * Resume a suspended tool call through the active thread subscription.
     * Re-supplies the shared run budget so the resumed run doesn't stop mid-task
     * on the agent's small default maxSteps.
     *
     * Interactive builtins (`ask_user`, `request_access`) are exempted from the
     * approval re-check on resume: their resume schema is `z.string()` /
     * `z.array(z.string())` which cannot carry the `{ approved }` field the
     * approval gate demands, so re-entering the approval branch would always
     * reject the answer. The caller already handled approval (setForTool policy,
     * yolo mode, or a prior explicit approval gate).
     */
    resumeToolCall({ resumeData, toolCallId, requestContext: requestContextInput, }: {
        resumeData: any;
        toolCallId: string;
        requestContext?: RequestContext;
    }): Promise<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