import { randomUUID } from 'crypto';
export class SequentialThinkingProcessor {
constructor(factStore, qualityScorer, factTypeManager) {
this.factStore = factStore;
this.qualityScorer = qualityScorer;
this.factTypeManager = factTypeManager;
this.processingQueue = [];
this.isProcessing = false;
}
async processSequentialThinking(sequentialData, context = {}) {
try {
const facts = this.extractFactsFromSequentialThinking(sequentialData, context);
const processedFacts = [];
for (const fact of facts) {
const processed = await this.processFact(fact);
if (processed) {
processedFacts.push(processed);
}
}
return {
processed: processedFacts.length,
total: facts.length,
facts: processedFacts,
};
} catch (error) {
console.error('Error processing sequential thinking:', error);
return { processed: 0, total: 0, facts: [], error: error.message };
}
}
extractFactsFromSequentialThinking(sequentialData, context) {
const facts = [];
if (typeof sequentialData === 'string') {
return this.extractFromText(sequentialData, context);
}
if (Array.isArray(sequentialData)) {
for (const item of sequentialData) {
facts.push(...this.extractFactsFromSequentialThinking(item, context));
}
return facts;
}
if (sequentialData && typeof sequentialData === 'object') {
if (sequentialData.content) {
facts.push(...this.extractFromText(sequentialData.content, {
...context,
...sequentialData.context,
}));
}
if (sequentialData.steps && Array.isArray(sequentialData.steps)) {
for (const step of sequentialData.steps) {
facts.push(...this.extractFactsFromSequentialThinking(step, context));
}
}
}
return facts;
}
extractFromText(text, context) {
const facts = [];
const insights = this.findInsights(text);
const patterns = this.findPatterns(text);
const decisions = this.findDecisions(text);
const problems = this.findProblems(text);
facts.push(...insights.map(content => ({
content,
type: 'discovery',
context,
extractedAt: new Date().toISOString(),
})));
facts.push(...patterns.map(content => ({
content,
type: 'verified_pattern',
context,
extractedAt: new Date().toISOString(),
})));
facts.push(...decisions.map(content => ({
content,
type: 'decision_rationale',
context,
extractedAt: new Date().toISOString(),
})));
facts.push(...problems.map(content => ({
content,
type: 'debugging_solution',
context,
extractedAt: new Date().toISOString(),
})));
return facts;
}
findInsights(text) {
const insightPatterns = [
/(?:I (?:learned|discovered|found|realized)|It turns out|Interesting(?:ly)?|Key insight)[:\s]+([^.!?]+[.!?])/gi,
/(?:The key is|Important to note|Worth noting)[:\s]+([^.!?]+[.!?])/gi,
/(?:This (?:means|implies|suggests))[:\s]+([^.!?]+[.!?])/gi,
];
return this.extractWithPatterns(text, insightPatterns);
}
findPatterns(text) {
const patternPatterns = [
/(?:The pattern is|Pattern:|Best practice)[:\s]+([^.!?]+[.!?])/gi,
/(?:Always|Never|Should|Must|Recommended)[:\s]+([^.!?]+[.!?])/gi,
/(?:Use|Avoid|Prefer)[:\s]+([^.!?]+[.!?])/gi,
];
return this.extractWithPatterns(text, patternPatterns);
}
findDecisions(text) {
const decisionPatterns = [
/(?:I (?:decided|chose|selected)|Decision)[:\s]+([^.!?]+[.!?])/gi,
/(?:Because|Rationale|Reasoning)[:\s]+([^.!?]+[.!?])/gi,
/(?:Going with|Opting for)[:\s]+([^.!?]+[.!?])/gi,
];
return this.extractWithPatterns(text, decisionPatterns);
}
findProblems(text) {
const problemPatterns = [
/(?:Problem|Issue|Bug)[:\s]+([^.!?]+[.!?])/gi,
/(?:Solution|Fix|Workaround)[:\s]+([^.!?]+[.!?])/gi,
/(?:To (?:fix|solve|resolve))[:\s]+([^.!?]+[.!?])/gi,
];
return this.extractWithPatterns(text, problemPatterns);
}
extractWithPatterns(text, patterns) {
const results = [];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(text)) !== null) {
const content = match[1].trim();
if (content.length > 10 && content.length < 500) {
results.push(content);
}
}
}
return results;
}
async processFact(fact) {
try {
const enrichedFact = await this.enrichFact(fact);
if (!this.qualityScorer.meetsQualityThreshold(enrichedFact)) {
return null;
}
const existingFact = await this.findSimilarFact(enrichedFact);
if (existingFact) {
return await this.mergeFacts(existingFact, enrichedFact);
}
return await this.factStore.storeFact(enrichedFact);
} catch (error) {
console.error('Error processing fact:', error);
return null;
}
}
async enrichFact(fact) {
const classifiedType = this.factTypeManager.classifyContent(
fact.content,
fact.tags || [],
fact.context || {}
);
const enriched = {
id: randomUUID(),
content: fact.content,
type: fact.type || classifiedType,
domain: fact.domain || this.inferDomain(fact),
tags: fact.tags || this.extractTags(fact.content),
context: fact.context || {},
metadata: {
source: 'sequential_thinking',
extractedAt: fact.extractedAt || new Date().toISOString(),
processedAt: new Date().toISOString(),
},
relationships: [],
accessCount: 0,
lastAccessed: null,
...fact,
};
const qualityResult = this.qualityScorer.calculateQualityScore(enriched);
enriched.qualityScore = qualityResult.totalScore;
enriched.qualityBreakdown = qualityResult;
return enriched;
}
inferDomain(fact) {
const content = fact.content.toLowerCase();
const context = fact.context || {};
if (context.domain) return context.domain;
const domainKeywords = {
web_development: ['react', 'html', 'css', 'javascript', 'frontend', 'backend', 'api'],
data_science: ['python', 'pandas', 'numpy', 'jupyter', 'analysis', 'model'],
devops: ['docker', 'kubernetes', 'deploy', 'ci/cd', 'pipeline', 'infrastructure'],
mobile: ['ios', 'android', 'react native', 'flutter', 'mobile'],
security: ['auth', 'security', 'encrypt', 'vulnerability', 'secure'],
};
for (const [domain, keywords] of Object.entries(domainKeywords)) {
if (keywords.some(keyword => content.includes(keyword))) {
return domain;
}
}
return 'general';
}
extractTags(content) {
const tags = [];
const tagPatterns = [
/#(\w+)/g,
/\b(important|critical|urgent|experimental|tested|verified)\b/gi,
];
for (const pattern of tagPatterns) {
let match;
while ((match = pattern.exec(content)) !== null) {
tags.push(match[1].toLowerCase());
}
}
return [...new Set(tags)];
}
async findSimilarFact(fact) {
const similarFacts = await this.factStore.queryFacts({
query: fact.content.substring(0, 50),
type: fact.type,
domain: fact.domain,
similarityThreshold: 0.8,
limit: 1,
});
return similarFacts.length > 0 ? similarFacts[0] : null;
}
async mergeFacts(existingFact, newFact) {
const merged = {
...existingFact,
content: this.mergeContent(existingFact.content, newFact.content),
tags: [...new Set([...existingFact.tags, ...newFact.tags])],
context: { ...existingFact.context, ...newFact.context },
metadata: {
...existingFact.metadata,
lastMerged: new Date().toISOString(),
mergeCount: (existingFact.metadata.mergeCount || 0) + 1,
},
};
const qualityResult = this.qualityScorer.calculateQualityScore(merged);
merged.qualityScore = qualityResult.totalScore;
merged.qualityBreakdown = qualityResult;
return await this.factStore.updateFact(merged.id, merged);
}
mergeContent(existing, newContent) {
if (newContent.length > existing.length) {
return newContent;
}
return existing;
}
async queueProcessing(sequentialData, context) {
this.processingQueue.push({ sequentialData, context });
if (!this.isProcessing) {
this.processQueue();
}
}
async processQueue() {
if (this.isProcessing || this.processingQueue.length === 0) {
return;
}
this.isProcessing = true;
try {
while (this.processingQueue.length > 0) {
const { sequentialData, context } = this.processingQueue.shift();
await this.processSequentialThinking(sequentialData, context);
await new Promise(resolve => setTimeout(resolve, 100));
}
} catch (error) {
console.error('Error processing queue:', error);
} finally {
this.isProcessing = false;
}
}
}