import { Agent } from '../agent/index.js';
import type { AgentSignalAttributes, AgentSignalContents, AgentSignalInput } from '../agent/signals.js';
import type { SendAgentNotificationSignalOptions, SendAgentNotificationSignalResult } from '../agent/types.js';
import type { MastraBrowser } from '../browser/browser.js';
import { Mastra } from '../mastra/index.js';
import type { MastraMemory } from '../memory/memory.js';
import type { SendNotificationSignalInput } from '../notifications/index.js';
import type { TracingContext, TracingOptions } from '../observability/index.js';
import { RequestContext } from '../request-context/index.js';
import type { ObservationalMemoryRecord } from '../storage/types.js';
import { Workspace } from '../workspace/workspace.js';
import { Session } from './session.js';
import type { AvailableModel, HeartbeatHandler, HarnessConfig, HarnessEventListener, HarnessMessage, HarnessMode, HarnessSession, HarnessThread, ModelAuthStatus, PermissionPolicy, PermissionRules, ToolCategory } from './types.js';
type HarnessSendNotificationSignalOptions = {
    ifActive?: SendAgentNotificationSignalOptions['ifActive'];
    ifIdle?: SendAgentNotificationSignalOptions['ifIdle'];
    tracingContext?: TracingContext;
    tracingOptions?: TracingOptions;
    requestContext?: RequestContext;
};
/**
 * Build a user-facing message for a non-success stream finish reason.
 *
 * Anthropic's classifier blocks / model refusals (e.g. `claude-fable-5`) surface
 * through the AI SDK as a `content-filter` finish reason, with details on
 * `providerMetadata.anthropic.stopDetails`. Without explicit handling these
 * runs end on an empty assistant message with no error, so the run appears to
 * silently stop. Returning a message here lets the harness finalize the run
 * into an explicit terminal error state.
 */
export declare function describeNonSuccessFinishReason(reason: string, providerMetadata: unknown): string | undefined;
/**
 * Returns Anthropic `providerOptions` that enable a server-side fallback to
 * {@link FABLE_FALLBACK_MODEL} when the active model is `claude-fable-5`, and
 * `undefined` otherwise.
 *
 * fable-5 can have a turn blocked server-side by its safety classifiers. With
 * a fallback configured, Anthropic transparently retries the blocked turn on
 * the fallback model and returns that model's answer instead of refusing. If
 * the whole chain refuses, the run still ends on a `content-filter` finish
 * reason, which is handled as a terminal error.
 *
 * The match is suffix-based so it covers `anthropic/claude-fable-5`, a bare
 * `claude-fable-5`, and any pack/provider-prefixed form.
 */
export declare function buildFableFallbackProviderOptions(modelId: string): {
    anthropic: {
        fallbacks: {
            model: string;
        }[];
    };
} | undefined;
/**
 * Build a user-facing notice when a turn was served by an Anthropic
 * server-side fallback model instead of the primary model.
 *
 * When the primary model's safety classifiers decline a turn and a fallback
 * chain is configured (see {@link buildFableFallbackProviderOptions}), the API
 * transparently retries on the fallback model and reports this via
 * `fallback_message` entries in `providerMetadata.anthropic.iterations`.
 * Without a notice the user has no way to tell that the response did not come
 * from the model they selected.
 */
export declare function describeServerSideFallback(providerMetadata: unknown): string | undefined;
/**
 * The Harness orchestrates multiple agent modes, shared state, memory, and storage.
 * It's the core abstraction that a TUI (or other UI) controls.
 *
 * @example
 * ```ts
 * const harness = new Harness({
 *   id: "my-coding-agent",
 *   storage: new LibSQLStore({ url: "file:./data.db" }),
 *   stateSchema: z.object({
 *     currentModelId: z.string().optional(),
 *   }),
 *   modes: [
 *     { id: "plan", name: "Plan", default: true, agent: planAgent },
 *     { id: "build", name: "Build", agent: buildAgent },
 *   ],
 * })
 *
 * harness.subscribe((event) => {
 *   if (event.type === "message_update") renderMessage(event.message)
 * })
 *
 * await harness.init()
 * await harness.sendMessage({ content: "Hello!" })
 * ```
 */
