brainy/src/types/brainy.types.ts
David Snelling 89e4d810ed docs: correct misleading SQ4 quantization comment in type definitions
Two type-definition comments (src/coreTypes.ts:472 +
src/types/brainy.types.ts:1123) stated:

  bits?: 8 | 4   // default: 8 (SQ8). SQ4 requires cortex native.

This was factually wrong. src/utils/vectorQuantization.ts:412 ships
distanceSQ4Js, a pure-JS SQ4 implementation that's been part of the
open-core path the whole time. The native SIMD acceleration is a drop-in
via setSQ4DistanceImplementation, NOT a hard requirement.

The misleading comment risked pushing open-core users to assume they
needed a paid native provider for SQ4 quantization when they did not.

Corrected to:

  bits?: 8 | 4   // default: 8 (SQ8). SQ4 has a pure-JS implementation;
                 // cortex's distance:sq4 SIMD provider accelerates it.

Pure documentation; no behaviour change. Caught during an upstream
open-core-boundary audit (handoff thread BRAINY-8.0-RENAME-COORDINATION,
section E.1).

Verification

- npx tsc --noEmit: clean
- npm test: 1468 / 1468 unit
- npm run build: clean
2026-06-09 12:53:34 -07:00

1371 lines
No EOL
48 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 🧠 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<T = any> {
/** 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<T = any> {
/** 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<T = any> {
// 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<T>
// 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<string, string | number> // Group-by key values for this aggregate row
metrics?: Record<string, number> // 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<string, number>
penalties?: Record<string, number>
}
// ============= 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<T = any> {
/** 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<T = any> {
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<T> // 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<T = any> {
/** 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<T = any> {
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<T> // 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<T = any> {
// 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<T>
// 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<T = any> {
to: string | Entity<T> | Vector // Find similar to this
limit?: number // Max results (default: 10)
threshold?: number // Min similarity score
type?: NounType | NounType[] // Restrict to types
where?: Partial<T> // 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<T = any> {
items: AddParams<T>[] // 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<T = any> {
items: UpdateParams<T>[] // 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<T = any> {
items: RelateParams<T>[] // Relations to create
parallel?: boolean
chunkSize?: number
onProgress?: (done: number, total: number) => void
continueOnError?: boolean
}
/**
* Batch result
*/
export interface BatchResult<T = any> {
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<string, unknown>
/** 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<string, AggregateMetricDef>
/** 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<string, number>
}
/**
* 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<string, string | number>
/** Running metric states keyed by metric name */
metrics: Record<string, MetricState>
/** 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<string, unknown>
/**
* 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<string, unknown>
/** 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<string, string | number>
/** Computed metric values (derived from MetricState based on op) */
metrics: Record<string, number>
/** 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<string, unknown>,
op: 'add' | 'update' | 'delete',
prev?: Record<string, unknown>
): AggregateGroupState[]
/** Compute the group key for a given entity */
computeGroupKey(
entity: Record<string, unknown>,
groupBy: GroupByDimension[]
): Record<string, string | number>
/** Rebuild an entire aggregate from scratch */
rebuildAggregate(
def: AggregateDefinition,
entities: Array<Record<string, unknown>>
): Map<string, AggregateGroupState>
/** Query aggregate state with filtering/sorting/pagination */
queryAggregate(
state: Map<string, AggregateGroupState>,
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<string, number>
/** Total relationship (verb) count across all types. */
relationCount: number
/** Breakdown by VerbType name. Zero-count types omitted. */
relationsByType: Record<string, number>
/** 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: {
hnsw: 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)
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
}
// 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<import('../types/graphTypes.js').NounType | import('../types/graphTypes.js').VerbType> }
/**
* 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.