/**
 * ToolkitCoordinator - Centralized Assessment Toolkit Service Management
 *
 * Orchestrates all toolkit services (TTS, tools, accessibility, state management) from a single entry point.
 * Provides centralized configuration for tool availability and settings.
 *
 * Key features:
 * - Owns all toolkit services (TTSService, ToolCoordinator, HighlightCoordinator, ElementToolStateStore, AccessibilityCatalogResolver)
 * - Single configuration point for tool availability and settings
 * - Sensible defaults for standalone usage
 * - Direct access for settings widgets (no player dependency)
 * - Clean separation: toolkit concerns only (NOT assessment state like navigation, timing, progress)
 *
 * Part of PIE Assessment Toolkit.
 */
import type { AccessibilityCatalog, AssessmentEntity, AssessmentItemRef } from "@pie-players/pie-players-shared/types";
import { type CanonicalToolsConfig, type ToolPlacementConfig, type ToolPlacementLevel, type ToolPolicyConfig, type ToolProviderConfig, type ToolProvidersConfig } from "./tools-config-normalizer.js";
import { type ToolConfigStrictness } from "./tool-config-validation.js";
import { AccessibilityCatalogResolver } from "./AccessibilityCatalogResolver.js";
import { ElementToolStateStore } from "./ElementToolStateStore.js";
import { type FrameworkErrorModel } from "./framework-error.js";
import { FrameworkErrorBus, type FrameworkErrorListener } from "./framework-error-bus.js";
import { HighlightCoordinator } from "./HighlightCoordinator.js";
import { ToolCoordinator } from "./ToolCoordinator.js";
import { TTSService } from "./TTSService.js";
import { type TTSSpeedOption, type TTSLayoutMode } from "./tts-runtime-config.js";
import type { SREMathSpeechOptions } from "./tts/math-speech.js";
import { ToolProviderRegistry } from "./tool-providers/index.js";
import type { ToolProviderApi } from "./tool-providers/ToolProviderApi.js";
import type { TTSToolProviderConfig } from "./tool-providers/index.js";
import type { ResolvedToolContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap, ToolRegistry } from "./ToolRegistry.js";
import { type PnpEnforcementMode, type PolicySource, type ResolvedEngineInputs, type ToolPolicyChangeListener, type ToolPolicyDecision, type ToolPolicyDecisionRequest } from "../policy/engine.js";
import type { SectionControllerContext, SectionControllerEvent, SectionControllerEventType, SectionControllerFactoryDefaults, SectionControllerHandle, SectionControllerKey, SectionSessionPersistenceStrategy, SectionPersistenceFactoryDefaults } from "./section-controller-types.js";
export type { SectionControllerContext, SectionControllerEvent, SectionControllerEventType, SectionControllerFactoryDefaults, SectionControllerHandle, SectionControllerKey, SectionControllerLoadedRenderable, SectionSessionPersistenceConfig, SectionSessionPersistenceStrategy, SectionControllerRuntimeState, SectionControllerSessionState, SectionPersistenceFactoryDefaults, } from "./section-controller-types.js";
export type { PnpEnforcementMode, ResolvedEngineInputs, ToolPolicyChangeListener, ToolPolicyDecision, ToolPolicyDecisionRequest, } from "../policy/engine.js";
/**
 * Generic tool configuration
 */
export interface ToolConfig {
    enabled?: boolean;
    provider?: unknown;
    settings?: Record<string, unknown>;
    [key: string]: unknown;
}
/**
 * TTS tool configuration
 */
export interface TTSToolConfig extends ToolConfig {
    backend?: "browser" | "polly" | "google" | "server";
    provider?: "polly" | "google" | "custom";
    serverProvider?: "polly" | "google" | "custom";
    engine?: "standard" | "neural";
    sampleRate?: number;
    format?: "mp3" | "ogg" | "pcm";
    speechMarksMode?: "word" | "word+sentence";
    defaultVoice?: string;
    rate?: number;
    pitch?: number;
    apiEndpoint?: string;
    language?: string;
    transportMode?: "pie" | "custom";
    endpointMode?: "synthesizePath" | "rootPost";
    endpointValidationMode?: "voices" | "endpoint" | "none";
    includeAuthOnAssetFetch?: boolean;
    validateEndpoint?: boolean;
    cache?: boolean;
    speedRate?: "slow" | "medium" | "fast";
    lang_id?: string;
    /**
     * Optional inline TTS speed buttons.
     * - Omitted/non-array: default speed buttons are shown.
     * - Empty array: hide speed buttons.
     * - Arrays that sanitize to no valid values: default speed buttons are shown.
     * - Object entries can customize button text while preserving numeric rates.
     */
    speedOptions?: TTSSpeedOption[];
    layoutMode?: TTSLayoutMode;
    /** Speech Rule Engine options for generated MathML speech. */
    mathSpeech?: SREMathSpeechOptions;
    settings?: Record<string, unknown> & {
        mathSpeech?: SREMathSpeechOptions;
    };
    authFetcher?: () => Promise<Partial<TTSToolProviderConfig>>;
}
/**
 * Answer eliminator tool configuration
 */
export interface AnswerEliminatorToolConfig extends ToolConfig {
    strategy?: "strikethrough" | "hide";
}
export interface ToolkitToolsConfig extends CanonicalToolsConfig {
    policy: ToolPolicyConfig;
    placement: Required<ToolPlacementConfig>;
    providers: ToolProvidersConfig;
}
/**
 * Configuration for ToolkitCoordinator
 */
export interface ToolkitCoordinatorConfig {
    /**
     * Unique identifier for the assessment content.
     * Used for scoping tool state across sections.
     */
    assessmentId: string;
    /**
     * Tool availability and configuration.
     * Defaults: all tools enabled with default settings.
     */
    tools?: Partial<CanonicalToolsConfig>;
    /**
     * Validation strictness for tool config contracts.
     * - off: keep diagnostics internal (no warnings or throws)
     * - warn: log diagnostics and continue
     * - error: throw on diagnostics
     *
     * @default "error"
     */
    toolConfigStrictness?: ToolConfigStrictness;
    /**
     * Optional registry used for tool-config validation and provider descriptor resolution.
     * Defaults to packaged PIE tools when omitted.
     */
    toolRegistry?: ToolRegistry | null;
    /**
     * Host-owned per-tool render-context resolvers. These run after
     * framework policy gates (placement, provider config, host policy,
     * PNP/profile rules, and custom policy sources) and can hide a
     * surviving tool or attach render params for the tool registration.
     * They cannot re-enable a tool removed by policy.
     */
    toolContextResolvers?: ToolContextResolverMap;
    /**
     * Accessibility configuration.
     * Includes QTI 3.0 accessibility catalogs and language settings.
     */
    accessibility?: {
        catalogs?: AccessibilityCatalog[];
        language?: string;
    };
    /**
     * Optional lifecycle and extension hooks for runtime customization.
     */
    hooks?: ToolkitCoordinatorHooks;
    /**
     * Lazy initialization mode.
     * When true, async service/provider initialization is deferred until ensure methods are called.
     *
     * @default false
     */
    lazyInit?: boolean;
    /**
     * Internal bootstrap escape hatch used by framework-owned hosts.
     * When true, constructor skips throwing validation and expects caller
     * to pass a pre-validated tools config.
     *
     * @internal
     */
    deferToolConfigValidation?: boolean;
    /**
     * Optional pre-constructed framework-error bus.
     *
     * Pass a bus owned by the embedding host (typically
     * `<pie-assessment-toolkit>`) when the host wants pre-coordinator
     * failures (e.g. `coordinator-init` itself) to flow through the same
     * fan-out as post-coordinator failures. When omitted, the coordinator
     * constructs its own private bus, which is what standalone embeds get.
     *
     * @internal
     */
    frameworkErrorBus?: FrameworkErrorBus;
}
export interface ToolkitErrorContext {
    phase: "coordinator-ready" | "state-load" | "state-save" | "provider-register" | "provider-init" | "tts-init" | "section-controller-init" | "section-controller-dispose";
    providerId?: string;
    details?: Record<string, unknown>;
}
export interface ProviderLifecycleContext {
    providerId: string;
    providerName?: string;
}
export interface ToolkitInitStatus {
    tts: boolean;
    stateLoaded: boolean;
    coordinator: boolean;
    providers: Record<string, boolean>;
}
export interface SectionControllerLifecycleEvent {
    type: "ready" | "disposed";
    key: SectionControllerKey;
    controller?: SectionControllerHandle;
}
/**
 * Subscribe-time arguments for {@link ToolkitCoordinator.subscribeSectionEvents}.
 *
 * Phase D contract: subscriptions follow the toolkit's *active section
 * cohort* automatically. The listener is bound to whatever section
 * controller is active at subscribe time and is migrated, with snapshot
 * replay, on every cohort transition. There is no per-subscription
 * `(sectionId, attemptId)` binding.
 */
