/**
 * ActionFilterService — dynamically filters which actions are shown to the LLM
 * based on relevance to the current message.
 *
 * Two-tier ranking:
 *   1. Vector search: embed action descriptions + similes at registration time.
 *      At message time, embed the query (user message + context). Use cosine
 *      similarity to get the top candidates.
 *   2. BM25 reranking: rerank the vector-search candidates using BM25
 *      (term-frequency * inverse-document-frequency). BM25 is especially good
 *      at matching specific keywords that vector search might miss.
 *
 * Graceful degradation:
 *   - If the embedding model is unavailable → BM25-only ranking.
 *   - If BM25 also fails → return all actions (same as before).
 */
import type { Action, IAgentRuntime, Memory, Provider } from "../types/index.ts";
import { Service } from "../types/service.ts";
import type { State } from "../types/state.ts";
declare module "../types/service.ts" {
    interface ServiceTypeRegistry {
        ACTION_FILTER: "action_filter";
    }
}
export interface RankedAction {
    action: Action;
    /** Cosine similarity against the query embedding (0-1 range, 0 if unavailable). */
    vectorScore: number;
    /** BM25 score against the query text (0+ range, 0 if unavailable). */
    bm25Score: number;
    /** Weighted combination of vectorScore and bm25Score, plus momentum boost. */
    combinedScore: number;
}
export interface FilterConfig {
    /** Master switch — if false the service is a no-op. */
    enabled: boolean;
    /** Minimum registered action count before filtering kicks in. */
    threshold: number;
    /** How many candidates to pull from the vector search stage. */
    vectorTopK: number;
    /** Final number of actions returned after reranking. */
    finalTopK: number;
    /** Weight for the normalized vector score in the combined score (0-1). */
    vectorWeight: number;
    /** Weight for the normalized BM25 score in the combined score (0-1). */
    bm25Weight: number;
    /** Action names that always bypass filtering (in addition to per-action alwaysInclude). */
    alwaysIncludeActions: string[];
    /** Time window (ms) for conversation momentum decay. */
    momentumDecayMs: number;
    /** Score boost for recently used actions (0-1). */
    momentumBoost: number;
}
export interface FilterMetrics {
    /** Total number of filter() invocations. */
    filterCalls: number;
    /** How many times filtering was actually applied (vs. passthrough). */
    filteredCalls: number;
    /** How many times we fell back to BM25-only (embedding unavailable). */
    bm25OnlyFallbacks: number;
    /** How many times we fell back to returning all actions (complete failure). */
    fullFallbacks: number;
    /** Reported misses — actions that were filtered out but then selected by the LLM. */
    missCount: number;
    /** Names of missed actions for debugging (bounded ring buffer). */
    missedActions: string[];
    /** Average combined-score of returned actions (last call). */
    lastAvgScore: number;
    /** Number of actions in the embedding index. */
    indexedActionCount: number;
    /** Number of actions whose embedding failed during buildIndex or addAction. */
    embedFailureCount: number;
}
/**
 * Build a rich text blob from an action's metadata, suitable for both
 * embedding and BM25 indexing.
 */
export declare function getActionEmbeddingText(action: Action): string;
/**
 * Build a text blob from a provider's metadata for BM25 indexing.
 * Includes name, description, and relevanceKeywords.
 */
export declare function getProviderIndexText(provider: Provider): string;
/**
 * Build the query text used for vector + BM25 matching against the action
 * index. Includes the user message, recent conversation context, and any
 * detected intent keywords.
 */
export declare function buildQueryText(message: Memory, state: State): string;
/**
 * Normalize an array of scores to [0, 1] using min-max normalization.
 * Returns an array of the same length. If all values are the same,
 * returns an array of 1s (or 0s if all are 0).
 *
 * NaN and Infinity values are sanitized to 0 before normalization.
 */
export declare function minMaxNormalize(scores: number[]): number[];
export declare class ActionFilterService extends Service {
    static serviceType: "action_filter";
    capabilityDescription: string;
    private actionEmbeddings;
    private bm25Index;
    /** Separate BM25 index for provider descriptions, used by filterProviders(). */
    private providerBM25Index;
    private filterConfig;
    private recentActions;
    private readonly maxRecentActions;
    private lastFilteredByRoom;
    private readonly maxTrackedRooms;
    private metrics;
    private embeddingAvailable;
    constructor(runtime?: IAgentRuntime, config?: Partial<FilterConfig>);
    /** Start the service. Reads ACTION_FILTER_* from runtime settings, then builds indices. */
    static start(runtime: IAgentRuntime): Promise<Service>;
    stop(): Promise<void>;
    /**
     * Build (or rebuild) the vector + BM25 index for all registered actions.
     * Also builds the provider BM25 index for dynamic provider filtering.
     */
    buildIndex(runtime: IAgentRuntime): Promise<void>;
    /**
     * Add a single action to the index at runtime (e.g. when a plugin
     * registers a new action after startup).
     */
    addAction(action: Action, runtime: IAgentRuntime): Promise<void>;
    /**
     * Remove an action from both indices (e.g. when a plugin is unloaded).
     */
    removeAction(actionName: string): void;
    /**
     * Filter the registered actions to the most relevant subset for this message.
     *
     * Flow:
     *  1. If action count <= threshold → return all (same as validate-all path).
     *  2. Always-include actions bypass filtering and are prepended to results.
     *  3. Vector search: embed query → cosine similarity → top vectorTopK.
     *  4. BM25 rerank: score vectorTopK candidates → combine scores.
     *  5. Apply momentum boost for recently used actions.
     *  6. Return top finalTopK actions.
     *
     * The returned actions have NOT been validated — the caller (actionsProvider)
     * is responsible for running `validate()` on the returned set.
     */
    filter(runtime: IAgentRuntime, message: Memory, state: State): Promise<Action[]>;
    /**
     * Score providers by relevance to the current message using BM25.
     * Returns provider names sorted by relevance score, highest first.
     * Only scores providers that have been indexed (i.e. have a description).
     *
     * This is used by composeState() to auto-include dynamic providers
     * that are relevant to the current message, without requiring explicit
     * relevanceKeywords on each provider.
     *
     * @param providers - The candidate providers to score (typically dynamic providers).
     * @param message - The current message being processed.
     * @param state - The current state (used to build query context).
     * @param topK - Maximum number of provider names to return (default: 5).
     * @returns Provider names sorted by descending BM25 relevance score.
     */
    filterProviders(providers: Provider[], message: Memory, state: State, topK?: number): string[];
    /**
     * Record that an action was used, so future queries in the same room
     * receive a momentum boost for that action.
     */
    recordActionUse(actionName: string, roomId: string): void;
    getMetrics(): FilterMetrics;
    reportMiss(actionName: string): void;
    hasAction(actionName: string): boolean;
    getConfig(): Readonly<FilterConfig>;
    /**
     * Check whether an action was in the most recent filtered set for a room.
     * Returns `true` if filtering was active for that room and the action
     * WAS in the filtered set, `false` if it was filtered OUT, or `null` if
     * filtering wasn't active for that room (so the caller should skip
     * false-negative reporting).
     */
    wasActionInFilteredSet(actionName: string, roomId: string): boolean | null;
    /**
     * Run the full two-tier ranking pipeline on a set of candidate actions.
     * Returns RankedAction[] sorted by combinedScore descending.
     */
    private rankActions;
    /**
     * Compute per-action momentum boosts based on recently used actions
     * in the same room as the current message.
     */
    private computeMomentumBoosts;
}
//# sourceMappingURL=action-filter.d.ts.map