export declare class Harness<TState = {}> {
    #private;
    readonly id: string;
    private config;
    private listeners;
    private workspace;
    private workspaceFn;
    private workspaceInitialized;
    private browser;
    private browserFn;
    private heartbeatTimers;
    private availableModelsCache;
    private availableModelsCacheTime;
    constructor(config: HarnessConfig<TState>);
    /**
     * Access the internal Mastra instance.
     * Available after `init()` when storage is configured.
     * Useful for scorer registration, observability access, and eval tooling.
     */
    getMastra(): Mastra | undefined;
    /**
     * The current harness session. Owns per-session runtime state such as
     * session-scoped permission grants. Prefer `harness.session.*` over the
     * (removed) re-exposed grant helpers on the Harness.
     */
    get session(): Session<TState>;
    /**
     * Sets or updates the harness-level browser and propagates it to mode agents.
     */
    setBrowser(browser: MastraBrowser | undefined): void;
    /**
     * Initialize the harness — loads storage and workspace.
     * Must be called before using the harness.
     */
    init(): Promise<void>;
    /**
     * Select the most recent thread, or create one if none exist.
     */
    selectOrCreateThread(): Promise<HarnessThread>;
    private getMemoryStorage;
    /**
     * The shared-host storage gateway the Session's thread domain reads/writes
     * through. The Session owns the thread-domain logic; this adapter just maps
     * raw storage rows to Harness types — it does not call back into Session.
     */
    private createThreadDataStore;
    private readThreadMetadataValue;
    private writeThreadMetadataValue;
    private removeThreadMetadataValue;
    private queryThreadById;
    private queryThreads;
    private queryThreadMessages;
    private queryFirstUserMessages;
    /**
     * Get current harness state (read-only snapshot).
     * @deprecated Prefer `harness.session.state.get()`.
     */
    getState(): Readonly<TState>;
    /**
     * Update harness state. Validates against schema if provided.
     * Emits state_changed event.
     * @deprecated Prefer `harness.session.state.set(...)`.
     */
    setState(updates: Partial<TState>): Promise<void>;
    private updateState;
    listModes(): HarnessMode[];
    /**
     * Switch to a different mode.
     * Aborts any in-progress generation and switches to the mode's default model.
     */
    switchMode({ modeId }: {
        modeId: string;
    }): Promise<void>;
    private propagateRuntimeServicesToAgent;
    private getAgentForMode;
    /**
     * Resolve the combined instructions for the current mode: harness-level
     * instructions + mode-specific instructions. Passed at call time via
     * `buildAgentMessageStreamOptions` so the agent's own instructions are
     * never mutated.
     */
    private resolveCurrentModeInstructions;
    /**
     * Convert AgentInstructions (string | string[] | system message objects) to
     * a plain string for combining with mode instructions.
     */
    private instructionsToString;
    /**
     * Get the agent for the current mode.
     */
    /**
     * Resolve the Agent backing the current mode, with runtime services (storage,
     * pubsub, telemetry) propagated. Public so consumers like MastraCode's
     * GoalManager can drive the agent's native objective methods
     * (`setObjective`/`getObjective`/`clearObjective`/`updateObjectiveOptions`),
     * which read/write the durable `threadState` `'goal'` slot.
     */
    getCurrentAgent(): Agent;
    /**
     * Get a short display name from the current model ID.
     */
    getModelName(): string;
    /**
     * Get the full model ID (e.g., "anthropic/claude-sonnet-4").
     */
    getFullModelId(): string;
    /**
     * Switch to a different model at runtime.
     */
    switchModel({ modelId, scope, modeId, }: {
        modelId: string;
        scope?: 'global' | 'thread';
        modeId?: string;
    }): Promise<void>;
    /**
     * Check if the current model's provider has authentication configured.
     * Uses app-provided catalog/auth hooks; Harness does not resolve gateway auth itself.
     */
    getCurrentModelAuthStatus(): Promise<ModelAuthStatus>;
    /**
     * Get available models from the app-provided catalog hook with use counts applied.
     */
    listAvailableModels(): Promise<AvailableModel[]>;
    invalidateAvailableModelsCache(): void;
    getResolvedMemory(): Promise<MastraMemory | null>;
    /**
     * Point the session at a different memory resourceId. The resourceId itself
     * lives on the session (`session.identity`); the Harness orchestrates the
     * surrounding teardown — dropping the current thread subscription and clearing
     * the active thread — since those are Harness-owned.
     */
    setResourceId({ resourceId }: {
        resourceId: string;
    }): void;
    getKnownResourceIds(): Promise<string[]>;
    createThread({ title }?: {
        title?: string;
    }): Promise<HarnessThread>;
    /**
     * Returns a memory accessor with thread and message management methods.
     */
    get memory(): {
        createThread: ({ title }?: {
            title?: string;
        }) => Promise<HarnessThread>;
        switchThread: ({ threadId }: {
            threadId: string;
        }) => Promise<void>;
        listThreads: (options?: {
            allResources?: boolean;
            includeForkedSubagents?: boolean;
        }) => Promise<HarnessThread[]>;
        renameThread: ({ title }: {
            title: string;
        }) => Promise<void>;
        deleteThread: ({ threadId }: {
            threadId: string;
        }) => Promise<void>;
    };
    private deleteThread;
    renameThread({ title }: {
        title: string;
    }): Promise<void>;
    cloneThread({ sourceThreadId, title, resourceId, }?: {
        sourceThreadId?: string;
        title?: string;
        resourceId?: string;
    }): Promise<HarnessThread>;
    switchThread({ threadId }: {
        threadId: string;
    }): Promise<void>;
    private loadThreadMetadata;
    /**
     * Load observational memory progress for the current thread.
     * Reads the OM record and recent messages to reconstruct status,
     * then emits an `om_status` event for the UI.
     */
    loadOMProgress(): Promise<void>;
    getObservationalMemoryRecord(): Promise<ObservationalMemoryRecord | null>;
    /**
     * Returns the observer model ID from state, falling back to omConfig defaults.
     */
    getObserverModelId(): string | undefined;
    /**
     * Returns the reflector model ID from state, falling back to omConfig defaults.
     */
    getReflectorModelId(): string | undefined;
    /**
     * Returns the observation threshold from state, falling back to omConfig defaults.
     */
    getObservationThreshold(): number | undefined;
    /**
     * Returns the reflection threshold from state, falling back to omConfig defaults.
     */
    getReflectionThreshold(): number | undefined;
    /**
     * Resolves the observer model ID to a language model instance via the configured resolver.
     */
    getResolvedObserverModel(): import("../llm").MastraModelConfig | undefined;
    /**
     * Resolves the reflector model ID to a language model instance via the configured resolver.
     */
    getResolvedReflectorModel(): import("../llm").MastraModelConfig | undefined;
    /**
     * Switch the Observer model.
     */
    switchObserverModel({ modelId }: {
        modelId: string;
    }): Promise<void>;
    /**
     * Switch the Reflector model.
     */
    switchReflectorModel({ modelId }: {
        modelId: string;
    }): Promise<void>;
    getSubagentModelId({ agentType }?: {
        agentType?: string;
    }): string | null;
    setSubagentModelId({ modelId, agentType }: {
        modelId: string;
        agentType?: string;
    }): Promise<void>;
    getToolCategory({ toolName }: {
        toolName: string;
    }): ToolCategory | null;
    setPermissionForCategory({ category, policy }: {
        category: ToolCategory;
        policy: PermissionPolicy;
    }): void;
    setPermissionForTool({ toolName, policy }: {
        toolName: string;
        policy: PermissionPolicy;
    }): void;
    getPermissionRules(): PermissionRules;
    /**
     * Resolve whether a tool call should be auto-approved, denied, or asked.
     * Resolution chain: per-tool deny → yolo → per-tool policy → session tool grant →
     * session category grant → category policy → "ask"
     */
    private resolveToolApproval;
    private cleanupAgentThreadSubscription;
    private ensureAgentThreadSubscription;
    private ensureCurrentAgentThreadSubscription;
    private createMessageInput;
    private buildAgentMessageStreamOptions;
    /**
     * Options that every harness-driven agent run must carry — the initial stream
     * AND every `resumeStream`. Centralized so the two paths can't drift: a
     * missing `maxSteps` on resume silently caps the resumed run at the agent's
     * small default and ends it mid-task (see {@link HARNESS_MAX_STEPS}).
     */
    private buildSharedRunOptions;
    private drainFollowUpQueue;
    private finishSubscribedStreamRun;
    private handleSubscribedStreamError;
    private processSubscribedThreadStream;
    /**
     * Send a signal to the current agent/thread.
     */
    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 the current agent/thread.
     */
    sendNotificationSignal(input: SendNotificationSignalInput, options?: HarnessSendNotificationSignalOptions): Promise<SendAgentNotificationSignalResult>;
    /**
     * Send a message to the current agent.
     * 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>;
    saveSystemReminderMessage({ message, reminderType, role, metadata, }: {
        message: string;
        reminderType: string;
        role?: 'user' | 'assistant' | 'system';
        metadata?: Record<string, unknown>;
    }): Promise<HarnessMessage | null>;
    private convertToHarnessMessage;
    private createEmptyAssistantMessage;
    private hasCurrentMessageContent;
    private finishCurrentMessageAndRotate;
    /**
     * Process a stream response (shared between sendMessage and tool approval).
     */
    private createStreamState;
    private abortForOmFailure;
    private processStream;
    private processStreamChunk;
    private finishStreamState;
    /**
     * Abort the current operation.
     */
    abort(): void;
    /**
     * Detach from the current thread's event stream without switching to another
     * thread. Used by the TUI `/new` command to stop receiving cross-process
     * events from the old thread while the new thread creation is deferred until
     * the first user message.
     *
     * The current thread ID is preserved so that {@link createThread} can still
     * release the thread lock (when configured) for the previous thread.
     */
    detachFromCurrentThread(): void;
    /**
     * Steer the agent mid-stream: aborts 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 operation completes.
     */
    followUp({ content, requestContext }: {
        content: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * True when one or more tools are parked awaiting a resume (e.g. ask_user /
     * request_access suspensions). A suspended run nulls the AbortController, so
     * isRunning() returns false even though the run is still pending — callers that
     * need to know whether the harness is awaiting user input (e.g. to allow abort)
     * should check this too.
     */
    /**
     * Resolve once the current thread'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 waitForCurrentThreadStreamIdle;
    private getSubagentDisplayName;
    /**
     * Respond to a pending tool suspension from the UI.
     * Provides resume data so the suspended tool can continue execution.
     *
     * `toolCallId` selects which suspended tool to resume — required when more than
     * one tool is suspended concurrently (e.g. parallel `ask_user` calls, see issue
     * #13642). When omitted it resolves to the sole pending suspension.
     */
    respondToToolSuspension({ resumeData, toolCallId, requestContext, }: {
        resumeData: any;
        toolCallId?: string;
        requestContext?: RequestContext;
    }): Promise<void>;
    /**
     * Respond to a suspended `submit_plan` tool call.
     *
     * `submit_plan` is an agent-agnostic tool that pauses via the native tool-suspension
     * primitive. The Harness layers its planning UX on top of that generic pause here:
     *
     * - On **rejection**, the plan-mode run is resumed with the feedback so the agent can
     *   revise and submit again. This is an ordinary tool resume.
     * - On **approval**, the parked plan-mode suspension is abandoned and the Harness
     *   switches to its default (execution) mode. switchMode aborts the plan-mode run, so
     *   there is no point resuming it first; the next signal/message drives the fresh
     *   default-mode run. The model still sees the "approved" tool result on the rebuilt
     *   message history when the default-mode run starts.
     *
     * Non-Harness consumers (a plain Agent in Studio or a customer app) instead resume the
     * tool directly via `agent.resumeStream({ action, feedback })` — no modes involved.
     */
    private handlePlanApprovalResume;
    private handleToolApprove;
    private handleToolDecline;
    private handleToolResume;
    /**
     * Subscribe to harness events. Returns an unsubscribe function.
     */
    subscribe(listener: HarnessEventListener): () => void;
    private emit;
    private dispatchDisplayStateChanged;
    private dispatchToListeners;
    /**
     * Build the toolsets object that includes built-in harness tools (ask_user, submit_plan,
     * and optionally subagent) plus any user-configured tools.
     * Used by sendMessage, handleToolApprove, and handleToolDecline.
     */
    private buildToolsets;
    /**
     * Build request context for agent execution.
     * Tools can access harness state via requestContext.get('harness').
     */
    private buildRequestContext;
    /**
     * Resolve memory from config — handles both static instances and dynamic factory functions.
     */
    private resolveMemory;
    private persistTokenUsage;
    getWorkspace(): Workspace | undefined;
    /**
     * Eagerly resolve the workspace. For dynamic workspaces (factory function),
     * this triggers resolution and caches the result so getWorkspace() returns it.
     * Useful for code paths outside the request flow (e.g. slash commands).
     */
    resolveWorkspace({ requestContext, }?: {
        requestContext?: RequestContext;
    }): Promise<Workspace | undefined>;
    hasWorkspace(): boolean;
    isWorkspaceReady(): boolean;
    destroyWorkspace(): Promise<void>;
    private startHeartbeats;
    registerHeartbeat(handler: HeartbeatHandler): void;
    removeHeartbeat({ id }: {
        id: string;
    }): Promise<void>;
    stopHeartbeats(): Promise<void>;
    destroy(): Promise<void>;
    getSession(): Promise<HarnessSession>;
    private generateId;
}
export {};
//# sourceMappingURL=harness.d.ts.map