export interface SectionEventSubscriptionArgs {
    listener: (event: SectionControllerEvent) => void;
    eventTypes?: readonly SectionControllerEventType[];
    itemIds?: readonly string[];
}
export type SectionItemEventType = Exclude<SectionControllerEventType, "section-navigation-change" | "section-session-applied" | "section-loading-complete" | "section-items-complete-changed" | "section-error">;
export type SectionScopedEventType = Extract<SectionControllerEventType, "section-navigation-change" | "section-session-applied" | "section-loading-complete" | "section-items-complete-changed" | "section-error">;
export type SectionItemEvent = Extract<SectionControllerEvent, {
    type: SectionItemEventType;
}>;
export type SectionScopedEvent = Extract<SectionControllerEvent, {
    type: SectionScopedEventType;
}>;
/**
 * Subscribe-time arguments for {@link ToolkitCoordinator.subscribeItemEvents}.
 *
 * See {@link SectionEventSubscriptionArgs} for the Phase D active-cohort
 * binding contract.
 */
export interface SectionItemEventSubscriptionArgs {
    listener: (event: SectionItemEvent) => void;
    eventTypes?: readonly SectionItemEventType[];
    itemIds?: readonly string[];
}
/**
 * Subscribe-time arguments for
 * {@link ToolkitCoordinator.subscribeSectionLifecycleEvents}.
 *
 * See {@link SectionEventSubscriptionArgs} for the Phase D active-cohort
 * binding contract.
 */
export interface SectionScopedEventSubscriptionArgs {
    listener: (event: SectionScopedEvent) => void;
    eventTypes?: readonly SectionScopedEventType[];
}
export interface ToolkitCoordinatorHooks {
    /**
     * Canonical framework-error hook.
     *
     * Called once per framework-level failure (tool-config validation,
     * provider register / init, TTS bring-up, state load / save, section
     * controller init / dispose, coordinator init). The model carries the
     * canonical {@link FrameworkErrorModel} shape — `kind`, `severity`,
     * `source`, `message`, `details`, `recoverable`, and the original
     * thrown value as `cause`.
     *
     * Listeners should return synchronously and avoid throwing; a thrown
     * hook is caught and logged but does not stop fan-out to the other
     * subscribers (DOM event, prop callback, `subscribeFrameworkErrors`
     * listeners).
     */
    onFrameworkError?: (model: FrameworkErrorModel) => void;
    onBeforeTTSInit?: (context: ToolkitErrorContext) => void | Promise<void>;
    onTTSReady?: () => void | Promise<void>;
    onCoordinatorReady?: (coordinator: ToolkitCoordinator) => void | Promise<void>;
    onProviderRegistered?: (providerId: string, meta: ProviderLifecycleContext) => void | Promise<void>;
    onProviderInitStart?: (providerId: string, meta: ProviderLifecycleContext) => void | Promise<void>;
    onProviderReady?: (providerId: string, meta: ProviderLifecycleContext) => void | Promise<void>;
    onTelemetry?: (eventName: string, payload?: Record<string, unknown>) => void | Promise<void>;
    loadToolState?: () => Record<string, Record<string, unknown>> | Promise<Record<string, Record<string, unknown>> | null | undefined> | null | undefined;
    saveToolState?: (state: Record<string, Record<string, unknown>>) => void | Promise<void>;
    /**
     * Provide section-level controller overrides only.
     * Avoid instantiating per-item controller graphs here unless item lifecycle
     * requirements explicitly demand it.
     */
    createSectionController?: (context: SectionControllerContext, defaults: SectionControllerFactoryDefaults) => SectionControllerHandle | Promise<SectionControllerHandle>;
    createSectionSessionPersistence?: (context: SectionControllerContext, defaults: SectionPersistenceFactoryDefaults) => SectionSessionPersistenceStrategy | Promise<SectionSessionPersistenceStrategy>;
    onSectionControllerReady?: (context: SectionControllerContext, controller: SectionControllerHandle) => void | Promise<void>;
    onSectionControllerDispose?: (context: SectionControllerContext, controller: SectionControllerHandle) => void | Promise<void>;
}
export type ToolkitTelemetryListener = (args: {
    eventName: string;
    payload?: Record<string, unknown>;
}) => void;
/**
 * Service bundle returned by getServiceBundle()
 */
