Open source vector database with HNSW indexing, graph relationships, and metadata facets. Features CLI with professional augmentation registry integration for discovering extensions and capabilities.
307 lines
No EOL
10 KiB
JavaScript
307 lines
No EOL
10 KiB
JavaScript
/**
|
|
* Domain Detector
|
|
* Automatically detects and manages data domains for logical separation
|
|
*/
|
|
export class DomainDetector {
|
|
constructor() {
|
|
this.domainPatterns = [
|
|
{
|
|
domain: 'medical',
|
|
patterns: {
|
|
fields: ['symptoms', 'diagnosis', 'treatment', 'medication', 'patient'],
|
|
keywords: ['medical', 'health', 'disease', 'symptom', 'treatment', 'doctor', 'patient']
|
|
},
|
|
priority: 1
|
|
},
|
|
{
|
|
domain: 'legal',
|
|
patterns: {
|
|
fields: ['contract', 'clause', 'litigation', 'statute', 'jurisdiction'],
|
|
keywords: ['legal', 'law', 'contract', 'court', 'attorney', 'litigation', 'statute']
|
|
},
|
|
priority: 1
|
|
},
|
|
{
|
|
domain: 'product',
|
|
patterns: {
|
|
fields: ['price', 'sku', 'inventory', 'category', 'brand'],
|
|
keywords: ['product', 'price', 'sale', 'inventory', 'catalog', 'item', 'sku']
|
|
},
|
|
priority: 1
|
|
},
|
|
{
|
|
domain: 'customer',
|
|
patterns: {
|
|
fields: ['customerId', 'email', 'phone', 'address', 'orders'],
|
|
keywords: ['customer', 'client', 'user', 'account', 'profile', 'contact']
|
|
},
|
|
priority: 1
|
|
},
|
|
{
|
|
domain: 'financial',
|
|
patterns: {
|
|
fields: ['amount', 'currency', 'transaction', 'balance', 'account'],
|
|
keywords: ['financial', 'money', 'payment', 'transaction', 'bank', 'credit', 'debit']
|
|
},
|
|
priority: 1
|
|
},
|
|
{
|
|
domain: 'technical',
|
|
patterns: {
|
|
fields: ['code', 'function', 'error', 'stack', 'api'],
|
|
keywords: ['code', 'software', 'api', 'error', 'debug', 'function', 'class', 'method']
|
|
},
|
|
priority: 2
|
|
}
|
|
];
|
|
this.customPatterns = [];
|
|
this.domainStats = new Map();
|
|
}
|
|
/**
|
|
* Detect domain from data object
|
|
* @param data - The data object to analyze
|
|
* @returns The detected domain and metadata
|
|
*/
|
|
detectDomain(data) {
|
|
if (!data || typeof data !== 'object') {
|
|
return { domain: 'general' };
|
|
}
|
|
// Check for explicit domain field
|
|
if (data.domain && typeof data.domain === 'string') {
|
|
this.updateStats(data.domain);
|
|
return {
|
|
domain: data.domain,
|
|
domainMetadata: this.extractDomainMetadata(data, data.domain)
|
|
};
|
|
}
|
|
// Score each domain pattern
|
|
const scores = new Map();
|
|
// Check custom patterns first (higher priority)
|
|
for (const pattern of this.customPatterns) {
|
|
const score = this.scorePattern(data, pattern);
|
|
if (score > 0) {
|
|
scores.set(pattern.domain, score * (pattern.priority || 1));
|
|
}
|
|
}
|
|
// Check default patterns
|
|
for (const pattern of this.domainPatterns) {
|
|
const score = this.scorePattern(data, pattern);
|
|
if (score > 0) {
|
|
const currentScore = scores.get(pattern.domain) || 0;
|
|
scores.set(pattern.domain, currentScore + score * (pattern.priority || 1));
|
|
}
|
|
}
|
|
// Find highest scoring domain
|
|
let bestDomain = 'general';
|
|
let bestScore = 0;
|
|
for (const [domain, score] of scores.entries()) {
|
|
if (score > bestScore) {
|
|
bestDomain = domain;
|
|
bestScore = score;
|
|
}
|
|
}
|
|
this.updateStats(bestDomain);
|
|
return {
|
|
domain: bestDomain,
|
|
domainMetadata: this.extractDomainMetadata(data, bestDomain)
|
|
};
|
|
}
|
|
/**
|
|
* Score a data object against a domain pattern
|
|
*/
|
|
scorePattern(data, pattern) {
|
|
let score = 0;
|
|
// Check field matches
|
|
if (pattern.patterns.fields) {
|
|
const dataKeys = Object.keys(data);
|
|
for (const field of pattern.patterns.fields) {
|
|
if (dataKeys.some(key => key.toLowerCase().includes(field.toLowerCase()))) {
|
|
score += 2; // Field match is strong signal
|
|
}
|
|
}
|
|
}
|
|
// Check keyword matches in values
|
|
if (pattern.patterns.keywords) {
|
|
const dataStr = JSON.stringify(data).toLowerCase();
|
|
for (const keyword of pattern.patterns.keywords) {
|
|
if (dataStr.includes(keyword.toLowerCase())) {
|
|
score += 1;
|
|
}
|
|
}
|
|
}
|
|
// Check regex patterns
|
|
if (pattern.patterns.regex) {
|
|
const dataStr = JSON.stringify(data);
|
|
if (pattern.patterns.regex.test(dataStr)) {
|
|
score += 3; // Regex match is very specific
|
|
}
|
|
}
|
|
return score;
|
|
}
|
|
/**
|
|
* Extract domain-specific metadata
|
|
*/
|
|
extractDomainMetadata(data, domain) {
|
|
const metadata = {};
|
|
switch (domain) {
|
|
case 'medical':
|
|
if (data.patientId)
|
|
metadata.patientId = data.patientId;
|
|
if (data.condition)
|
|
metadata.condition = data.condition;
|
|
if (data.severity)
|
|
metadata.severity = data.severity;
|
|
break;
|
|
case 'legal':
|
|
if (data.caseId)
|
|
metadata.caseId = data.caseId;
|
|
if (data.jurisdiction)
|
|
metadata.jurisdiction = data.jurisdiction;
|
|
if (data.documentType)
|
|
metadata.documentType = data.documentType;
|
|
break;
|
|
case 'product':
|
|
if (data.sku)
|
|
metadata.sku = data.sku;
|
|
if (data.category)
|
|
metadata.category = data.category;
|
|
if (data.brand)
|
|
metadata.brand = data.brand;
|
|
if (data.price)
|
|
metadata.priceRange = this.getPriceRange(data.price);
|
|
break;
|
|
case 'customer':
|
|
if (data.customerId)
|
|
metadata.customerId = data.customerId;
|
|
if (data.segment)
|
|
metadata.segment = data.segment;
|
|
if (data.lifetime_value)
|
|
metadata.valueCategory = this.getValueCategory(data.lifetime_value);
|
|
break;
|
|
case 'financial':
|
|
if (data.accountId)
|
|
metadata.accountId = data.accountId;
|
|
if (data.transactionType)
|
|
metadata.transactionType = data.transactionType;
|
|
if (data.amount)
|
|
metadata.amountRange = this.getAmountRange(data.amount);
|
|
break;
|
|
case 'technical':
|
|
if (data.service)
|
|
metadata.service = data.service;
|
|
if (data.environment)
|
|
metadata.environment = data.environment;
|
|
if (data.severity)
|
|
metadata.severity = data.severity;
|
|
break;
|
|
}
|
|
// Add detection confidence
|
|
metadata.detectionConfidence = this.calculateConfidence(data, domain);
|
|
return metadata;
|
|
}
|
|
/**
|
|
* Calculate detection confidence
|
|
*/
|
|
calculateConfidence(data, domain) {
|
|
// If domain was explicitly specified
|
|
if (data.domain === domain)
|
|
return 'high';
|
|
// Check how many patterns matched
|
|
const pattern = [...this.customPatterns, ...this.domainPatterns]
|
|
.find(p => p.domain === domain);
|
|
if (!pattern)
|
|
return 'low';
|
|
const score = this.scorePattern(data, pattern);
|
|
if (score >= 5)
|
|
return 'high';
|
|
if (score >= 2)
|
|
return 'medium';
|
|
return 'low';
|
|
}
|
|
/**
|
|
* Categorize price ranges
|
|
*/
|
|
getPriceRange(price) {
|
|
if (price < 10)
|
|
return 'low';
|
|
if (price < 100)
|
|
return 'medium';
|
|
if (price < 1000)
|
|
return 'high';
|
|
return 'premium';
|
|
}
|
|
/**
|
|
* Categorize customer value
|
|
*/
|
|
getValueCategory(value) {
|
|
if (value < 100)
|
|
return 'low';
|
|
if (value < 1000)
|
|
return 'medium';
|
|
if (value < 10000)
|
|
return 'high';
|
|
return 'vip';
|
|
}
|
|
/**
|
|
* Categorize amount ranges
|
|
*/
|
|
getAmountRange(amount) {
|
|
if (amount < 100)
|
|
return 'micro';
|
|
if (amount < 1000)
|
|
return 'small';
|
|
if (amount < 10000)
|
|
return 'medium';
|
|
if (amount < 100000)
|
|
return 'large';
|
|
return 'enterprise';
|
|
}
|
|
/**
|
|
* Add custom domain pattern
|
|
* @param pattern - Custom domain pattern to add
|
|
*/
|
|
addCustomPattern(pattern) {
|
|
// Remove existing pattern for same domain if exists
|
|
this.customPatterns = this.customPatterns.filter(p => p.domain !== pattern.domain);
|
|
this.customPatterns.push(pattern);
|
|
}
|
|
/**
|
|
* Remove custom domain pattern
|
|
* @param domain - Domain to remove pattern for
|
|
*/
|
|
removeCustomPattern(domain) {
|
|
this.customPatterns = this.customPatterns.filter(p => p.domain !== domain);
|
|
}
|
|
/**
|
|
* Update domain statistics
|
|
*/
|
|
updateStats(domain) {
|
|
const count = this.domainStats.get(domain) || 0;
|
|
this.domainStats.set(domain, count + 1);
|
|
}
|
|
/**
|
|
* Get domain statistics
|
|
* @returns Map of domain to count
|
|
*/
|
|
getDomainStats() {
|
|
return new Map(this.domainStats);
|
|
}
|
|
/**
|
|
* Clear domain statistics
|
|
*/
|
|
clearStats() {
|
|
this.domainStats.clear();
|
|
}
|
|
/**
|
|
* Get all configured domains
|
|
* @returns Array of domain names
|
|
*/
|
|
getConfiguredDomains() {
|
|
const domains = new Set();
|
|
for (const pattern of [...this.domainPatterns, ...this.customPatterns]) {
|
|
domains.add(pattern.domain);
|
|
}
|
|
return Array.from(domains).sort();
|
|
}
|
|
}
|
|
//# sourceMappingURL=domainDetector.js.map
|