/** * 🧠 Brainy 3.0 Type Definitions * * Beautiful, consistent, type-safe interfaces for the future of neural databases */ import { Vector } from '../coreTypes.js' import { NounType, VerbType } from './graphTypes.js' // ============= Core Types ============= /** * Entity (Noun) β€” the fundamental data unit in Brainy * * **Data vs Metadata:** * - `data`: Content used for vector embeddings. Searchable via **semantic similarity** * (HNSW index) and hybrid text+semantic search. NOT queryable via `where` filters. * - `metadata`: Structured fields indexed by MetadataIndex. Queryable via `where` * filters in `find()`. Standard system fields (noun, createdAt, etc.) are stored * alongside user metadata but extracted to top-level Entity fields on read. */ export interface Entity { /** Unique identifier (UUID v4) */ id: string /** Embedding vector (384-dim by default). Empty array when loaded without includeVectors. */ vector: Vector /** Entity type classification (NounType enum) */ type: NounType /** * Per-product sub-classification within the NounType (e.g. a `Person` entity might * have `subtype: 'employee'` or `'customer'`; a `Document` might have `subtype: 'invoice'`). * Flat string, no hierarchy. Top-level standard field β€” indexed on the fast path and * rolled into per-NounType statistics. */ subtype?: string /** Opaque content β€” used for embeddings and semantic search. Not indexed by MetadataIndex. */ data?: any /** User-defined structured fields β€” indexed and queryable via `where` filters. */ metadata?: T /** Multi-tenancy service identifier */ service?: string /** Creation timestamp (ms since epoch) */ createdAt: number /** Last update timestamp (ms since epoch) */ updatedAt?: number /** Source that created this entity (e.g., augmentation info) */ createdBy?: string /** Type classification confidence (0-1) */ confidence?: number /** Entity importance/salience (0-1) */ weight?: number /** * Monotonic revision counter, auto-bumped on every successful `update()`. * Starts at `1` on `add()`. Pre-7.31.0 entities without `_rev` are read as `1`. * Pass back as `update({ id, ..., ifRev: _rev })` for optimistic-concurrency CAS β€” * throws `RevisionConflictError` if the persisted rev moved since read. */ _rev?: number } /** * Relation (Verb) β€” a typed edge connecting two entities * * **Data vs Metadata (on relationships):** * - `data`: Opaque content stored on the relationship. If provided during relate(), * overrides the auto-computed vector (default: average of source+target vectors). * - `metadata`: Structured queryable fields on the edge (e.g., role, startDate). */ export interface Relation { /** Unique identifier (UUID v4) */ id: string /** Source entity ID */ from: string /** Target entity ID */ to: string /** Relationship type classification (VerbType enum) */ type: VerbType /** * Per-product sub-classification within the VerbType (e.g. a `Manages` * relationship might have `subtype: 'direct'` vs `'dotted-line'`; a `RelatedTo` * edge might carry `'spouse'` / `'sibling'` / `'colleague'`). Flat string, no * hierarchy. Top-level standard field β€” indexed on the fast path and rolled into * per-VerbType statistics so queries like `getRelations({ verb, subtype })` hit * the column-store directly. */ subtype?: string /** Connection strength (0-1, default: 1.0) */ weight?: number /** Opaque content for the relationship (overrides auto-computed vector if provided) */ data?: any /** User-defined structured fields on the edge */ metadata?: T /** Multi-tenancy service identifier */ service?: string /** Creation timestamp (ms since epoch) */ createdAt: number /** Last update timestamp (ms since epoch) */ updatedAt?: number /** Relationship certainty (0-1) */ confidence?: number /** Evidence for why this relationship was detected */ evidence?: RelationEvidence } /** * Evidence for why a relationship was detected */ export interface RelationEvidence { sourceText?: string // Text that indicated this relationship position?: { // Position in source text start: number end: number } method: 'neural' | 'pattern' | 'structural' | 'explicit' // How it was detected reasoning?: string // Human-readable explanation } /** * Search result with similarity score * * Flattens commonly-used entity fields to top level for convenience, * while preserving full entity in 'entity' field for backward compatibility. */ export interface Result { // Search metadata id: string score: number // Convenience: Common entity fields flattened to top level type?: NounType // Entity type (from entity.type) subtype?: string // Per-product sub-classification (from entity.subtype) metadata?: T // Entity metadata (from entity.metadata) data?: any // Entity data (from entity.data) confidence?: number // Type classification confidence (from entity.confidence) weight?: number // Entity importance (from entity.weight) _rev?: number // Monotonic revision counter (from entity._rev) β€” pass back as update({ ifRev }) for CAS // Full entity (preserved for backward compatibility) entity: Entity // Score transparency explanation?: ScoreExplanation // Match visibility - shows what matched in hybrid search textMatches?: string[] // Query words found in entity (e.g., ["david", "warrior"]) textScore?: number // Normalized text match score (0-1) semanticScore?: number // Semantic similarity score (0-1) matchSource?: 'text' | 'semantic' | 'both' // Where this result came from rrfScore?: number // Raw RRF fusion score (for advanced ranking analysis) // Aggregation: present only on rows returned by find({ aggregate }). These mirror the // documented AggregateResult shape so callers can read group/metric data at the top level // instead of digging into `metadata`. (The same values are also flattened into `metadata` // for backward compatibility.) groupKey?: Record // Group-by key values for this aggregate row metrics?: Record // Computed metric values (sum/avg/min/max/count) count?: number // Total entity count in this group } /** * Score explanation for transparency */ export interface ScoreExplanation { vectorScore?: number metadataScore?: number graphScore?: number boosts?: Record penalties?: Record } // ============= Operation Parameters ============= /** * Parameters for adding entities * * **Data vs Metadata:** * - `data` is embedded into a vector and searchable via semantic similarity (HNSW). * It is NOT indexed by MetadataIndex and NOT queryable via `where` filters. * - `metadata` is indexed by MetadataIndex and queryable via `where` filters in `find()`. */ export interface AddParams { /** Content to embed and store. Strings are auto-embedded; objects are JSON-stringified for embedding. */ data: any | Vector /** Entity type classification (required) */ type: NounType /** * Per-product sub-classification within the NounType (e.g. a `Person` entity might have * `subtype: 'employee'` or `'customer'`; a `Document` might have `subtype: 'invoice'`). * Flat string, no hierarchy β€” consumers choose the vocabulary. Indexed and rolled up into * per-NounType statistics for fast `find({ type, subtype })` filtering and `groupBy:['subtype']` * aggregation on the standard-field fast path. */ subtype?: string /** Structured queryable fields β€” indexed by MetadataIndex, used in `where` filters */ metadata?: T /** Custom entity ID (auto-generated UUID v4 if not provided) */ id?: string /** Pre-computed embedding vector (skips auto-embedding when provided) */ vector?: Vector /** Multi-tenancy service identifier */ service?: string /** Type classification confidence (0-1) */ confidence?: number /** Entity importance/salience (0-1) */ weight?: number /** Track which augmentation created this entity */ createdBy?: { augmentation: string; version: string } /** * Conditional insert. When `true` AND a custom `id` is supplied AND an entity with * that `id` already exists, `add()` returns the existing `id` without writing β€” no * throw, no overwrite. Used for idempotent bootstrap and create-or-noop patterns. * Ignored when `id` is omitted (a freshly generated UUID can never collide). */ ifAbsent?: boolean } /** * Parameters for updating entities */ export interface UpdateParams { id: string // Entity to update data?: any // New content to re-embed type?: NounType // Change type subtype?: string // Change subtype (set to '' or null-equivalent via dedicated unset is future work) metadata?: Partial // Metadata to update merge?: boolean // Merge or replace metadata (default: true) vector?: Vector // New pre-computed vector confidence?: number // Update type classification confidence weight?: number // Update entity importance/salience /** * Optimistic concurrency check. When provided, the update fails with * `RevisionConflictError` if the persisted entity's `_rev` does not equal `ifRev`. * `_rev` is auto-bumped on every successful update β€” read it from the entity returned * by `get()` / `find()` / `search()`. Omit to skip the check (unconditional update). */ ifRev?: number } /** * Parameters for creating relationships * * **Data vs Metadata (on relationships):** * - `data`: Opaque content for the edge. If provided, overrides the auto-computed * vector (default: average of source+target entity vectors). * - `metadata`: Structured queryable fields on the edge. */ export interface RelateParams { /** Source entity ID (required β€” must exist) */ from: string /** Target entity ID (required β€” must exist) */ to: string /** Relationship type classification (required) */ type: VerbType /** * Per-product sub-classification within the VerbType (e.g. a `Manages` * relationship might have `subtype: 'direct'` or `'dotted-line'`; a `RelatedTo` * edge might carry `'spouse'` or `'colleague'`). Flat string, no hierarchy. * Indexed and rolled up into per-VerbType statistics for fast filtering * (`getRelations({ verb, subtype })`) and aggregation (`groupBy:['subtype']`). */ subtype?: string /** Connection strength (0-1, default: 1.0) */ weight?: number /** Content for the relationship (optional β€” overrides auto-computed vector) */ data?: any /** Structured queryable fields on the edge */ metadata?: T /** Create reverse edge too (default: false) */ bidirectional?: boolean /** Multi-tenancy service identifier */ service?: string /** Relationship certainty (0-1) */ confidence?: number /** Evidence for why this relationship exists */ evidence?: RelationEvidence } /** * Parameters for updating relationships */ export interface UpdateRelationParams { id: string // Relation to update type?: VerbType // Change verb type subtype?: string // Change sub-classification (omit to preserve existing) weight?: number // New weight confidence?: number // New confidence (0-1) data?: any // New content metadata?: Partial // Metadata to update merge?: boolean // Merge or replace metadata } // ============= Query Parameters ============= /** * Unified find parameters β€” Triple Intelligence search * * Combines three search dimensions in one query: * - **Vector:** `query` or `vector` for semantic/hybrid similarity search (searches `data`) * - **Metadata:** `where` for structured field filters (queries `metadata` via MetadataIndex) * - **Graph:** `connected` for relationship traversal (via GraphAdjacencyIndex) * * See also: [Query Operators](../../docs/QUERY_OPERATORS.md) for all `where` operators. */ export interface FindParams { // Vector Intelligence /** Natural language or semantic search query (embedded and matched via HNSW + text index) */ query?: string /** Direct vector search (pre-computed embedding) */ vector?: Vector // Metadata Intelligence /** Filter by entity type(s). Alias for `where.noun`. */ type?: NounType | NounType[] /** * Filter by per-product subtype (top-level standard field β€” uses the fast path, not the * metadata fallback). Pass a single string for equality, or an array for set membership * (e.g. `subtype: ['employee', 'contractor']`). For operator-form predicates (e.g. * `{ exists: true }`, `{ missing: true }`) use `where: { subtype: { …operators… } }`. */ subtype?: string | string[] /** Metadata filters using BFO operators (e.g., `{ year: { greaterThan: 2020 } }`) */ where?: Partial // Graph Intelligence connected?: GraphConstraints // Proximity search near?: { id: string // Find near this entity threshold?: number // Min similarity (0-1) } // Control options limit?: number // Max results (default: 10) offset?: number // Skip N results cursor?: string // Cursor-based pagination // Sorting orderBy?: string // Field to sort by (e.g., 'createdAt', 'title', 'metadata.priority') order?: 'asc' | 'desc' // Sort direction: 'asc' (default) or 'desc' // Advanced options mode?: SearchMode // Search strategy explain?: boolean // Return scoring explanation includeRelations?: boolean // Include entity relationships excludeVFS?: boolean // Exclude VFS entities from results (default: false - VFS included) service?: string // Multi-tenancy filter // Hybrid search options searchMode?: 'auto' | 'text' | 'semantic' | 'vector' | 'hybrid' // Search strategy: auto (default), text-only, semantic/vector-only, or explicit hybrid hybridAlpha?: number // Weight between text (0.0) and semantic (1.0) search, default: auto-detected by query length // Triple Intelligence Fusion fusion?: { strategy?: 'adaptive' | 'weighted' | 'progressive' weights?: { vector?: number graph?: number field?: number } } // Performance options writeOnly?: boolean // Skip validation for high-speed ingestion // Aggregation /** Query a named aggregate definition. String shorthand or full query params. */ aggregate?: string | AggregateQueryParams } /** * Graph constraints for search */ export interface GraphConstraints { to?: string // Connected to this entity from?: string // Connected from this entity via?: VerbType | VerbType[] // Via these relationship types type?: VerbType | VerbType[] // Alias for via /** * Filter traversal edges by VerbType subtype. Single string for equality, * array for set membership. Composes with `via` β€” `{ via: 'manages', subtype: * 'direct' }` traverses only direct-management edges, not dotted-line. Edges * without a subtype value are excluded when this filter is set. */ subtype?: string | string[] depth?: number // Max traversal depth (default: 1) direction?: 'in' | 'out' | 'both' // Direction of traversal (default: 'both') bidirectional?: boolean // Consider both directions } /** * Search modes */ export type SearchMode = | 'auto' // Automatically choose best mode (default - enables hybrid text+semantic) | 'vector' // Pure vector search (semantic only) | 'semantic' // Alias for vector search | 'text' // Pure text/keyword search | 'metadata' // Pure metadata filtering | 'graph' // Pure graph traversal | 'hybrid' // Combine all intelligences (explicit hybrid mode) /** * Parameters for similarity search */ export interface SimilarParams { to: string | Entity | Vector // Find similar to this limit?: number // Max results (default: 10) threshold?: number // Min similarity score type?: NounType | NounType[] // Restrict to types where?: Partial // Additional filters service?: string // Multi-tenancy excludeVFS?: boolean // Exclude VFS entities (default: false - VFS included) } /** * Parameters for getting relationships * * All parameters are optional. When called without parameters, returns all relationships * with pagination (default limit: 100). * * @example * ```typescript * // Get all relationships (default limit: 100) * const all = await brain.getRelations() * * // Get relationships from a specific entity (string shorthand) * const fromEntity = await brain.getRelations(entityId) * * // Equivalent to: * const fromEntity2 = await brain.getRelations({ from: entityId }) * * // Get relationships to a specific entity * const toEntity = await brain.getRelations({ to: entityId }) * * // Filter by relationship type * const friends = await brain.getRelations({ type: VerbType.FriendOf }) * * // Pagination * const page2 = await brain.getRelations({ offset: 100, limit: 50 }) * * // Combined filters * const filtered = await brain.getRelations({ * from: entityId, * type: VerbType.WorksWith, * limit: 20 * }) * ``` * * Fixed bug where calling without parameters returned empty array * Added string ID shorthand syntax */ export interface GetRelationsParams { /** * Filter by source entity ID * * Returns all relationships originating from this entity. */ from?: string /** * Filter by target entity ID * * Returns all relationships pointing to this entity. */ to?: string /** * Filter by relationship type(s) * * Can be a single VerbType or array of VerbTypes. */ type?: VerbType | VerbType[] /** * Filter by VerbType subtype * * Top-level standard field β€” uses the fast path, not the metadata fallback. * Pass a single string for equality (e.g. `subtype: 'direct'`), or an array * for set membership (e.g. `subtype: ['direct', 'dotted-line']`). */ subtype?: string | string[] /** * Maximum number of results to return * * @default 100 */ limit?: number /** * Number of results to skip (offset-based pagination) * * @default 0 */ offset?: number /** * Cursor for cursor-based pagination * * More efficient than offset for large result sets. */ cursor?: string /** * Filter by service (multi-tenancy) * * Only return relationships belonging to this service. */ service?: string } // ============= Batch Operations ============= /** * Batch add parameters */ export interface AddManyParams { items: AddParams[] // Items to add parallel?: boolean // Process in parallel (default: true) chunkSize?: number // Batch size (default: 100) onProgress?: (done: number, total: number) => void continueOnError?: boolean // Continue if some fail /** * Conditional insert applied to every item. Equivalent to setting `ifAbsent: true` * on each item individually. Item-level `ifAbsent` overrides the batch flag. */ ifAbsent?: boolean } /** * Batch update parameters */ export interface UpdateManyParams { items: UpdateParams[] // Items to update parallel?: boolean chunkSize?: number onProgress?: (done: number, total: number) => void continueOnError?: boolean } /** * Batch delete parameters */ export interface DeleteManyParams { ids?: string[] // Specific IDs to delete type?: NounType // Delete all of type where?: any // Delete by metadata limit?: number // Max to delete (safety) onProgress?: (done: number, total: number) => void continueOnError?: boolean // Continue processing if a delete fails } /** * Batch relate parameters */ export interface RelateManyParams { items: RelateParams[] // Relations to create parallel?: boolean chunkSize?: number onProgress?: (done: number, total: number) => void continueOnError?: boolean } /** * Batch result */ export interface BatchResult { successful: T[] // Successfully processed items failed: Array<{ // Failed items with errors item: any error: string }> total: number // Total attempted duration: number // Time taken in ms } // ============= Import Progress ============= /** * Import stage enumeration */ export type ImportStage = | 'detecting' // Detecting file format | 'reading' // Reading file from disk/network | 'parsing' // Parsing file structure (CSV rows, PDF pages, Excel sheets) | 'extracting' // Extracting entities using AI | 'indexing' // Creating graph nodes and relationships | 'completing' // Final cleanup and stats /** * Overall import status */ export type ImportStatus = | 'starting' // Initializing import | 'processing' // Actively importing | 'completing' // Finalizing | 'done' // Complete /** * Comprehensive import progress information * * Provides multi-dimensional progress tracking: * - Bytes processed (always deterministic) * - Entities extracted and indexed * - Stage-specific progress * - Time estimates * - Performance metrics * */ export interface ImportProgress { // Overall Progress overall_progress: number // 0-100 weighted estimate across all stages overall_status: ImportStatus // High-level status // Current Stage stage: ImportStage // What's happening now stage_progress: number // 0-100 within current stage (0 if unknown) stage_message: string // Human-readable: "Extracting entities from PDF..." // Bytes (Always Available - most deterministic metric) bytes_processed: number // Bytes read/processed so far total_bytes: number // Total file size (0 if streaming/unknown) bytes_percentage: number // Convenience: bytes_processed / total_bytes * 100 bytes_per_second?: number // Processing rate (relevant during parsing) // Entities (Available when extraction starts) entities_extracted: number // Entities found during AI extraction entities_indexed: number // Entities added to Brainy graph entities_per_second?: number // Entities/sec (relevant during extraction/indexing) estimated_total_entities?: number // Estimated final count estimation_confidence?: number // 0-1 confidence in estimation // Timing elapsed_ms: number // Time since import started estimated_remaining_ms?: number // Estimated time remaining estimated_total_ms?: number // Estimated total time // Context (helps users understand what's happening) current_item?: string // "Processing page 5 of 23" current_file?: string // "Sheet: Q2 Sales Data" file_number?: number // 3 (when importing multiple files) total_files?: number // 10 // Performance Metrics (for debugging/optimization) metrics?: { parsing_rate_mbps?: number // MB/s during parsing extraction_rate_entities_per_sec?: number // Entities/s during extraction indexing_rate_entities_per_sec?: number // Entities/s during indexing memory_usage_mb?: number // Current memory usage peak_memory_mb?: number // Peak memory usage } // Backwards Compatibility (for legacy code) current: number // Alias for entities_indexed total: number // Alias for estimated_total_entities or 0 } /** * Import progress callback - backwards compatible * * Supports both legacy (current, total) and new (ImportProgress object) signatures */ export type ImportProgressCallback = | ((progress: ImportProgress) => void) | ((current: number, total: number) => void) /** * Stage weight configuration for overall progress calculation * * These weights reflect the typical time distribution across stages. * Extraction is typically the slowest stage (60% of time). */ export interface StageWeights { detecting: number // Default: 0.01 (1%) reading: number // Default: 0.05 (5%) parsing: number // Default: 0.10 (10%) extracting: number // Default: 0.60 (60% - slowest!) indexing: number // Default: 0.20 (20%) completing: number // Default: 0.04 (4%) } /** * Import result statistics */ export interface ImportStats { graphNodesCreated: number // Entities added to graph graphEdgesCreated: number // Relationships created vfsFilesCreated: number // VFS files created duration: number // Total time in ms bytesProcessed: number // Total bytes read averageRate: number // Average entities/sec peakMemoryMB?: number // Peak memory usage } /** * Import operation result */ export interface ImportResult { success: boolean stats: ImportStats errors?: Array<{ stage: ImportStage message: string error?: any }> } // ============= Advanced Operations ============= /** * Options for brain.get() entity retrieval * * **Performance Optimization**: * By default, brain.get() loads ONLY metadata (not vectors), resulting in: * - **76-81% faster** reads (10ms vs 43ms for metadata-only) * - **95% less bandwidth** (300 bytes vs 6KB per entity) * - **87% less memory** (optimal for VFS and large-scale operations) * * **When to use includeVectors**: * - Computing similarity on a specific entity (not search): `brain.similar({ to: entity.vector })` * - Manual vector operations: `cosineSimilarity(entity.vector, otherVector)` * - Inspecting embeddings for debugging * * **When NOT to use includeVectors** (metadata-only is sufficient): * - VFS operations (readFile, stat, readdir) - 100% of cases * - Existence checks: `if (await brain.get(id))` * - Metadata inspection: `entity.metadata`, `entity.data`, `entity.type` * - Relationship traversal: `brain.getRelations({ from: id })` * - Search operations: `brain.find()` generates embeddings automatically * * @example * ```typescript * // βœ… FAST (default): Metadata-only - 10ms, 300 bytes * const entity = await brain.get(id) * console.log(entity.data, entity.metadata) // βœ… Available * console.log(entity.vector) // Empty Float32Array (stub) * * // βœ… FULL: Load vectors when needed - 43ms, 6KB * const fullEntity = await brain.get(id, { includeVectors: true }) * const similarity = cosineSimilarity(fullEntity.vector, otherVector) * * // βœ… VFS automatically uses fast path (no change needed) * await vfs.readFile('/file.txt') // 53ms β†’ 10ms (81% faster) * ``` * */ export interface GetOptions { /** * Include 384-dimensional vector embeddings in the response * * **Default: false** (metadata-only for 76-81% speedup) * * Set to `true` when you need to: * - Compute similarity on this specific entity's vector * - Perform manual vector operations * - Inspect embeddings for debugging * * **Note**: Search operations (`brain.find()`) generate vectors automatically, * so you don't need this flag for search. Only for direct vector operations * on a retrieved entity. * * @default false */ includeVectors?: boolean } /** * Graph traversal parameters */ export interface TraverseParams { from: string | string[] // Starting node(s) direction?: 'out' | 'in' | 'both' // Traversal direction types?: VerbType[] // Edge types to follow depth?: number // Max depth (default: 2) strategy?: 'bfs' | 'dfs' // Breadth or depth first filter?: (entity: Entity, depth: number, path: string[]) => boolean limit?: number // Max nodes to visit } // ============= Aggregation Engine Types ============= /** * Supported aggregation operations */ export type AggregationOp = | 'sum' | 'count' | 'avg' | 'min' | 'max' | 'stddev' | 'variance' /** Exact percentile (requires `p` in `[0,1]` on the metric def) β€” value-multiset, delete-safe. */ | 'percentile' /** Exact count of distinct values β€” value-multiset, delete-safe. */ | 'distinctCount' /** * Time window granularity for GROUP BY time dimensions */ export type TimeWindowGranularity = | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' | { seconds: number } /** * A GROUP BY dimension β€” one of: * - a plain metadata field name (string), * - a time-windowed field (`{ field, window }`), or * - an **unnest** field (`{ field, unnest: true }`): the field holds an array, and the entity * contributes once to a group per distinct element (e.g. `tags: string[]` β†’ tag frequency). * An entity whose unnest field is missing or an empty array contributes to no group. */ export type GroupByDimension = | string | { field: string; window: TimeWindowGranularity } | { field: string; unnest: true } /** * Source filter for which entities feed into an aggregate */ export interface AggregateSource { /** Filter by entity type(s) */ type?: NounType | NounType[] /** Metadata filter (same syntax as find({ where })) */ where?: Record /** Multi-tenancy service filter */ service?: string } /** * Full aggregate definition β€” registered via brain.defineAggregate() */ export interface AggregateDefinition { /** Unique name for this aggregate (used in queries) */ name: string /** Which entities contribute to this aggregate */ source: AggregateSource /** Dimensions to group by */ groupBy: GroupByDimension[] /** Named metrics to compute */ metrics: Record /** Control materialization of results as NounType.Measurement entities */ materialize?: boolean | { debounceMs?: number; trackSources?: boolean } } /** * Single metric definition within an aggregate */ export interface AggregateMetricDef { /** Aggregation operation */ op: AggregationOp /** Metadata field to aggregate (required for all ops except count) */ field?: string /** Percentile fraction in `[0, 1]` β€” required when `op === 'percentile'`, ignored otherwise. */ p?: number } /** * Internal running state for a single metric. * Tracks enough to compute all operations incrementally. */ export interface MetricState { sum: number count: number min: number max: number /** Running M2 for Welford's online variance (sum of squared differences from mean) */ m2?: number /** * Value multiset (String(value) β†’ occurrence count) for exact percentile + distinctCount. * Maintained only for `percentile`/`distinctCount` metrics. JSON-serializable; mirrors * Cortex's `value_counts` so JS and native agree bit-for-bit. */ valueCounts?: Record } /** * Internal state for one aggregate group (one combination of group key values) */ export interface AggregateGroupState { /** The group key values (e.g., { category: 'food', period: '2024-01' }) */ groupKey: Record /** Running metric states keyed by metric name */ metrics: Record /** Entity ID of the materialized Measurement entity (if materialized) */ materializedEntityId?: string /** Timestamp of last update */ lastUpdated: number } /** * Query parameters for reading aggregate results */ export interface AggregateQueryParams { /** Name of the aggregate to query */ name: string /** Filter aggregate groups by their key values */ where?: Record /** * Filter groups by their computed METRIC values (SQL HAVING). Same BFO operators as * `where`, but applied to the derived metric results plus `count`, e.g. * `{ revenue: { greaterThan: 1000 } }`. Evaluated per group (O(groups), independent of * entity count), before sort/pagination. */ having?: Record /** Sort by metric name or group key field */ orderBy?: string /** Sort direction */ order?: 'asc' | 'desc' /** Max results */ limit?: number /** Skip N results */ offset?: number } /** * A single aggregate result row */ export interface AggregateResult { /** Group key values for this row */ groupKey: Record /** Computed metric values (derived from MetricState based on op) */ metrics: Record /** Total entity count in this group */ count: number /** Entity ID of materialized Measurement (if materialized) */ entityId?: string } /** * Provider interface for Cortex-accelerated aggregation. * When registered as 'aggregation' provider, Brainy delegates to this. */ export interface AggregationProvider { /** Register an aggregate definition (caches compiled definition for hot path) */ defineAggregate?(def: AggregateDefinition): void /** Remove a registered aggregate definition */ removeAggregate?(name: string): void /** Incrementally update aggregation state when an entity changes */ incrementalUpdate( name: string, def: AggregateDefinition, entity: Record, op: 'add' | 'update' | 'delete', prev?: Record ): AggregateGroupState[] /** Compute the group key for a given entity */ computeGroupKey( entity: Record, groupBy: GroupByDimension[] ): Record /** Rebuild an entire aggregate from scratch */ rebuildAggregate( def: AggregateDefinition, entities: Array> ): Map /** Query aggregate state with filtering/sorting/pagination */ queryAggregate( state: Map, params: AggregateQueryParams ): AggregateResult[] /** Restore previously serialized state (called during init) */ restoreState?(data: string): void /** Serialize internal state for persistence (called during flush) */ serializeState?(): string } // ============= Configuration ============= /** * Integration Hub configuration * * Enables external tool integrations: Excel, Power BI, Google Sheets, etc. * Works in all environments with zero external dependencies. * * @example * ```typescript * // Enable all integrations with defaults * new Brainy({ integrations: true }) * * // Custom configuration * new Brainy({ * integrations: { * basePath: '/api/v1', * enable: ['odata', 'sheets'] * } * }) * ``` */ export interface IntegrationsConfig { /** Base path for all integration endpoints (default: '') */ basePath?: string /** Which integrations to enable (default: all) */ enable?: ('odata' | 'sheets' | 'sse' | 'webhooks')[] | 'all' /** Per-integration config overrides */ config?: { odata?: { basePath?: string } sheets?: { basePath?: string } sse?: { basePath?: string; heartbeatInterval?: number } webhooks?: { maxRetries?: number } } } /** * Operator-facing summary returned by `brain.stats()`. Designed to fit in a * terminal screen so an incident responder can read it at a glance: counts, * mode, lock owner, indexed fields, and index health flags. */ export interface BrainyStats { /** Whether this instance can mutate. `reader` is set by `openReadOnly()` and `asOf()`. */ mode: 'writer' | 'reader' /** Total entity (noun) count across all types. */ entityCount: number /** Breakdown by NounType name (`person`, `event`, ...). Zero-count types omitted. */ entitiesByType: Record /** Total relationship (verb) count across all types. */ relationCount: number /** Breakdown by VerbType name. Zero-count types omitted. */ relationsByType: Record /** Indexed metadata field names known to the metadata index. */ fieldRegistry: string[] /** Per-index health flags. `true` = index has entries OR no entities exist yet. */ indexHealth: { /** @deprecated 8.0 β€” renamed to `vector`. Same boolean; kept as a compat alias until the final 8.0 cleanup. */ hnsw: boolean /** Vector index health (8.0 name β€” open-core JS HNSW path or a native acceleration provider). */ vector: boolean metadata: boolean graph: boolean } /** Storage backend info β€” `backend` is the adapter class name. */ storage: { backend: string rootDir?: string } /** * Writer lock metadata if one is currently held on this directory. Present * for both writer instances (their own lock) and readers inspecting a * directory with a live writer. */ writerLock?: { pid: number hostname: string startedAt: string lastHeartbeat: string version: string rootDir?: string } /** The Brainy library version this instance was built against. */ version: string } /** * Brainy configuration */ export interface BrainyConfig { // Storage configuration storage?: { type: 'auto' | 'memory' | 'filesystem' | 's3' | 'r2' | 'opfs' | 'gcs' /** Root directory for filesystem storage. Passed through to storage factories * including plugin-provided factories (e.g. Cortex mmap). */ rootDirectory?: string options?: any branch?: string // COW branch name (default: 'main') } // Index configuration index?: { m?: number // HNSW M parameter efConstruction?: number // HNSW construction parameter efSearch?: number // HNSW search parameter } // Performance options cache?: boolean | { // Enable caching maxSize?: number ttl?: number } // Distributed configuration distributed?: { enabled: boolean nodeId?: string nodes?: string[] // Other nodes in cluster coordinatorUrl?: string // Coordinator endpoint shardCount?: number // Number of shards (default: 64) replicationFactor?: number // Number of replicas (default: 3) consensus?: 'raft' | 'none' // Consensus mechanism transport?: 'tcp' | 'http' | 'udp' } // Advanced options warmup?: boolean // Warm up on init realtime?: boolean // Enable real-time updates multiTenancy?: boolean // Enable service isolation telemetry?: boolean // Send anonymous usage stats // Performance tuning options for production disableAutoRebuild?: boolean // Disable automatic index rebuilding on init disableMetrics?: boolean // Completely disable metrics collection disableAutoOptimize?: boolean // Disable automatic index optimization batchWrites?: boolean // Enable write batching for better performance maxConcurrentOperations?: number // Limit concurrent file operations // HNSW persistence mode // Controls when HNSW graph connections are persisted to storage // - 'immediate': Persist on every add (slow but durable, default for filesystem) // - 'deferred': Persist only on flush/close (fast, default for cloud storage) // Cloud storage (GCS/S3/R2/Azure) should use 'deferred' for 30-50Γ— faster adds hnswPersistMode?: 'immediate' | 'deferred' // HNSW optimization options (v7.11.0) // @deprecated 8.0 β€” use `vector` instead. This field is kept as a compat // shim during the 8.0 rename scaffolding; values are merged into the new // `vector` block with explicit `vector.*` values winning on conflict. hnsw?: { quantization?: { enabled?: boolean // default: false β€” current behavior exactly bits?: 8 | 4 // default: 8 (SQ8). SQ4 has a pure-JS implementation; cortex's distance:sq4 SIMD provider accelerates it. rerankMultiplier?: number // default: 3 β€” over-retrieve 3x, rerank with float32 } vectorStorage?: 'memory' | 'lazy' // default: 'memory' β€” 'lazy' evicts vectors after insert } /** * Vector index configuration (Brainy 8.0). * * Algorithm-neutral surface. The `recall` preset means the same thing * whether Brainy's open-core JS HNSW path is in play or a native * acceleration provider has taken over the `'vector'` provider key: * - `'fast'` β€” minimum-latency search, accepts lower recall * - `'balanced'` β€” Brainy 7.x defaults, the right pick for almost everyone * - `'accurate'` β€” maximum recall, accepts higher latency * * Power users may override individual knobs via `advanced.hnsw` (the JS * path) or `advanced.diskann` (a native DiskANN-style provider). The * preset is the floor; explicit overrides win. * * **Closed-form contract** locked in handoff thread * BRAINY-8.0-RENAME-COORDINATION Β§ A.2 (cortex-confirmed 2026-06-09). */ vector?: { /** Recall preset. Defaults to `'balanced'` when omitted. */ recall?: 'fast' | 'balanced' | 'accurate' /** * Vector quantization. Independent of `recall` β€” it trades RAM for a * small recall hit at any preset. `bits: 8` is SQ8 (4Γ— memory reduction, * ~0.4% recall loss). `bits: 4` is SQ4 (8Γ— memory reduction, ~1-3% recall * loss). Both ship in the open-core path; cortex's `distance:sq8` / * `distance:sq4` SIMD providers accelerate them when available. */ quantization?: { enabled?: boolean bits?: 8 | 4 rerankMultiplier?: number } /** Vector storage mode. `'memory'` keeps vectors resident; `'lazy'` evicts after insert. */ vectorStorage?: 'memory' | 'lazy' /** * Power-user overrides. The recall preset works for 99% of users β€” use * these only if you've measured. `hnsw` overrides apply on the JS HNSW * path; `diskann` overrides apply when a DiskANN-style native provider * is in play. Both blocks are honored on their respective paths and * silently ignored on the other (a one-shot warning fires when * `strictConfig !== false`). */ advanced?: { hnsw?: { M?: number efConstruction?: number efSearch?: number ml?: number } diskann?: { pqM?: number pqKsub?: number maxDegree?: number searchListSize?: number alpha?: number useMmapAdjacency?: boolean mmapAdjacencyPath?: string } } } // Memory management options maxQueryLimit?: number // Override auto-detected query result limit (max: 100000) reservedQueryMemory?: number // Memory reserved for queries in bytes (e.g., 1073741824 = 1GB) // Embedding initialization // Controls when the WASM embedding engine is initialized // - false (default): Lazy initialization on first embed() call // - true: Eager initialization during brain.init() // Set to true for cloud deployments (Cloud Run, Lambda) where you want // WASM compilation to happen during container startup, not on first request eagerEmbeddings?: boolean // Plugin configuration // Controls which plugins are loaded during init() // - undefined (default): Auto-detect installed plugins (@soulcraft/cortex, etc.) // - false: No plugins β€” skip auto-detection entirely // - []: No plugins β€” skip auto-detection entirely // - ['@soulcraft/cortex']: Load only specified plugins, no auto-detection plugins?: string[] | false // Logging configuration verbose?: boolean // Enable verbose logging silent?: boolean // Suppress all logging output // Integration Hub // Enable external tool integrations: Excel, Power BI, Google Sheets, etc. // - true: Enable all integrations with default paths // - false/undefined: Disable integrations (default) // - IntegrationsConfig: Custom configuration integrations?: boolean | IntegrationsConfig // Migration configuration // - false/undefined (default): Log warning if pending migrations exist, but don't auto-run // - true: Automatically run pending migrations during init() for small datasets (<10K entities) autoMigrate?: boolean /** * Brain-wide subtype enforcement mode. * * Opt-in in 7.30.0 (default: `false`); becomes the default in 8.0.0. * * - `false` / `undefined` (default): no brain-wide check. Per-type rules * registered via `brain.requireSubtype(type, options)` still apply. * - `true`: every `add()` / `addMany()` / `update()` / `relate()` / * `relateMany()` / `updateRelation()` rejects writes where the entity's * NounType (or relationship's VerbType) has no non-empty `subtype` value. * - `{ except: [NounType.Thing, NounType.Custom] }`: same as `true`, but * the listed types are allowed through without a subtype. Use for genuine * catch-all types where no subtype makes sense. * * Per-type registrations always compose with the brain-wide flag β€” a type * registered with `requireSubtype(type, { required: true })` is always * enforced regardless of this flag. */ requireSubtype?: boolean | { except: Array } /** * Validation strictness for provider-knob mismatches (Brainy 8.0). * * When a registered provider silently ignores a configuration knob the * user passed (e.g. `config.vector.advanced.diskann.*` on the open-core JS * HNSW path, or `config.vector.advanced.hnsw.*` on a native DiskANN-style * path), the user otherwise gets no feedback that their override has no * effect. This option controls the response: * * - `false` β€” no enforcement. Mismatched knobs are silently accepted. * - `'warn'` β€” (default in 8.0) one-shot warning per call site via * `prodLog.warn`, listing the ignored knobs and the docs link to the * appropriate `advanced.*` escape hatch. * - `true` β€” hard error at `init()`. Refuses to start until the config * is consistent with the resolved provider impl. * * The warning / error format matches the 7.30.1 teaching-error pattern: * problem β†’ escape valves β†’ caller location β†’ docs link. * * **Contract** locked in handoff thread BRAINY-8.0-RENAME-COORDINATION * Β§ B.6 (cortex-confirmed 2026-06-09). */ strictConfig?: boolean | 'warn' /** * Process role for multi-process safety on filesystem storage. * * - `'writer'` (default): acquires an exclusive lock on the storage directory at * `init()` and refuses to open if another live writer holds the lock. Required * for any instance that calls `add`/`update`/`delete`/`relate` or any other * mutation. Released on `close()` and on process exit/SIGINT/SIGTERM. * - `'reader'`: opens without acquiring the writer lock. Coexists with a live * writer and with other readers. All mutation methods throw * `Cannot mutate a read-only Brainy instance`. Use `Brainy.openReadOnly()` * as a convenience factory. * * For cloud storage backends (s3/r2/gcs/azure) the lock is a best-effort * advisory marker β€” multi-process safety against concurrent writers on * cloud-backed stores is not yet enforced. See `docs/concepts/multi-process.md`. */ mode?: 'writer' | 'reader' /** * Bypass the writer-lock check at init even when another writer holds the lock. * Use only when you know the existing lock is stale and stale-detection * (PID liveness + heartbeat) cannot prove it. Logs a warning regardless. */ force?: boolean } // ============= Neural API Types ============= /** * Neural similarity parameters */ export interface NeuralSimilarityParams { between?: [any, any] // Compare two items items?: any[] // Compare multiple items explain?: boolean // Return detailed breakdown } /** * Neural clustering parameters */ export interface NeuralClusterParams { items?: string[] | Entity[] // Items to cluster (or all) algorithm?: 'hierarchical' | 'kmeans' | 'dbscan' | 'spectral' params?: { k?: number // Number of clusters (kmeans) threshold?: number // Distance threshold (hierarchical) epsilon?: number // DBSCAN epsilon minPoints?: number // DBSCAN min points } visualize?: boolean // Return visualization data } /** * Neural anomaly detection parameters */ export interface NeuralAnomalyParams { threshold?: number // Standard deviations (default: 2.5) type?: NounType // Check specific type method?: 'isolation' | 'lof' | 'statistical' | 'autoencoder' returnScores?: boolean // Return anomaly scores } // ============= Content Extraction Types ============= /** * Detected content type for smart text extraction * */ export type ContentType = 'plaintext' | 'richtext-json' | 'html' | 'markdown' /** * Content category for extracted segments * * Universal categories that work across documents, code, and UI: * - 'title': Names the subject β€” headings, identifiers, labels, JSON keys * - 'annotation': Human explanation β€” comments, docstrings, captions, alt text * - 'content': Body substance β€” paragraphs, list items, flowing text * - 'value': Data literals β€” strings, numbers, form values, error messages * - 'code': Unparsed code blocks (custom parsers decompose into above) * - 'structural': Boilerplate β€” keywords, operators, punctuation, formatting * * Built-in extractors produce: 'title', 'content', 'code'. * All 6 categories are available for custom parsers. */ export type ContentCategory = 'title' | 'annotation' | 'content' | 'value' | 'code' | 'structural' /** * A segment of extracted text with its content category * */ export interface ExtractedSegment { /** The extracted text content */ text: string /** What role this text plays: 'title' | 'annotation' | 'content' | 'value' | 'code' | 'structural' */ contentCategory: ContentCategory } // ============= Semantic Highlighting Types ============= /** * Parameters for hybrid highlighting * * Zero-config highlighting that returns both text (exact) and semantic (concept) matches. * Perfect for UI highlighting at different levels. * * Added contentType hint and contentExtractor callback for structured text * (rich-text JSON, HTML, Markdown). Auto-detects format when not specified. * * @example * ```typescript * // Plain text * const highlights = await brain.highlight({ * query: "david the warrior", * text: "David Smith is a brave fighter who battles dragons" * }) * * // Rich-text JSON (auto-detected) * const highlights = await brain.highlight({ * query: "david the warrior", * text: JSON.stringify(tiptapDocument) * }) * * // Custom extractor (for proprietary formats) * const highlights = await brain.highlight({ * query: "function", * text: sourceCode, * contentExtractor: (text) => treeSitterParse(text) * }) * ``` */ export interface HighlightParams { /** The search query to match against */ query: string /** The text to highlight (e.g., entity.data) */ text: string /** Granularity of highlighting: 'word' (default), 'phrase', or 'sentence' */ granularity?: 'word' | 'phrase' | 'sentence' /** Minimum semantic similarity score for semantic matches (default: 0.5) */ threshold?: number /** * Optional content type hint to skip auto-detection. * When omitted, the content type is detected from the text content. */ contentType?: ContentType /** * Optional custom content extractor function. * When provided, bypasses built-in detection and extraction entirely. * Use this to plug in custom parsers (tree-sitter, Monaco, proprietary formats). */ contentExtractor?: (text: string) => ExtractedSegment[] } /** * A highlight showing which text matched the query * * matchType tells the UI how to style the highlight: * - 'text': Exact word match (strongest signal, highest confidence) * - 'semantic': Conceptually similar match (may need softer highlight) */ export interface Highlight { /** The text that matched */ text: string /** Match score (0-1). For text matches, always 1.0. For semantic, varies by similarity. */ score: number /** Position in original text [start, end] */ position: [number, number] /** Match type: 'text' (exact word match) or 'semantic' (concept match) */ matchType: 'text' | 'semantic' /** * Content category of the source segment: 'title' | 'annotation' | 'content' | 'value' | 'code' | 'structural'. * Present when the input text was structured (JSON, HTML, Markdown). */ contentCategory?: ContentCategory } // ============= Export all types ============= export * from './graphTypes.js' // Re-export NounType, VerbType, etc.