export interface ToolkitServiceBundle {
    ttsService: TTSService;
    toolCoordinator: ToolCoordinator;
    highlightCoordinator: HighlightCoordinator;
    elementToolStateStore: ElementToolStateStore;
    catalogResolver: AccessibilityCatalogResolver;
    toolProviderRegistry: ToolProviderRegistry;
}
/**
 * ToolkitCoordinator - Orchestrates all assessment toolkit services
 *
 * @example
 * ```typescript
 * // Create coordinator with configuration
 * const coordinator = new ToolkitCoordinator({
 *   assessmentId: 'demo-three-questions',
 *   tools: {
 *     providers: {
 *       textToSpeech: { enabled: true, defaultVoice: 'en-US' },
 *       answerEliminator: { enabled: true, strategy: 'strikethrough' }
 *     },
 *     placement: {
 *       item: ['textToSpeech', 'answerEliminator']
 *     }
 *   }
 * });
 *
 * // Pass to section player
 * player.toolkitCoordinator = coordinator;
 *
 * // Access services directly
 * const ttsService = coordinator.ttsService;
 * const toolState = coordinator.elementToolStateStore.getAllState();
 * ```
 */
export declare class ToolkitCoordinator {
    /** Assessment identifier (for scoping tool state) */
    readonly assessmentId: string;
    /** Configuration */
    readonly config: ToolkitCoordinatorConfig;
    /** Managed services (public for direct access) */
    readonly ttsService: TTSService;
    readonly toolCoordinator: ToolCoordinator;
    readonly highlightCoordinator: HighlightCoordinator;
    readonly elementToolStateStore: ElementToolStateStore;
    readonly catalogResolver: AccessibilityCatalogResolver;
    readonly toolProviderRegistry: ToolProviderRegistry;
    readonly hooks: ToolkitCoordinatorHooks;
    readonly lazyInit: boolean;
    /** Track TTS initialization state */
    private ttsInitialized;
    private ttsInitPromise?;
    private ttsReconfigurePromise?;
    private stateLoaded;
    private stateLoadPromise?;
    private coordinatorReadyPromise?;
    private coordinatorReadyNotified;
    private readonly providerInitPromises;
    private readonly toolRegistry;
    private readonly toolContextResolvers;
    private readonly toolContextResolverChangeListeners;
    private readonly sectionControllers;
    private readonly sectionControllerKeys;
    private readonly sectionControllerInitPromises;
    private readonly sectionPersistenceStrategies;
    private readonly sectionControllerLifecycleListeners;
    /**
     * Phase D: every active section-event subscription, indexed by
     * listener identity. The listener follows the toolkit's active
     * section cohort across transitions; this map is the registry the
     * coordinator iterates on every cohort change to detach the listener
     * from the outgoing controller, attach it to the new one, and replay
     * the snapshot (content-loaded × N then section-loading-complete) in
     * canonical order.
     *
     * Dedup is by listener identity: subscribing the same listener
     * function twice replaces the prior subscription's filter args.
     */
    private readonly activeSubscriptions;
    /**
     * Phase D: map key of the section controller currently treated as
     * the *active cohort*. Set by `getOrCreateSectionController` (both
     * the create-new and resolve-existing paths) and cleared when the
     * matching controller is disposed. `null` while no cohort exists,
     * which is the only state where `subscribeSectionEvents` throws.
     */
    private activeCohortMapKey;
    /**
     * Latest requested active cohort. Async controller initialization can
     * resolve out of order; only the most recent request may migrate active
     * subscriptions. Older completions still populate the controller cache.
     */
    private latestRequestedActiveCohortMapKey;
    private readonly telemetryListeners;
    private readonly frameworkErrorBus;
    private readonly ownsFrameworkErrorBus;
    /**
     * Unified Tool Policy Engine. Owned by the coordinator and lives
     * for the lifetime of the coordinator instance — there is no
     * explicit teardown path today; the engine and its listener set
     * are reclaimed by GC when the coordinator becomes unreachable.
     * Subscribers attached via {@link onPolicyChange} must therefore
     * detach via the unsubscribe function the engine returns; do not
     * rely on a `disposed` event being emitted on coordinator teardown.
     *
     * Hosts read decisions via {@link decideToolPolicy} or subscribe
     * to changes via {@link onPolicyChange}.
     */
    private readonly policyEngine;
    /**
     * Host-set override for PNP/profile enforcement. `null` (the default) means
     * "auto" — the coordinator infers the effective mode from the
     * PNP/profile policy inputs the bound `AssessmentEntity` and `AssessmentItemRef`
     * actually carry (see {@link resolveEffectivePnpEnforcement}).
     * `"on"` / `"off"` are explicit host opt-in / opt-out and stick
     * across subsequent assessment / item swaps until the host clears
     * the override by calling `setPnpEnforcement(null)`.
     */
    private pnpEnforcementOverride;
    /**
     * Last assessment passed to {@link updateAssessment}. Read by
     * {@link resolveEffectivePnpEnforcement} to compute auto-mode.
     * The engine's own copy is the canonical record for decisions;
     * this mirror exists only so the auto-mode helper does not need
     * to round-trip through {@link policyEngine}'s frozen snapshot.
     */
    private boundAssessment;
    /**
     * Last item reference passed to {@link updateCurrentItemRef}.
     * Mirrored alongside {@link boundAssessment} so
     * {@link resolveEffectivePnpEnforcement} can detect item-level
     * profile policy inputs (`requiredTools` / `restrictedTools` /
     * `toolParameters`) without round-tripping through the engine's
     * frozen snapshot.
     */
    private boundCurrentItemRef;
    private static resolveConfig;
    constructor(config: ToolkitCoordinatorConfig);
    /**
     * Subscribe the canonical `onFrameworkError` hook adapter to the
     * framework-error bus.
     *
     * Called once from the constructor. The adapter inspects the live
     * `this.hooks` reference, so a hook added later via {@link setHooks}
     * is picked up automatically without re-subscribing.
     */
    private subscribeFrameworkErrorHookAdapters;
    /**
     * Emit a telemetry event to `onTelemetry` hook + all `subscribeTelemetry`
     * listeners.
     *
     * **Naming convention.** Event names MUST be prefixed at the call site,
     * not auto-decorated here. The convention is:
     *
     * - `pie-toolkit-*` for toolkit lifecycle (state load, providers,
     *   coordinator readiness, section-controller register/dispose, TTS
     *   bring-up, tool-config updates, etc.).
     * - `pie-tool-*` for individual tool events (provider init lifecycle,
     *   provider backend calls, tool-specific telemetry forwarded from
     *   `__pieTelemetry`).
     * - `pie-section-*` is reserved for section-player layout events
     *   surfaced via `attachInstrumentationEventBridge` and is not emitted
     *   from this method directly.
     *
     * Anything that does not fit a documented prefix is a deliberate decision
     * to be raised in code review, not a fallback. There is no "auto prefix"
     * here on purpose: it keeps every emit-site honest about which namespace
     * it owns, and lets `subscribeTelemetry` consumers compare against
     * documented strings without per-consumer normalization.
     */
    private emitTelemetry;
    private emitSectionControllerLifecycle;
    private handleError;
    /**
     * Subscribe to framework-error events emitted by this coordinator.
     *
     * See `ToolkitCoordinatorApi.subscribeFrameworkErrors` for the
     * contract. The bus is shared with the canonical
     * `onFrameworkError` lifecycle hook, so a listener registered here
     * sees the same fan-out the hook sees.
     */
    subscribeFrameworkErrors(listener: FrameworkErrorListener): () => void;
    /**
     * Report a framework-error model directly into this coordinator's bus.
     *
     * Used by embedding hosts (e.g. `<pie-assessment-toolkit>`) that
     * pre-construct their own framework-error model in a path that does
     * not go through `handleError` — for example, `runtime-init` failures
     * raised before any coordinator phase, or `tool-config` failures
     * synthesized from validation diagnostics.
     *
     * Hosts that already share their bus via the constructor's
     * `frameworkErrorBus` config field do not need to call this; their
     * own `bus.reportFrameworkError(model)` is observed here.
     *
     * @internal
     */
    reportFrameworkError(model: FrameworkErrorModel): void;
    private getSectionControllerMapKey;
    private createDefaultSectionPersistence;
    private resolveSectionPersistence;
    private setupStatePersistenceHooks;
    private ensureStateLoaded;
    /**
     * Register tool providers in the registry
     */
    private _registerToolProviders;
    private getProviderDescriptorTools;
    private registerProviderFromTool;
    private createToolTelemetryForwarder;
    private addToolTelemetryReporter;
    private registerProvider;
    ensureProviderReady(providerId: string): Promise<ToolProviderApi>;
    setHooks(hooks: ToolkitCoordinatorHooks): void;
    subscribeTelemetry(listener: ToolkitTelemetryListener): () => void;
    getSectionController(args: {
        sectionId: string;
        attemptId?: string;
    }): SectionControllerHandle | undefined;
    subscribeSectionEvents(args: SectionEventSubscriptionArgs): () => void;
    /**
     * Bind a Phase D subscription to a section controller. Detaches any
     * prior controller binding the subscription was holding, attaches a
     * fresh `controller.subscribe(...)` callback, and replays the
     * canonical late-subscribe sequence (content-loaded × N then
     * section-loading-complete) so the listener observes the same
     * ordering a fresh subscriber would have seen.
     *
     * Listener throws are caught and `console.warn`-logged; the throw
     * does not interrupt fan-out to the remaining listeners (matches
     * the {@link FrameworkErrorBus} isolation pattern).
     */
    private bindSubscriptionToController;
    private deliverSectionEventSafely;
    /**
     * Mark the given map key as the active section cohort. Called from
     * `getOrCreateSectionController` (both create-new and resolve-existing
     * paths) so a cohort transition through either path migrates active
     * subscriptions.
     *
     * Same-cohort re-entry is a no-op so a same-cohort `updateInput`
     * (PnP toggle, prompt edit) doesn't double-replay snapshots to
     * already-bound listeners.
     */
    private setActiveCohort;
    private setActiveCohortIfLatestRequest;
    private suspendActiveCohortIfSuperseded;
    /**
     * Clear the active cohort if `mapKey` matches it, detaching every
     * active subscription's current controller binding. Subscriptions
     * stay in the registry — a subsequent `setActiveCohort(...)` will
     * re-bind them to the new controller.
     */
    private clearActiveCohortIfMatches;
    private buildSectionEventPredicate;
    private collectEventItemIds;
    /**
     * Build replay `content-loaded` events for renderables the controller has
     * already finished loading.
     *
     * Strict by design: only renderables explicitly reported in
     * `runtimeState.loadedRenderables` are replayed. Synthetic test harnesses
     * that omit the field (or controllers from older revisions that did not
     * populate it) get an empty replay set rather than a fabricated one — that
     * preserves the contract that replays mirror events that actually fired.
     *
     * Order follows registration order from
     * `SectionController.collectLoadedRenderableSnapshot`, which mirrors the
     * order live `content-loaded` events were emitted in.
     */
    private buildContentLoadedReplayEvents;
    private buildLoadingCompleteReplayEvent;
    /**
     * Subscribe to item-scoped controller events.
     *
     * Same active-cohort binding contract as
     * {@link subscribeSectionEvents}; defaults `eventTypes` to the
     * item-scoped subset.
     */
    subscribeItemEvents(args: SectionItemEventSubscriptionArgs): () => void;
    /**
     * Subscribe to section-scoped controller events.
     *
     * Same active-cohort binding contract as
     * {@link subscribeSectionEvents}; defaults `eventTypes` to the
     * section-scoped subset. Section-scoped events do not carry item
     * identifiers, so this helper intentionally does not expose
     * `itemIds` filtering.
     */
    subscribeSectionLifecycleEvents(args: SectionScopedEventSubscriptionArgs): () => void;
    onSectionControllerLifecycle(listener: (event: SectionControllerLifecycleEvent) => void): () => void;
    getOrCreateSectionController(args: {
        sectionId: string;
        attemptId?: string;
        input?: unknown;
        updateExisting?: boolean;
        createDefaultController: () => SectionControllerHandle | Promise<SectionControllerHandle>;
    }): Promise<SectionControllerHandle>;
    private resolveExistingSectionController;
    private createSectionControllerContext;
    private initializeNewSectionController;
    private finalizeSectionControllerReady;
    private handleSectionControllerInitError;
    disposeSectionController(args: {
        sectionId: string;
        attemptId?: string;
        persistBeforeDispose?: boolean;
        clearPersistence?: boolean;
    }): Promise<void>;
    private runSectionControllerDisposePipeline;
    private finalizeSectionControllerDispose;
    /**
     * Initialize TTS service with provider
     */
    ensureTTSReady(config?: TTSToolConfig): Promise<void>;
    private waitForPendingTTSReconfigure;
    private _initializeTTS;
    private resolveTTSToolConfig;
    private initializeTTSService;
    private ensureBrowserVoicesReady;
    /**
     * Get all services as a bundle for section player convenience.
     * Section player can extract and pass services to child components.
     */
    getServiceBundle(): ToolkitServiceBundle;
    /**
     * Get a tool provider from the registry
     *
     * @param providerId Provider identifier
     * @returns Tool provider instance
     */
    getToolProvider(providerId: string): Promise<ToolProviderApi<any, any>>;
    waitUntilReady(): Promise<void>;
    isReady(): boolean;
    getInitStatus(): ToolkitInitStatus;
    private getTTSConfigFromProviders;
    private assertCanonicalToolId;
    private installToolContextResolvers;
    setToolContextResolvers(resolvers: ToolContextResolverMap | null | undefined): void;
    private notifyToolContextResolverChange;
    /**
     * Check if a tool is enabled.
     * Tools are enabled by default unless explicitly disabled.
     *
     * @param toolId Tool identifier (e.g., 'textToSpeech', 'answerEliminator')
     * @returns True if tool is enabled
     */
    isToolEnabled(toolId: string): boolean;
    /**
     * Get tool configuration.
     *
     * @param toolId Tool identifier
     * @returns Tool configuration or null if not configured
     */
    getToolConfig(toolId: string): ToolProviderConfig | null;
    /**
     * Update tool configuration.
     * Applies changes to underlying services.
     *
     * @param toolId Tool identifier
     * @param updates Partial configuration updates
     */
    updateToolConfig(toolId: "textToSpeech", updates: Partial<TTSToolConfig>): void;
    updateToolConfig(toolId: string, updates: Partial<ToolProviderConfig>): void;
    /**
     * Update the enabled tool list for one placement level.
     *
     * This is the generic placement companion to {@link updateToolConfig}:
     * it validates the next canonical tools config, keeps the policy
     * engine in lockstep, and emits the same policy-change event used by
     * live toolbars/debug panels.
     */
    updateToolPlacement(level: ToolPlacementLevel, toolIds: string[]): void;
    /**
     * Patch one or more placement levels in the canonical tools config.
     */
    updateToolsPlacement(partial: ToolPlacementConfig): void;
    /**
     * Resolve the visible tool set for a given placement level + scope.
     *
     * Thin shim over the owned tool-policy engine.
     */
    decideToolPolicy(request: ToolPolicyDecisionRequest): ToolPolicyDecision;
    /**
     * Subscribe to policy-engine change events. Fires whenever the
     * coordinator's bound inputs change (`updateToolConfig`,
     * `updateToolPlacement`, `updateAssessment`, `updateCurrentItemRef`,
     * `setPnpEnforcement`) or a custom `PolicySource` is registered /
     * removed via {@link registerPolicySource}.
     *
     * The listener receives a `ToolPolicyChangeEvent` with the event
     * `reason` and a frozen snapshot of the engine inputs. Listeners
     * that want the new visible tool set should call
     * {@link decideToolPolicy} with their level / scope.
     *
     * Note: the engine itself can also emit `reason: "disposed"`, but
     * the coordinator does not dispose its engine on teardown today,
     * so subscribers attached via this method will not observe that
     * reason. Detach via the returned unsubscribe function instead of
     * relying on a `disposed` event.
     */
    onPolicyChange(listener: ToolPolicyChangeListener): () => void;
    /**
     * Bind (or clear) the active assessment for PNP/profile policy decisions.
     *
     * Under auto-mode (no host override via {@link setPnpEnforcement}),
     * the coordinator promotes the engine to `pnpEnforcement: "on"`
     * iff the assessment carries any profile precedence material
     * (`personalNeedsProfile`, `settings.districtPolicy`,
     * `settings.testAdministration`) or the currently-bound item ref
     * carries item-level profile policy inputs. A bare assessment record (just
     * `id` / `name`, no PNP, no settings) keeps `"off"`.
     *
     * The host override set via {@link setPnpEnforcement} is sticky
     * across assessment swaps; calling with `null` clears the binding
     * and re-runs the auto-mode helper.
     */
    updateAssessment(assessment: AssessmentEntity | null): void;
    /**
     * Bind (or clear) the current item reference for policy decisions.
     *
     * Used by item-level profile gates (item `requiredTools` /
     * `restrictedTools` / `toolParameters`). Item-level profile material
     * also feeds {@link resolveEffectivePnpEnforcement} — navigating
     * to an item with profile settings can flip auto-mode to `"on"` even
     * when the parent assessment carries no profile block of its own.
     */
    updateCurrentItemRef(itemRef: AssessmentItemRef | null): void;
    /**
     * Override the auto-mode PNP/profile enforcement decision.
     */
    setPnpEnforcement(mode: PnpEnforcementMode | null): void;
    /**
     * Get the policy engine inputs currently driving decisions. Useful
     * for debugging / instrumentation; do not mutate.
     */
    getPolicyInputs(): Readonly<ResolvedEngineInputs>;
    /**
     * Register a custom {@link PolicySource} with the owned policy
     * engine. The source participates in every subsequent
     * {@link decideToolPolicy} call until disposed (the returned
     * function detaches and emits a `policy-source-removed` event).
     *
     * Delegates verbatim to
     * {@link ToolPolicyEngine.registerPolicySource} — see that
     * method for the full contract (event ordering, idempotency of
     * the returned dispose function, and how registered sources
     * compose with the built-in PNP policy source).
     */
    registerPolicySource(source: PolicySource): () => void;
    /**
     * Register a host-owned resolver for one tool's render context.
     *
     * Resolvers are evaluated only for tools that already survived the
     * framework policy pipeline. They can hide the tool for the current
     * scope or attach render params consumed by the packaged registration;
     * they cannot re-enable tools blocked by placement, provider config,
     * host policy, or PNP/profile rules.
     */
    registerToolContextResolver(toolId: string, resolver: ToolContextResolver): () => void;
    hasToolContextResolver(toolId: string): boolean;
    resolveToolContext(context: ToolContextResolverContext): ResolvedToolContext | null;
    onToolContextResolverChange(listener: () => void): () => void;
    /**
     * Compute the effective PNP/profile enforcement mode given the explicit
     * host override and the auto-mode helper.
     *
     * Auto-mode (no override) defers to
     * {@link resolveDefaultPnpEnforcement}, which returns `"on"`
     * exactly when the bound assessment or current item ref carries
     * profile precedence material (PNP, district policy, test
     * administration, item-level required/restricted/parameters), and
     * `"off"` otherwise. Profile gates engage the moment profile material
     * is present.
     */
    private resolveEffectivePnpEnforcement;
    private resolveConfiguredPnpEnforcement;
    /**
     * Apply tool configuration changes to underlying services.
     * Called after updateToolConfig().
     */
    private _applyToolConfigChange;
    private _reconfigureTTSProvider;
}
