import { SmrtClassOptions, SmrtObject } from '@happyvertical/smrt-core'; type AgentLike = { options: SmrtClassOptions; }; /** * Handler function that processes a single matched interest item * * Called for each item after filtering/qualification. Use to determine * what action to take for each matched item. * * @param item - The matched SmrtObject * @param agent - The agent instance (for accessing agent context/methods) * @returns An action descriptor object (or any value) * * @example * ```typescript * // Simple action descriptor * handler: async (meeting) => ({ * action: 'recap', * meeting * }) * * // Using agent context * handler: async (meeting, agent) => ({ * action: 'analyze', * config: agent.config, * priority: meeting.isUrgent ? 'high' : 'normal' * }) * ``` */ export type InterestHandlerFn = (item: T, agent: A) => Promise | R; /** * Filter object using SDK SQL operator-in-key pattern (AND-only for now) * * Supports operators in keys: * - `{ 'status': 'active' }` → WHERE status = 'active' * - `{ 'price >': 100 }` → WHERE price > 100 * - `{ 'type in': ['a', 'b'] }` → WHERE type IN ('a', 'b') * * Supported operators: =, >, <, >=, <=, !=, in, like */ export type ObjectFilter = Record; /** * Async qualifier function for post-filter processing * * Receives items after SQL filtering, returns filtered/modified items. * Use for filtering that can't be expressed in SQL (e.g., AI-based filtering). * * @example * ```typescript * const qualify: AsyncQualifierFn = async (meetings) => { * return meetings.filter(m => m.isPublic); * }; * ``` */ export type AsyncQualifierFn = (items: T[]) => Promise; /** * Custom query function for complex SQL patterns * * Returns a WHERE clause and parameters for use with collection.query(). * Use for patterns that can't be expressed with standard filters: * - NOT EXISTS subqueries * - JOINs with other tables * - Complex OR conditions * - Window functions * * @param tableName - The main table name (aliased as 't' in the query) * @returns Tuple of [whereClause, params] to append to query * * @example * ```typescript * // Find meetings without corresponding recaps * const query: QueryFn = (t) => [ * `${t}.start_date < datetime('now') AND NOT EXISTS ( * SELECT 1 FROM contents c * WHERE c.meeting_id = ${t}.id * AND c._meta_type = 'MeetingRecap' * )`, * [] * ]; * ``` */ export type QueryFn = (tableName: string) => [sql: string, params: unknown[]]; /** * Single interest filter configuration * * Supports either standard SDK filters OR custom query function, plus * optional sort, limit, and post-query qualification. */ export interface InterestFilter { /** * Optional label for this interest (useful for debugging/logging) */ name?: string; /** * SQL filter object for queries (standard SDK filter) * Merged with global filter using AND logic (object spread) * * Use this for simple AND conditions with standard operators. * For complex queries (NOT EXISTS, JOINs), use `query` instead. */ filter?: ObjectFilter; /** * Custom query function for complex SQL patterns * * When provided, bypasses standard filter and uses collection.query() * with the generated SQL. Supports NOT EXISTS, JOINs, CTEs, etc. * * Cannot be used together with `filter`. */ query?: QueryFn; /** * SQL orderBy format: 'priority DESC' or ['priority DESC', 'name ASC'] */ sort?: string | string[]; /** * Maximum number of items to return for this interest */ limit?: number; /** * Async post-filter function on results * Runs after SQL query returns, enables AI-based or complex filtering */ qualify?: AsyncQualifierFn; /** * Handler function called for each matched item * * Use to determine what action to take for each item. The handler * receives the item and agent instance, and returns an action descriptor. * * @example * ```typescript * handler: async (meeting, agent) => ({ * action: 'recap', * meeting, * config: agent.config * }) * ``` */ handler?: InterestHandlerFn; } /** * Configuration for a specific object type's interest * * Can be a single InterestFilter or an array of InterestFilters. * Arrays allow multiple independent queries for the same object type. * * @example * ```typescript * // Single filter (backward compatible) * const config: ObjectInterestConfig = { * filter: { status: 'active' }, * sort: 'created_at DESC' * }; * * // Multiple filters (new feature) * const config: ObjectInterestConfig = [ * { * name: 'needs-analysis', * filter: { 'agendaUrl !=': null, status: 'scheduled' } * }, * { * name: 'needs-recap', * query: (t) => [ * `${t}.start_date < datetime('now') AND NOT EXISTS ( * SELECT 1 FROM contents WHERE meeting_id = ${t}.id * )`, * [] * ] * } * ]; * ``` */ export type ObjectInterestConfig = InterestFilter | InterestFilter[]; /** * Global interest configuration for an agent * * @example * ```typescript * const interests: InterestOptions = { * filter: { status: 'active' }, * sort: 'created_at DESC', * objects: { * Meeting: { * sort: 'scheduled_at DESC', * filter: { 'scheduled_at >': new Date() }, * limit: 10 * }, * Document: { * filter: { 'type in': ['agenda', 'minutes'] } * } * } * }; * ``` */ export interface InterestOptions { /** * Global sort applied to final combined results * If not specified, results are grouped by type with type-specific sorts */ sort?: string | string[]; /** * Global filter applied to all object types * Merged with object-specific filters using AND logic */ filter?: ObjectFilter; /** * Global async qualifier applied after all object-specific qualifiers */ qualify?: AsyncQualifierFn; /** * Object-specific interest configurations * Keys must match ObjectRegistry class names (case-insensitive lookup) */ objects: { [className: string]: ObjectInterestConfig; }; } /** * Result item from interesting() method * * @example * ```typescript * const items = await agent.interesting(); * for (const { type, data, name, handled } of items) { * console.log(`${type} from filter "${name}": action=${handled?.action}`); * } * ``` */ export interface InterestResult { /** * Object class name from ObjectRegistry */ type: string; /** * The actual SmrtObject instance */ data: T; /** * Name of the filter that matched this item (if specified) * Useful for debugging and logging */ name?: string; /** * Result from handler function (if handler was defined) * Contains the action descriptor returned by the handler */ handled?: R; } /** * Extended agent options including interests */ export interface AgentWithInterestsOptions { /** * Interest configuration for this agent */ interests?: InterestOptions; } /** * Merge global and object-specific filters via object spread. * * Non-colliding keys from both filters are combined (effectively AND-ing them * in the resulting query). On a key collision the object-specific value * **replaces** the global one — `{ ...global, ...object }` — so a per-object * filter overrides the global filter for that key. A global safety filter is * therefore NOT preserved when an object filter sets the same key; choose * distinct keys (or different operators) if both must apply. * * @param globalFilter - Global filter applied to all types * @param objectFilter - Object-specific filter (wins on key collision) * @returns Merged filter object * * @example * ```typescript * // Distinct keys are combined: * mergeFilters({ status: 'active' }, { 'created_at >': date }) * // Returns: { status: 'active', 'created_at >': date } * * // Colliding key: the object value replaces the global one: * mergeFilters({ status: 'active' }, { status: 'archived' }) * // Returns: { status: 'archived' } * ``` */ export declare function mergeFilters(globalFilter?: ObjectFilter, objectFilter?: ObjectFilter): ObjectFilter; /** * Normalize sort to array format * * @param sort - Sort specification (string or array) * @returns Array of sort fields * * @example * ```typescript * normalizeSort('created_at DESC') * // Returns: ['created_at DESC'] * * normalizeSort(['priority DESC', 'name ASC']) * // Returns: ['priority DESC', 'name ASC'] * ``` */ export declare function normalizeSort(sort?: string | string[]): string[]; export {}; //# sourceMappingURL=interests.d.ts.map