feat: add Universal Display Augmentation for AI-powered enhanced output
- Implements intelligent display fields with AI-generated titles and descriptions - Leverages existing IntelligentTypeMatcher for semantic type detection - Adds lazy computation with LRU caching for zero performance impact - Enhances CLI with clean, minimal formatting (no visual clutter) - Provides method-based API (getDisplay()) to avoid namespace conflicts - Maintains 100% backward compatibility with existing code - Enables by default with complete isolation architecture - Includes comprehensive tests and documentation The augmentation transforms search results and data display with smart, contextual information while maintaining Soulcraft's clean aesthetic.
This commit is contained in:
parent
5c44616336
commit
4b58b8af01
11 changed files with 3511 additions and 62 deletions
448
tests/display-augmentation.test.ts
Normal file
448
tests/display-augmentation.test.ts
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
/**
|
||||
* Universal Display Augmentation Tests
|
||||
*
|
||||
* Comprehensive test suite for the display augmentation system
|
||||
* including AI-powered field computation, caching, and CLI integration
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||||
import { BrainyData } from '../src/brainyData.js'
|
||||
import { UniversalDisplayAugmentation } from '../src/augmentations/universalDisplayAugmentation.js'
|
||||
import { DisplayCache } from '../src/augmentations/display/cache.js'
|
||||
import { IntelligentComputationEngine } from '../src/augmentations/display/intelligentComputation.js'
|
||||
|
||||
describe('Universal Display Augmentation', () => {
|
||||
let brainy: BrainyData
|
||||
let displayAugmentation: UniversalDisplayAugmentation
|
||||
|
||||
beforeEach(async () => {
|
||||
// Use in-memory storage for tests
|
||||
brainy = new BrainyData({
|
||||
storage: { forceMemoryStorage: true },
|
||||
verbose: false
|
||||
})
|
||||
|
||||
await brainy.init()
|
||||
|
||||
// Get display augmentation (should be enabled by default)
|
||||
const augmentations = (brainy as any).augmentations
|
||||
displayAugmentation = augmentations?.get('display')
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
if (brainy) {
|
||||
await brainy.clearAll({ force: true })
|
||||
}
|
||||
})
|
||||
|
||||
describe('Augmentation Setup', () => {
|
||||
it('should be enabled by default', () => {
|
||||
expect(displayAugmentation).toBeDefined()
|
||||
expect(displayAugmentation.name).toBe('display')
|
||||
expect(displayAugmentation.version).toBe('1.0.0')
|
||||
})
|
||||
|
||||
it('should have correct metadata access configuration', () => {
|
||||
expect(displayAugmentation.metadata).toEqual({
|
||||
reads: '*',
|
||||
writes: ['_display']
|
||||
})
|
||||
})
|
||||
|
||||
it('should declare computed fields', () => {
|
||||
expect(displayAugmentation.computedFields).toBeDefined()
|
||||
expect(displayAugmentation.computedFields.display).toBeDefined()
|
||||
expect(displayAugmentation.computedFields.display.title).toEqual({
|
||||
type: 'string',
|
||||
description: 'Primary display name (AI-computed)'
|
||||
})
|
||||
})
|
||||
|
||||
it('should have correct operation targeting', () => {
|
||||
expect(displayAugmentation.operations).toContain('get')
|
||||
expect(displayAugmentation.operations).toContain('search')
|
||||
expect(displayAugmentation.operations).toContain('findSimilar')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Display Field Computation', () => {
|
||||
it('should enhance noun results with display fields', async () => {
|
||||
// Add test data
|
||||
const id = await brainy.addNoun('John Doe', {
|
||||
type: 'Person',
|
||||
role: 'CEO',
|
||||
company: 'Acme Corp'
|
||||
})
|
||||
|
||||
// Get the enhanced result
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
// Should have display capabilities
|
||||
expect(result.getDisplay).toBeDefined()
|
||||
expect(typeof result.getDisplay).toBe('function')
|
||||
|
||||
// Test display fields
|
||||
const displayFields = await result.getDisplay()
|
||||
expect(displayFields).toBeDefined()
|
||||
expect(displayFields.title).toBeDefined()
|
||||
expect(displayFields.type).toBeDefined()
|
||||
expect(displayFields.icon).toBeDefined()
|
||||
expect(displayFields.description).toBeDefined()
|
||||
expect(displayFields.confidence).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should provide type-appropriate icons', async () => {
|
||||
const testCases = [
|
||||
{ data: 'Apple Inc', metadata: { type: 'Organization' }, expectedIcon: '🏢' },
|
||||
{ data: 'Jane Smith', metadata: { type: 'Person' }, expectedIcon: '👤' },
|
||||
{ data: 'San Francisco', metadata: { type: 'Location' }, expectedIcon: '📍' },
|
||||
{ data: 'Machine Learning', metadata: { type: 'Concept' }, expectedIcon: '💭' }
|
||||
]
|
||||
|
||||
for (const testCase of testCases) {
|
||||
const id = await brainy.addNoun(testCase.data, testCase.metadata)
|
||||
const result = await brainy.getNoun(id)
|
||||
const displayFields = await result.getDisplay()
|
||||
|
||||
expect(displayFields.icon).toBe(testCase.expectedIcon)
|
||||
expect(displayFields.type).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle missing or minimal metadata gracefully', async () => {
|
||||
// Add data with minimal metadata
|
||||
const id = await brainy.addNoun('Some random text')
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
const displayFields = await result.getDisplay()
|
||||
expect(displayFields.title).toBeDefined()
|
||||
expect(displayFields.type).toBeDefined()
|
||||
expect(displayFields.icon).toBeDefined()
|
||||
expect(displayFields.confidence).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should compute enhanced descriptions', async () => {
|
||||
const id = await brainy.addNoun('Tesla Model 3', {
|
||||
type: 'Product',
|
||||
category: 'Electric Vehicle',
|
||||
manufacturer: 'Tesla'
|
||||
})
|
||||
|
||||
const result = await brainy.getNoun(id)
|
||||
const displayFields = await result.getDisplay()
|
||||
|
||||
expect(displayFields.description).toBeDefined()
|
||||
expect(displayFields.description.length).toBeGreaterThan(displayFields.title.length)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Search Result Enhancement', () => {
|
||||
beforeEach(async () => {
|
||||
// Add test data for search
|
||||
await brainy.addNoun('John Doe', { type: 'Person', role: 'CEO' })
|
||||
await brainy.addNoun('Apple Inc', { type: 'Organization', industry: 'Technology' })
|
||||
await brainy.addNoun('MacBook Pro', { type: 'Product', brand: 'Apple' })
|
||||
})
|
||||
|
||||
it('should enhance search results', async () => {
|
||||
const results = await brainy.search('CEO', { limit: 5 })
|
||||
expect(results.length).toBeGreaterThan(0)
|
||||
|
||||
// Check that results are enhanced
|
||||
const firstResult = results[0]
|
||||
expect(firstResult.getDisplay).toBeDefined()
|
||||
|
||||
const displayFields = await firstResult.getDisplay()
|
||||
expect(displayFields.title).toBeDefined()
|
||||
expect(displayFields.icon).toBeDefined()
|
||||
})
|
||||
|
||||
it('should maintain search scores while adding display fields', async () => {
|
||||
const results = await brainy.search('Apple', { limit: 5 })
|
||||
expect(results.length).toBeGreaterThan(0)
|
||||
|
||||
const firstResult = results[0]
|
||||
expect(firstResult.score).toBeDefined()
|
||||
expect(firstResult.getDisplay).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Verb Display Enhancement', () => {
|
||||
it('should enhance verb relationships with display fields', async () => {
|
||||
// Add entities and relationship
|
||||
const johnId = await brainy.addNoun('John Doe', { type: 'Person' })
|
||||
const appleId = await brainy.addNoun('Apple Inc', { type: 'Organization' })
|
||||
const verbId = await brainy.addVerb(johnId, appleId, 'WorksFor')
|
||||
|
||||
// Get the enhanced verb
|
||||
const verb = await brainy.getVerb(verbId)
|
||||
expect(verb.getDisplay).toBeDefined()
|
||||
|
||||
const displayFields = await verb.getDisplay()
|
||||
expect(displayFields.relationship).toBeDefined()
|
||||
expect(displayFields.icon).toBeDefined()
|
||||
expect(displayFields.type).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Caching System', () => {
|
||||
it('should cache computed display fields', async () => {
|
||||
const id = await brainy.addNoun('Test Entity', { type: 'Concept' })
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
// First computation
|
||||
const displayFields1 = await result.getDisplay()
|
||||
|
||||
// Second computation should be cached
|
||||
const displayFields2 = await result.getDisplay()
|
||||
|
||||
// Should be identical (cached)
|
||||
expect(displayFields1).toEqual(displayFields2)
|
||||
|
||||
// Check cache statistics
|
||||
const stats = displayAugmentation.getStats()
|
||||
expect(stats.totalComputations).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should provide cache statistics', () => {
|
||||
const stats = displayAugmentation.getStats()
|
||||
expect(stats).toBeDefined()
|
||||
expect(stats.totalComputations).toBeDefined()
|
||||
expect(stats.cacheHitRatio).toBeDefined()
|
||||
expect(stats.averageComputationTime).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Helper Methods', () => {
|
||||
it('should provide getAvailableFields method', async () => {
|
||||
const id = await brainy.addNoun('Test Entity')
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
expect(result.getAvailableFields).toBeDefined()
|
||||
const fields = result.getAvailableFields('display')
|
||||
expect(Array.isArray(fields)).toBe(true)
|
||||
expect(fields).toContain('title')
|
||||
expect(fields).toContain('description')
|
||||
expect(fields).toContain('type')
|
||||
expect(fields).toContain('icon')
|
||||
})
|
||||
|
||||
it('should provide getAvailableAugmentations method', async () => {
|
||||
const id = await brainy.addNoun('Test Entity')
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
expect(result.getAvailableAugmentations).toBeDefined()
|
||||
const augs = result.getAvailableAugmentations()
|
||||
expect(Array.isArray(augs)).toBe(true)
|
||||
expect(augs).toContain('display')
|
||||
})
|
||||
|
||||
it('should provide explore method for debugging', async () => {
|
||||
const id = await brainy.addNoun('Test Entity', { type: 'Concept', description: 'Test' })
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
expect(result.explore).toBeDefined()
|
||||
|
||||
// Should not throw when called
|
||||
await expect(result.explore()).resolves.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Configuration', () => {
|
||||
it('should support runtime configuration', () => {
|
||||
const newConfig = {
|
||||
enabled: false,
|
||||
cacheSize: 500
|
||||
}
|
||||
|
||||
displayAugmentation.configure(newConfig)
|
||||
|
||||
// Configuration should be applied
|
||||
expect((displayAugmentation as any).config.enabled).toBe(false)
|
||||
expect((displayAugmentation as any).config.cacheSize).toBe(500)
|
||||
})
|
||||
|
||||
it('should clear cache when disabled', () => {
|
||||
displayAugmentation.configure({ enabled: false })
|
||||
|
||||
// Cache should be cleared
|
||||
const stats = displayAugmentation.getStats()
|
||||
expect(stats.totalComputations).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Error Handling', () => {
|
||||
it('should handle computation errors gracefully', async () => {
|
||||
// Add data that might cause computation issues
|
||||
const id = await brainy.addNoun('') // Empty string
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
// Should still provide display fields, even if basic
|
||||
const displayFields = await result.getDisplay()
|
||||
expect(displayFields).toBeDefined()
|
||||
expect(displayFields.title).toBeDefined()
|
||||
expect(displayFields.icon).toBeDefined()
|
||||
})
|
||||
|
||||
it('should work without AI components', async () => {
|
||||
// Test fallback to heuristic-based computation
|
||||
const id = await brainy.addNoun('Test Without AI', { type: 'Thing' })
|
||||
const result = await brainy.getNoun(id)
|
||||
|
||||
// Should still work with heuristic fallback
|
||||
const displayFields = await result.getDisplay()
|
||||
expect(displayFields).toBeDefined()
|
||||
expect(displayFields.title).toBeDefined()
|
||||
expect(displayFields.type).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Performance', () => {
|
||||
it('should have reasonable computation times', async () => {
|
||||
const startTime = Date.now()
|
||||
|
||||
const id = await brainy.addNoun('Performance Test Entity', {
|
||||
type: 'Concept',
|
||||
description: 'Testing performance characteristics'
|
||||
})
|
||||
|
||||
const result = await brainy.getNoun(id)
|
||||
await result.getDisplay()
|
||||
|
||||
const endTime = Date.now()
|
||||
const duration = endTime - startTime
|
||||
|
||||
// Should complete within reasonable time (adjust based on system capabilities)
|
||||
expect(duration).toBeLessThan(5000) // 5 seconds max
|
||||
})
|
||||
|
||||
it('should handle batch operations efficiently', async () => {
|
||||
const startTime = Date.now()
|
||||
const ids: string[] = []
|
||||
|
||||
// Add multiple entities
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const id = await brainy.addNoun(`Test Entity ${i}`, { type: 'Concept' })
|
||||
ids.push(id)
|
||||
}
|
||||
|
||||
// Get display fields for all
|
||||
const displayPromises = ids.map(async id => {
|
||||
const result = await brainy.getNoun(id)
|
||||
return result.getDisplay()
|
||||
})
|
||||
|
||||
await Promise.all(displayPromises)
|
||||
|
||||
const endTime = Date.now()
|
||||
const duration = endTime - startTime
|
||||
|
||||
// Batch should be reasonably fast
|
||||
expect(duration).toBeLessThan(10000) // 10 seconds max for 10 items
|
||||
})
|
||||
})
|
||||
|
||||
describe('Shutdown and Cleanup', () => {
|
||||
it('should shutdown gracefully', async () => {
|
||||
// Should not throw
|
||||
await expect(displayAugmentation.shutdown()).resolves.toBeUndefined()
|
||||
})
|
||||
|
||||
it('should clear cache on shutdown', async () => {
|
||||
displayAugmentation.clearCache()
|
||||
|
||||
const stats = displayAugmentation.getStats()
|
||||
expect(stats.totalComputations).toBe(0)
|
||||
expect(stats.cacheHitRatio).toBe(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Display Cache', () => {
|
||||
let cache: DisplayCache
|
||||
|
||||
beforeEach(() => {
|
||||
cache = new DisplayCache(100)
|
||||
})
|
||||
|
||||
it('should store and retrieve display fields', () => {
|
||||
const testFields = {
|
||||
title: 'Test Title',
|
||||
description: 'Test Description',
|
||||
type: 'Test Type',
|
||||
icon: '📝',
|
||||
tags: ['test'],
|
||||
confidence: 0.9,
|
||||
computedAt: Date.now(),
|
||||
version: '1.0.0'
|
||||
}
|
||||
|
||||
const key = cache.generateKey('test-id', { name: 'test' }, 'noun')
|
||||
cache.set(key, testFields)
|
||||
|
||||
const retrieved = cache.get(key)
|
||||
expect(retrieved).toEqual(testFields)
|
||||
})
|
||||
|
||||
it('should implement LRU eviction', () => {
|
||||
const smallCache = new DisplayCache(2)
|
||||
|
||||
const fields = {
|
||||
title: 'Test',
|
||||
description: 'Test',
|
||||
type: 'Test',
|
||||
icon: '📝',
|
||||
tags: [],
|
||||
confidence: 0.9,
|
||||
computedAt: Date.now(),
|
||||
version: '1.0.0'
|
||||
}
|
||||
|
||||
// Fill cache to capacity
|
||||
smallCache.set('key1', fields)
|
||||
smallCache.set('key2', fields)
|
||||
|
||||
// Add one more (should evict oldest)
|
||||
smallCache.set('key3', fields)
|
||||
|
||||
// key1 should be evicted
|
||||
expect(smallCache.get('key1')).toBeNull()
|
||||
expect(smallCache.get('key2')).toBeDefined()
|
||||
expect(smallCache.get('key3')).toBeDefined()
|
||||
})
|
||||
|
||||
it('should generate consistent cache keys', () => {
|
||||
const data = { name: 'test', type: 'Person' }
|
||||
|
||||
const key1 = cache.generateKey('id-123', data, 'noun')
|
||||
const key2 = cache.generateKey('id-123', data, 'noun')
|
||||
|
||||
expect(key1).toBe(key2)
|
||||
|
||||
// Different entity type should produce different key
|
||||
const key3 = cache.generateKey('id-123', data, 'verb')
|
||||
expect(key1).not.toBe(key3)
|
||||
})
|
||||
|
||||
it('should provide cache statistics', () => {
|
||||
const fields = {
|
||||
title: 'Test',
|
||||
description: 'Test',
|
||||
type: 'Test',
|
||||
icon: '📝',
|
||||
tags: [],
|
||||
confidence: 0.9,
|
||||
computedAt: Date.now(),
|
||||
version: '1.0.0'
|
||||
}
|
||||
|
||||
cache.set('test-key', fields, 100) // 100ms computation time
|
||||
cache.get('test-key') // Hit
|
||||
cache.get('nonexistent') // Miss
|
||||
|
||||
const stats = cache.getStats()
|
||||
expect(stats.totalComputations).toBe(1)
|
||||
expect(stats.cacheHitRatio).toBe(0.5) // 1 hit, 1 miss
|
||||
expect(stats.averageComputationTime).toBe(100)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue