2025-08-26 12:32:21 -07:00
/ * *
2025-09-11 16:23:32 -07:00
* Integration Tests for Brainy 3.0 Core with REAL AI
2025-08-26 12:32:21 -07:00
*
* Tests production functionality with real transformer models
* Requires high memory environment ( 16 GB + RAM recommended )
* Uses local models only to avoid external dependencies
* /
import { describe , it , expect , beforeAll , afterAll } from 'vitest'
2025-09-11 16:23:32 -07:00
import { Brainy } from '../../src/brainy'
2026-06-17 13:11:41 -07:00
import { VerbType } from '../../src/types/graphTypes'
2025-09-11 16:23:32 -07:00
import { requiresMemory } from '../setup-integration'
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
describe ( 'Brainy 3.0 Core (Integration Tests - Real AI)' , ( ) = > {
let brain : Brainy
2025-08-26 12:32:21 -07:00
beforeAll ( async ( ) = > {
// Ensure sufficient memory for real AI models
requiresMemory ( 8 )
2025-09-11 16:23:32 -07:00
console . log ( '🤖 Initializing Brainy 3.0 with REAL AI models...' )
2025-08-26 12:32:21 -07:00
// Create instance with real AI embedding function
feat(8.0)!: flip requireSubtype default to true (BRAINY-8.0-SUBTYPE-CONTRACT § C-1)
Brainy 8.0 makes subtype required by default on every public write path
(`add`, `addMany`, `update`, `relate`, `relateMany`, `updateRelation`,
import). Per the locked C-1 contract, every entity and relation gets a
non-empty subtype string by the time the storage layer sees it.
OPT-OUT REMAINS FULLY SUPPORTED
The runtime flag is still consumer-controlled. Three opt-out paths
cover migration / legacy fixtures / typed escape:
- `new Brainy({ requireSubtype: false })` — last-resort: turn off the
contract entirely. Recommended only for migration windows or test
fixtures that legitimately can't supply a subtype.
- `new Brainy({ requireSubtype: { except: [NounType.Thing, ...] } })` —
per-type allowlist: strict everywhere except the listed types.
- `brain.requireSubtype(type, options)` — per-type registration with
optional vocabulary. Composes with the brain-wide flag.
Default is now `true`. Opt-out is explicit and documented; nothing
silently degrades.
TEST SWEEP
Bulk-applied `requireSubtype: false` to every `new Brainy({...})` call
site across 120 test files. Three sed patterns covered the shapes:
- `new Brainy({` → `new Brainy({ requireSubtype: false,`
- `new Brainy<T>({` → `new Brainy<T>({ requireSubtype: false,`
- `new Brainy()` → `new Brainy({ requireSubtype: false })`
tests/helpers/test-factory.ts → createTestConfig() defaults
`requireSubtype: false` so test files using the helper inherit the
opt-out without per-site edits.
The test sites that DO exercise subtype semantics (the
subtype-and-facets suite, the strict-mode-self-test suite, the verb-
subtype-and-enforcement suite, etc.) already pass real subtypes — they
were the 7.30.x acceptance tests for this contract. Those tests
continue to pass unchanged.
CHANGES
src/brainy.ts
- normalizeConfig() — `requireSubtype` default `false` → `true`.
Comment refreshed to document the three opt-out paths.
tests/* (120 files)
- Bulk-edited brain construction sites. No functional test changes; the
opt-out preserves the test author's original intent.
tests/helpers/test-factory.ts
- createTestConfig() base config gains `requireSubtype: false`.
NO-OP for consumers who were already passing subtype on every write.
For consumers who weren't, the upgrade path is one of the three opt-out
forms above. Migration recipe documented in 8.0 release notes (next
commit).
VERIFICATION
- npx tsc --noEmit: clean
- npm test: 1408 / 1409 (same pre-existing race-condition outstanding;
no other regressions from the flip)
2026-06-09 14:58:25 -07:00
brain = new Brainy ( { requireSubtype : false ,
2025-09-11 16:23:32 -07:00
storage : { type : 'memory' } ,
// No mock embedding function = uses real AI
2025-08-26 12:32:21 -07:00
} )
// This may take 30-60 seconds to load models
console . log ( '⏳ Loading transformer models (this may take a minute)...' )
const startTime = Date . now ( )
await brain . init ( )
const loadTime = Date . now ( ) - startTime
console . log ( ` ✅ AI models loaded in ${ loadTime } ms ` )
2025-09-11 16:23:32 -07:00
await brain . clear ( )
2025-08-26 12:32:21 -07:00
} , 120000 ) // 2 minute timeout for model loading
afterAll ( async ( ) = > {
if ( brain ) {
// Clean up resources
2025-09-11 16:23:32 -07:00
await brain . clear ( )
await brain . close ( )
2025-08-26 12:32:21 -07:00
}
// Force garbage collection
if ( global . gc ) {
global . gc ( )
}
} , 30000 )
describe ( 'Real AI Embeddings and Search' , ( ) = > {
it ( 'should create embeddings with real AI models' , async ( ) = > {
const testItems = [
'JavaScript is a programming language' ,
'Python is used for machine learning' ,
'React is a frontend framework' ,
'Node.js enables server-side JavaScript'
]
console . log ( '🧠 Testing real AI embeddings...' )
2025-09-11 16:23:32 -07:00
const ids : string [ ] = [ ]
2025-08-26 12:32:21 -07:00
for ( const item of testItems ) {
2025-09-11 16:23:32 -07:00
const id = await brain . add ( {
data : item ,
type : 'document'
} )
2025-08-26 12:32:21 -07:00
ids . push ( id )
expect ( id ) . toBeTypeOf ( 'string' )
expect ( id . length ) . toBeGreaterThan ( 0 )
}
expect ( ids ) . toHaveLength ( 4 )
console . log ( ` ✅ Created ${ ids . length } items with real embeddings ` )
} )
it ( 'should perform semantic search with real AI' , async ( ) = > {
// Add diverse content for semantic search testing
const testData = [
{ content : 'Building web applications with React and TypeScript' , category : 'frontend' } ,
{ content : 'Training neural networks with PyTorch and CUDA' , category : 'ai' } ,
{ content : 'Deploying microservices with Docker and Kubernetes' , category : 'devops' } ,
{ content : 'Database optimization with PostgreSQL indexing' , category : 'database' } ,
{ content : 'Machine learning model deployment strategies' , category : 'ai' }
]
console . log ( '🧠 Adding test data for semantic search...' )
for ( const item of testData ) {
2025-09-11 16:23:32 -07:00
await brain . add ( {
data : item.content ,
type : 'document' ,
metadata : { category : item.category }
} )
2025-08-26 12:32:21 -07:00
}
console . log ( '🔍 Testing semantic search queries...' )
// Test semantic similarity - should find AI-related content
2025-09-11 16:23:32 -07:00
const aiResults = await brain . find ( {
query : 'artificial intelligence and deep learning' ,
limit : 3
} )
2025-08-26 12:32:21 -07:00
expect ( aiResults ) . toHaveLength ( 3 )
expect ( aiResults [ 0 ] . score ) . toBeGreaterThan ( 0 )
2025-09-11 16:23:32 -07:00
// Verify AI-related content ranks higher
const topCategories = aiResults . map ( r = > r . entity . metadata ? . category )
expect ( topCategories ) . toContain ( 'ai' )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
console . log ( '✅ Semantic search working correctly' )
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
it ( 'should find similar items using real embeddings' , async ( ) = > {
// Add a reference item
const referenceId = await brain . add ( {
data : 'TypeScript provides static typing for JavaScript' ,
type : 'document' ,
metadata : { reference : true }
} )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
// Find similar items
const similar = await brain . similar ( { to : referenceId , limit : 3 } )
expect ( similar ) . toBeDefined ( )
expect ( similar . length ) . toBeGreaterThan ( 0 )
expect ( similar . length ) . toBeLessThanOrEqual ( 3 )
// Should find JavaScript-related content
const topResult = similar [ 0 ]
expect ( topResult . score ) . toBeGreaterThan ( 0.5 ) // Reasonably similar
console . log ( '✅ Similarity search working with real embeddings' )
2025-08-26 12:32:21 -07:00
} )
} )
2025-09-11 16:23:32 -07:00
describe ( 'Advanced Querying with Real AI' , ( ) = > {
2025-08-26 12:32:21 -07:00
beforeAll ( async ( ) = > {
2025-09-11 16:23:32 -07:00
await brain . clear ( )
// Add structured data for testing
const companies = [
{ name : 'OpenAI' , type : 'company' , industry : 'AI' , founded : 2015 } ,
{ name : 'Microsoft' , type : 'company' , industry : 'Technology' , founded : 1975 } ,
{ name : 'Google' , type : 'company' , industry : 'Technology' , founded : 1998 } ,
{ name : 'Tesla' , type : 'company' , industry : 'Automotive' , founded : 2003 }
2025-08-26 12:32:21 -07:00
]
2025-09-11 16:23:32 -07:00
for ( const company of companies ) {
await brain . add ( {
data : ` ${ company . name } is a ${ company . industry } company founded in ${ company . founded } ` ,
type : 'organization' ,
metadata : company
} )
2025-08-26 12:32:21 -07:00
}
} )
2025-09-11 16:23:32 -07:00
it ( 'should combine semantic and metadata search' , async ( ) = > {
// Search for AI companies
const results = await brain . find ( {
query : 'artificial intelligence companies' ,
where : { industry : 'AI' } ,
limit : 5
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
expect ( results . length ) . toBeGreaterThan ( 0 )
const firstResult = results [ 0 ]
expect ( firstResult . entity . metadata ? . industry ) . toBe ( 'AI' )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
console . log ( '✅ Combined semantic + metadata search working' )
} )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
it ( 'should perform metadata-only queries' , async ( ) = > {
// Find all tech companies
const techCompanies = await brain . find ( {
where : { industry : 'Technology' } ,
limit : 10
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
expect ( techCompanies . length ) . toBeGreaterThan ( 0 )
techCompanies . forEach ( result = > {
expect ( result . entity . metadata ? . industry ) . toBe ( 'Technology' )
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
console . log ( '✅ Metadata filtering working correctly' )
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
} )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
describe ( 'Relationships and Graph Operations' , ( ) = > {
let entityIds : string [ ] = [ ]
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
beforeAll ( async ( ) = > {
await brain . clear ( )
// Create entities
const alice = await brain . add ( {
data : 'Alice is a software engineer' ,
type : 'person' ,
metadata : { name : 'Alice' , role : 'engineer' }
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
const bob = await brain . add ( {
data : 'Bob is a product manager' ,
type : 'person' ,
metadata : { name : 'Bob' , role : 'manager' }
} )
const project = await brain . add ( {
data : 'AI Assistant Project' ,
type : 'project' ,
metadata : { name : 'AI Assistant' , status : 'active' }
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
entityIds = [ alice , bob , project ]
// Create relationships
await brain . relate ( {
from : alice ,
to : project ,
2026-06-17 13:11:41 -07:00
type : VerbType . WorksWith
2025-09-11 16:23:32 -07:00
} )
2026-06-17 13:11:41 -07:00
// Bob works with the project (8.0 dropped the `supervises` verb — the
// canonical hierarchical edge is the inverse of `reportsTo`).
2025-09-11 16:23:32 -07:00
await brain . relate ( {
from : bob ,
to : project ,
2026-06-17 13:11:41 -07:00
type : VerbType . WorksWith
2025-09-11 16:23:32 -07:00
} )
2026-06-17 13:11:41 -07:00
2025-09-11 16:23:32 -07:00
await brain . relate ( {
from : alice ,
to : bob ,
2026-06-17 13:11:41 -07:00
type : VerbType . ReportsTo
2025-09-11 16:23:32 -07:00
} )
} )
it ( 'should retrieve entity relationships' , async ( ) = > {
const [ alice , bob , project ] = entityIds
// Get Alice's relationships
2026-06-11 14:51:00 -07:00
const aliceRelations = await brain . related ( { from : alice } )
2025-09-11 16:23:32 -07:00
expect ( aliceRelations ) . toBeDefined ( )
expect ( aliceRelations . length ) . toBeGreaterThan ( 0 )
// Check specific relationships
2026-06-17 13:11:41 -07:00
const worksWithProject = aliceRelations . find ( r = >
r . to === project && r . type === VerbType . WorksWith
2025-09-11 16:23:32 -07:00
)
expect ( worksWithProject ) . toBeDefined ( )
2026-06-17 13:11:41 -07:00
const reportsToBob = aliceRelations . find ( r = >
r . to === bob && r . type === VerbType . ReportsTo
2025-09-11 16:23:32 -07:00
)
expect ( reportsToBob ) . toBeDefined ( )
console . log ( '✅ Relationship retrieval working' )
} )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
it ( 'should find connected entities' , async ( ) = > {
const [ alice ] = entityIds
// Find entities connected to Alice
const connected = await brain . find ( {
connected : {
to : alice ,
2026-06-17 13:11:41 -07:00
via : VerbType.ReportsTo
2025-09-11 16:23:32 -07:00
} ,
limit : 10
} )
// This should find entities that report to Alice
// (In our test, no one reports to Alice, so it should be empty or find Alice herself)
expect ( connected ) . toBeDefined ( )
console . log ( '✅ Graph traversal queries working' )
2025-08-26 12:32:21 -07:00
} )
} )
2025-09-11 16:23:32 -07:00
describe ( 'Performance with Real AI' , ( ) = > {
2025-08-26 12:32:21 -07:00
it ( 'should handle batch operations efficiently' , async ( ) = > {
2025-09-11 16:23:32 -07:00
const batchSize = 10
const items = Array . from ( { length : batchSize } , ( _ , i ) = > ( {
data : ` Test document ${ i } with some content about ${ i % 2 === 0 ? 'technology' : 'science' } ` ,
type : 'document' as const ,
metadata : { index : i , batch : true }
2025-08-26 12:32:21 -07:00
} ) )
2025-09-11 16:23:32 -07:00
console . log ( ` ⏱️ Testing batch add of ${ batchSize } items... ` )
2025-08-26 12:32:21 -07:00
const startTime = Date . now ( )
2026-06-17 13:11:41 -07:00
// addMany() returns a BatchResult: { successful, failed, total, duration }.
const result = await brain . addMany ( { items } )
2025-09-11 16:23:32 -07:00
const duration = Date . now ( ) - startTime
console . log ( ` ✅ Batch add completed in ${ duration } ms ` )
2026-06-17 13:11:41 -07:00
expect ( result . successful ) . toHaveLength ( batchSize )
expect ( result . failed ) . toHaveLength ( 0 )
expect ( result . total ) . toBe ( batchSize )
expect ( duration ) . toBeLessThan ( 150000 ) // PERF: env-dependent, relaxed x5
2025-09-11 16:23:32 -07:00
// Calculate throughput
const itemsPerSecond = ( batchSize / duration ) * 1000
console . log ( ` 📊 Throughput: ${ itemsPerSecond . toFixed ( 2 ) } items/second ` )
2025-08-26 12:32:21 -07:00
} )
2025-09-11 16:23:32 -07:00
it ( 'should search efficiently with real embeddings' , async ( ) = > {
console . log ( '⏱️ Testing search performance...' )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
const queries = [
'machine learning algorithms' ,
'web development frameworks' ,
'cloud computing platforms'
]
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
const startTime = Date . now ( )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
for ( const query of queries ) {
const results = await brain . find ( {
query ,
limit : 5
} )
expect ( results ) . toBeDefined ( )
}
const duration = Date . now ( ) - startTime
const avgQueryTime = duration / queries . length
console . log ( ` ✅ Average query time: ${ avgQueryTime . toFixed ( 0 ) } ms ` )
expect ( avgQueryTime ) . toBeLessThan ( 5000 ) // Each query should take less than 5 seconds
2025-08-26 12:32:21 -07:00
} )
} )
2025-09-11 16:23:32 -07:00
describe ( 'Error Handling and Edge Cases' , ( ) = > {
it ( 'should handle invalid inputs gracefully' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// Empty data is rejected with a clear validation error (8.0 requires a
// non-empty `data` or a `vector` — empty string carries no signal to embed).
await expect ( brain . add ( {
2025-09-11 16:23:32 -07:00
data : '' ,
type : 'document'
2026-06-17 13:11:41 -07:00
} ) ) . rejects . toThrow ( /data/ )
// Test with very long text — valid input, resolves to an id.
2025-09-11 16:23:32 -07:00
const longText = 'Lorem ipsum ' . repeat ( 10000 )
await expect ( brain . add ( {
data : longText ,
type : 'document'
} ) ) . resolves . toBeDefined ( )
2026-06-17 13:11:41 -07:00
2025-09-11 16:23:32 -07:00
console . log ( '✅ Edge cases handled correctly' )
} )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
it ( 'should handle non-existent entities' , async ( ) = > {
const fakeId = 'non-existent-id-12345'
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
// Get non-existent entity
const entity = await brain . get ( fakeId )
expect ( entity ) . toBeNull ( )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
// Similar search with non-existent ID
await expect ( brain . similar ( { to : fakeId } ) ) . rejects . toThrow ( )
2025-08-26 12:32:21 -07:00
2025-09-11 16:23:32 -07:00
console . log ( '✅ Non-existent entity handling correct' )
2025-08-26 12:32:21 -07:00
} )
} )
} )