fix: set verb.source/target to entity UUID instead of NounType
relate() was setting verb.source = fromEntity.type (a NounType like "concept") instead of the entity UUID. Cortex's graph index indexes by verb.source, so lookups by UUID found nothing — causing in-session reads to return 0 results. Also fixes: - PathResolver calling private getIdsFromChunks() → public getIds() - Plugin auto-detection removed; cortex loads only via explicit config - GraphVerb types accept number timestamps and sourceId/targetId aliases - Dead autoDetect() method removed from PluginRegistry - In-session regression tests added for getRelations after relate()
This commit is contained in:
parent
0ec3d85c39
commit
932fb9520b
6 changed files with 31 additions and 48 deletions
|
|
@ -1488,14 +1488,14 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
vector: relationVector,
|
vector: relationVector,
|
||||||
sourceId: params.from,
|
sourceId: params.from,
|
||||||
targetId: params.to,
|
targetId: params.to,
|
||||||
source: fromEntity.type,
|
source: params.from,
|
||||||
target: toEntity.type,
|
target: params.to,
|
||||||
verb: params.type,
|
verb: params.type,
|
||||||
type: params.type,
|
type: params.type,
|
||||||
weight: params.weight ?? 1.0,
|
weight: params.weight ?? 1.0,
|
||||||
metadata: params.metadata as any,
|
metadata: params.metadata,
|
||||||
createdAt: Date.now()
|
createdAt: Date.now()
|
||||||
} as any
|
}
|
||||||
|
|
||||||
// Execute atomically with transaction system
|
// Execute atomically with transaction system
|
||||||
await this.transactionManager.executeTransaction(async (tx) => {
|
await this.transactionManager.executeTransaction(async (tx) => {
|
||||||
|
|
@ -6694,15 +6694,14 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
*/
|
*/
|
||||||
private async loadPlugins(): Promise<void> {
|
private async loadPlugins(): Promise<void> {
|
||||||
// plugins config:
|
// plugins config:
|
||||||
// undefined (default) → auto-detect installed plugins
|
// undefined (default) → no auto-detection (safe default)
|
||||||
// false → no plugins, skip auto-detection
|
// false → no auto-detection
|
||||||
// [] → no plugins, skip auto-detection
|
// [] → no auto-detection
|
||||||
// ['@soulcraft/cortex'] → load only these, no auto-detection
|
// ['@soulcraft/cortex'] → load only these explicitly listed packages
|
||||||
|
// Note: plugins registered via brain.use() are always activated regardless of config
|
||||||
const pluginConfig = this.config.plugins
|
const pluginConfig = this.config.plugins
|
||||||
if (pluginConfig === false) {
|
if (Array.isArray(pluginConfig) && pluginConfig.length > 0) {
|
||||||
// Explicitly disabled — no plugins
|
// Explicit list: import and register the specified packages
|
||||||
} else if (Array.isArray(pluginConfig)) {
|
|
||||||
// Explicit list: only register the specified packages, no auto-detection
|
|
||||||
for (const pkg of pluginConfig) {
|
for (const pkg of pluginConfig) {
|
||||||
try {
|
try {
|
||||||
const mod = await import(pkg)
|
const mod = await import(pkg)
|
||||||
|
|
@ -6714,9 +6713,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
// Package not found — skip
|
// Package not found — skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Default: auto-detect known plugins
|
|
||||||
await this.pluginRegistry.autoDetect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create plugin context
|
// Create plugin context
|
||||||
|
|
|
||||||
|
|
@ -291,15 +291,15 @@ export interface GraphVerb {
|
||||||
service?: string // Multi-tenancy support - which service created this verb
|
service?: string // Multi-tenancy support - which service created this verb
|
||||||
|
|
||||||
// Additional properties used in the codebase
|
// Additional properties used in the codebase
|
||||||
source?: string // Alias for sourceId
|
source?: string // Entity UUID (same as sourceId, for graphTypes compatibility)
|
||||||
target?: string // Alias for targetId
|
target?: string // Entity UUID (same as targetId, for graphTypes compatibility)
|
||||||
verb?: string // Alias for type
|
verb?: string // Alias for type
|
||||||
data?: Record<string, any> // Additional flexible data storage
|
data?: Record<string, any> // Additional flexible data storage
|
||||||
embedding?: Vector // Alias for vector
|
embedding?: Vector // Alias for vector
|
||||||
|
|
||||||
// Timestamp and creator properties
|
// Timestamp and creator properties
|
||||||
createdAt?: { seconds: number; nanoseconds: number } // When the verb was created
|
createdAt?: number | { seconds: number; nanoseconds: number } // When the verb was created
|
||||||
updatedAt?: { seconds: number; nanoseconds: number } // When the verb was last updated
|
updatedAt?: number | { seconds: number; nanoseconds: number } // When the verb was last updated
|
||||||
createdBy?: { augmentation: string; version: string } // Information about what created this verb
|
createdBy?: { augmentation: string; version: string } // Information about what created this verb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,29 +84,6 @@ export class PluginRegistry {
|
||||||
this.plugins.set(plugin.name, plugin)
|
this.plugins.set(plugin.name, plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-detect known plugins by attempting dynamic import.
|
|
||||||
* Additional package names can be passed for third-party plugins.
|
|
||||||
*/
|
|
||||||
async autoDetect(additionalPackages: string[] = []): Promise<void> {
|
|
||||||
const packages = [
|
|
||||||
'@soulcraft/cortex',
|
|
||||||
'@soulcraft/brainy-cortex', // deprecated — backward compat
|
|
||||||
...additionalPackages
|
|
||||||
]
|
|
||||||
|
|
||||||
for (const pkg of packages) {
|
|
||||||
try {
|
|
||||||
const mod = await import(pkg)
|
|
||||||
const plugin: BrainyPlugin = mod.default || mod
|
|
||||||
if (plugin && typeof plugin.activate === 'function' && plugin.name) {
|
|
||||||
this.plugins.set(plugin.name, plugin)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Package not installed — skip silently
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate all registered plugins.
|
* Activate all registered plugins.
|
||||||
|
|
|
||||||
|
|
@ -369,12 +369,14 @@ export interface GraphNoun {
|
||||||
*/
|
*/
|
||||||
export interface GraphVerb {
|
export interface GraphVerb {
|
||||||
id: string // Unique identifier for the verb
|
id: string // Unique identifier for the verb
|
||||||
source: string // ID of the source noun
|
source: string // Entity UUID of the source noun
|
||||||
target: string // ID of the target noun
|
target: string // Entity UUID of the target noun
|
||||||
|
sourceId?: string // Alias for source (coreTypes compatibility)
|
||||||
|
targetId?: string // Alias for target (coreTypes compatibility)
|
||||||
label?: string // Optional descriptive label
|
label?: string // Optional descriptive label
|
||||||
verb: VerbType // Type of relationship
|
verb: VerbType // Type of relationship
|
||||||
createdAt: Timestamp // When the verb was created
|
createdAt: Timestamp | number // When the verb was created
|
||||||
updatedAt: Timestamp // When the verb was last updated
|
updatedAt: Timestamp | number // When the verb was last updated
|
||||||
createdBy: CreatorMetadata // Information about what created this verb
|
createdBy: CreatorMetadata // Information about what created this verb
|
||||||
service?: string // Multi-tenancy support - which service created this verb
|
service?: string // Multi-tenancy support - which service created this verb
|
||||||
data?: Record<string, any> // Additional flexible data storage
|
data?: Record<string, any> // Additional flexible data storage
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ export class PathResolver {
|
||||||
try {
|
try {
|
||||||
// Direct O(log n) query to roaring bitmap index
|
// Direct O(log n) query to roaring bitmap index
|
||||||
// This queries the 'path' field in VFS entity metadata
|
// This queries the 'path' field in VFS entity metadata
|
||||||
const ids = await metadataIndex.getIdsFromChunks('path', path)
|
const ids = await metadataIndex.getIds('path', path)
|
||||||
|
|
||||||
if (ids.length === 0) {
|
if (ids.length === 0) {
|
||||||
this.metadataIndexMisses++
|
this.metadataIndexMisses++
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,17 @@ describe('VFS restart persistence', () => {
|
||||||
entityId = await brain.vfs.resolvePathToId('/chapter-1.txt')
|
entityId = await brain.vfs.resolvePathToId('/chapter-1.txt')
|
||||||
expect(entityId).toBeTruthy()
|
expect(entityId).toBeTruthy()
|
||||||
|
|
||||||
// Verify within same session
|
// Verify within same session — entity, readdir, and relations
|
||||||
const entity1 = await brain.get(entityId!)
|
const entity1 = await brain.get(entityId!)
|
||||||
expect(entity1).not.toBeNull()
|
expect(entity1).not.toBeNull()
|
||||||
|
|
||||||
const entries1 = await brain.vfs.readdir('/')
|
const entries1 = await brain.vfs.readdir('/')
|
||||||
expect(entries1.length).toBeGreaterThan(0)
|
expect(entries1.length).toBeGreaterThan(0)
|
||||||
|
|
||||||
|
// In-session getRelations: root should have Contains relationship to the file
|
||||||
|
const relations1 = await brain.getRelations({ from: rootId, type: VerbType.Contains })
|
||||||
|
expect(relations1.length).toBeGreaterThan(0)
|
||||||
|
|
||||||
await brain.close()
|
await brain.close()
|
||||||
|
|
||||||
// === SESSION 2: Read data after restart ===
|
// === SESSION 2: Read data after restart ===
|
||||||
|
|
@ -100,6 +104,10 @@ describe('VFS restart persistence', () => {
|
||||||
const docEntries1 = await brain.vfs.readdir('/docs')
|
const docEntries1 = await brain.vfs.readdir('/docs')
|
||||||
expect(docEntries1.length).toBe(2) // guide.txt + api.txt
|
expect(docEntries1.length).toBe(2) // guide.txt + api.txt
|
||||||
|
|
||||||
|
// In-session getRelations: root should have Contains relationships
|
||||||
|
const rootRelations1 = await brain.getRelations({ from: rootId, type: VerbType.Contains })
|
||||||
|
expect(rootRelations1.length).toBeGreaterThan(0)
|
||||||
|
|
||||||
await brain.close()
|
await brain.close()
|
||||||
|
|
||||||
// === SESSION 2: Verify all data persisted ===
|
// === SESSION 2: Verify all data persisted ===
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue