Skip to main content
Glama
creative-stream.ts23.8 kB
/** * Creative Reasoning Stream * * Implements innovative, divergent thinking with: * - Brainstorming and ideation * - Alternative solution generation * - Creative techniques (analogy, metaphor, reframing, lateral thinking) * - Novelty scoring (how unique/innovative) * - Feasibility assessment (how practical) * - Progress tracking and timeout management * - Problem-specific ideas (Requirements 4.2, 15.3) */ import { KeyTermExtractor, type KeyTerms } from "../key-term-extractor"; import type { ReasoningStream, StreamProcessor } from "../stream"; import { StreamStatus, StreamType, type Insight, type Problem, type StreamResult } from "../types"; /** * Creative stream processor * * Implements the core creative reasoning logic with brainstorming, * alternative generation, and creative techniques. * Generates problem-specific ideas using key term extraction. */ export class CreativeStreamProcessor implements StreamProcessor { private readonly keyTermExtractor: KeyTermExtractor; constructor() { this.keyTermExtractor = new KeyTermExtractor(); } /** * Process a problem using creative reasoning * * @param problem - Problem to analyze * @returns Promise resolving to stream result */ async process(problem: Problem): Promise<StreamResult> { const startTime = Date.now(); const reasoning: string[] = []; const insights: Insight[] = []; // Validate problem - throw for truly invalid problems if (!problem || !problem.id || !problem.description) { throw new Error("Invalid problem: missing required fields"); } try { // Extract key terms for problem-specific ideas (Req 4.2, 15.3) const keyTerms = this.keyTermExtractor.extract(problem.description, problem.context); // Step 1: Initial brainstorming reasoning.push( `Brainstorming innovative solutions for: ${problem.description.substring(0, 100)}${problem.description.length > 100 ? "..." : ""}` ); // Step 2: Generate diverse ideas using creative techniques const ideas = this.generateCreativeIdeas(problem, keyTerms); reasoning.push(`Generated ${ideas.length} diverse ideas using multiple creative techniques`); // Step 3: Apply creative techniques const analogyIdeas = this.applyAnalogy(problem, keyTerms); if (analogyIdeas.length > 0) { reasoning.push(`Using analogy: ${analogyIdeas[0].content.substring(0, 80)}...`); insights.push(...analogyIdeas); } const reframingIdeas = this.applyReframing(problem, keyTerms); if (reframingIdeas.length > 0) { reasoning.push(`Reframing perspective: ${reframingIdeas[0].content.substring(0, 80)}...`); insights.push(...reframingIdeas); } const lateralIdeas = this.applyLateralThinking(problem, keyTerms); if (lateralIdeas.length > 0) { reasoning.push(`What if we ${lateralIdeas[0].content.toLowerCase().substring(0, 60)}...?`); insights.push(...lateralIdeas); } // Step 4: Combine and build on ideas const combinedIdeas = this.combineIdeas(ideas, problem, keyTerms); if (combinedIdeas.length > 0) { reasoning.push( `Building on previous ideas: combining ${combinedIdeas.length} concepts together` ); insights.push(...combinedIdeas); } // Step 5: Assess novelty and feasibility const scoredIdeas = this.scoreIdeas([...ideas, ...insights], problem); reasoning.push( `Assessed novelty and feasibility: ${scoredIdeas.filter((i) => i.importance > 0.7).length} highly novel ideas identified` ); // Step 6: Consider constraints while maintaining creativity if (problem.constraints && problem.constraints.length > 0) { reasoning.push( `Considering constraints: ${problem.constraints.join(", ")} - but looking for creative workarounds` ); const constraintAwareIdeas = this.adaptToConstraints(scoredIdeas, problem, keyTerms); insights.push(...constraintAwareIdeas); } // Step 7: Generate conclusion const conclusion = this.generateConclusion(problem, scoredIdeas, keyTerms); reasoning.push(`Therefore, ${conclusion}`); // Calculate confidence based on idea quality and diversity const confidence = this.calculateConfidence(problem, scoredIdeas); const processingTime = Math.max(1, Date.now() - startTime); // Return top scored ideas as final insights const finalInsights = scoredIdeas .sort((a, b) => b.importance - a.importance) .slice(0, Math.min(10, scoredIdeas.length)); return { streamId: `creative-${problem.id}`, streamType: StreamType.CREATIVE, conclusion, reasoning, insights: finalInsights, confidence, processingTime, status: StreamStatus.COMPLETED, }; } catch (error) { const processingTime = Math.max(1, Date.now() - startTime); return { streamId: `creative-${problem.id}`, streamType: StreamType.CREATIVE, conclusion: "", reasoning, insights, confidence: 0, processingTime, status: StreamStatus.FAILED, error: error as Error, }; } } /** * Get the stream type this processor handles * * @returns Stream type identifier */ getStreamType(): StreamType { return StreamType.CREATIVE; } /** * Generate creative ideas through brainstorming with term reference tracking * * @param problem - Problem to brainstorm * @param keyTerms - Extracted key terms for problem-specific ideas * @returns Array of creative insights with referenced terms tracked */ private generateCreativeIdeas(problem: Problem, keyTerms: KeyTerms): Insight[] { const ideas: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "the challenge"; const domainTerms = keyTerms.domainTerms.slice(0, 2); const actionVerb = keyTerms.actionVerbs[0] || "transform"; // Generate problem-specific ideas using extracted terms const ideaTemplates = [ `Create a novel ${domainTerms[0] || "approach"} for ${primaryTerm} that leverages ${domainTerms[1] || "existing strengths"}`, `Imagine ${primaryTerm} reimagined with ${problem.goals?.[0] || "enhanced capabilities"}`, `Design a unique method to ${actionVerb} ${primaryTerm} using unconventional techniques`, `Develop an innovative ${domainTerms[0] || "strategy"} that addresses ${primaryTerm} from a fresh angle`, `Invent a creative way to ${problem.goals?.[0] || `improve ${primaryTerm}`} by combining disparate concepts`, ]; for (const template of ideaTemplates) { ideas.push({ content: template, source: StreamType.CREATIVE, confidence: 0.7, importance: 0.6 + Math.random() * 0.3, // Vary novelty scores referencedTerms: this.keyTermExtractor.findReferencedTerms(template, keyTerms), }); } return ideas; } /** * Apply analogy technique with term reference tracking * * @param problem - Problem to analyze * @param keyTerms - Extracted key terms for problem-specific analogies * @returns Array of analogy-based insights with referenced terms tracked */ private applyAnalogy(_problem: Problem, keyTerms: KeyTerms): Insight[] { const insights: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "this challenge"; const domainTerm = keyTerms.domainTerms[0] || ""; // Generate problem-specific analogies let analogy: string; if ( domainTerm === "performance" || domainTerm === "optimization" || domainTerm === "scalability" ) { analogy = `${primaryTerm} is like a highway system - we can apply traffic flow optimization principles to improve throughput`; } else if (domainTerm === "user" || domainTerm === "customer" || domainTerm === "engagement") { analogy = `${primaryTerm} is like a conversation - we can apply principles of active listening and responsiveness`; } else if (domainTerm === "security" || domainTerm === "authentication") { analogy = `${primaryTerm} is like a castle defense - we can apply layered protection strategies`; } else if (domainTerm === "data" || domainTerm === "analytics") { analogy = `${primaryTerm} is like archaeology - we can apply systematic excavation techniques to uncover insights`; } else { analogy = `${primaryTerm} is like how nature solves similar problems through evolution - we could apply adaptive principles`; } insights.push({ content: analogy, source: StreamType.CREATIVE, confidence: 0.65, importance: 0.75, referencedTerms: this.keyTermExtractor.findReferencedTerms(analogy, keyTerms), }); return insights; } /** * Apply reframing technique with term reference tracking * * @param problem - Problem to reframe * @param keyTerms - Extracted key terms for problem-specific reframing * @returns Array of reframed insights with referenced terms tracked */ private applyReframing(_problem: Problem, keyTerms: KeyTerms): Insight[] { const insights: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "this situation"; const actionVerb = keyTerms.actionVerbs[0] || "improve"; // Generate problem-specific reframing const perspectives = [ `Reframing ${primaryTerm}: what if we viewed this as an opportunity to ${actionVerb} rather than a problem to fix?`, `Instead of trying to ${actionVerb} ${primaryTerm}, what if we reimagined the entire approach from scratch?`, `From a user's perspective: what would make ${primaryTerm} delightful rather than just functional?`, ]; const selectedPerspective = perspectives[Math.floor(Math.random() * perspectives.length)]; insights.push({ content: selectedPerspective, source: StreamType.CREATIVE, confidence: 0.7, importance: 0.8, referencedTerms: this.keyTermExtractor.findReferencedTerms(selectedPerspective, keyTerms), }); return insights; } /** * Apply lateral thinking technique with term reference tracking * * @param problem - Problem to analyze * @param keyTerms - Extracted key terms for problem-specific lateral thinking * @returns Array of lateral thinking insights with referenced terms tracked */ private applyLateralThinking(_problem: Problem, keyTerms: KeyTerms): Insight[] { const insights: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "this"; const domainTerm = keyTerms.domainTerms[0] || ""; // Generate problem-specific "what if" scenarios const lateralQuestions = [ `What if we did the exact opposite with ${primaryTerm} - instead of adding, what if we removed?`, `Suppose we had unlimited ${domainTerm || "resources"} for ${primaryTerm} - what would we try first?`, `What if ${primaryTerm} didn't need to exist at all - what would replace it?`, `Imagine we could redesign ${primaryTerm} from scratch with today's technology - what would be different?`, ]; const selectedQuestion = lateralQuestions[Math.floor(Math.random() * lateralQuestions.length)]; insights.push({ content: selectedQuestion, source: StreamType.CREATIVE, confidence: 0.6, importance: 0.85, referencedTerms: this.keyTermExtractor.findReferencedTerms(selectedQuestion, keyTerms), }); return insights; } /** * Combine ideas in novel ways with term reference tracking * * @param ideas - Existing ideas * @param problem - Original problem * @param keyTerms - Extracted key terms for problem-specific combinations * @returns Array of combined insights with referenced terms tracked */ private combineIdeas(ideas: Insight[], _problem: Problem, keyTerms: KeyTerms): Insight[] { const combined: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "the solution"; const domainTerms = keyTerms.domainTerms.slice(0, 2); if (ideas.length >= 2) { // Combine ideas with problem-specific context const hybridContent = `Hybrid approach for ${primaryTerm}: combine ${ideas[0].content.substring(0, 40)}... with ${ideas[1].content.substring(0, 40)}...`; combined.push({ content: hybridContent, source: StreamType.CREATIVE, confidence: 0.65, importance: 0.7, referencedTerms: this.keyTermExtractor.findReferencedTerms(hybridContent, keyTerms), }); } // Add iterative improvement with specific terms if (ideas.length > 0 && domainTerms.length > 0) { const iterativeContent = `Building on ${primaryTerm} concept: integrate ${domainTerms.join(" and ")} elements for enhanced effectiveness`; combined.push({ content: iterativeContent, source: StreamType.CREATIVE, confidence: 0.7, importance: 0.65, referencedTerms: this.keyTermExtractor.findReferencedTerms(iterativeContent, keyTerms), }); } else if (ideas.length > 0) { const iterativeContent = `Building on ${primaryTerm} concept: iterate and expand with complementary approaches`; combined.push({ content: iterativeContent, source: StreamType.CREATIVE, confidence: 0.7, importance: 0.65, referencedTerms: this.keyTermExtractor.findReferencedTerms(iterativeContent, keyTerms), }); } return combined; } /** * Score ideas for novelty and feasibility * * @param ideas - Ideas to score * @param problem - Original problem * @returns Scored insights */ private scoreIdeas(ideas: Insight[], problem: Problem): Insight[] { return ideas.map((idea) => { // Novelty scoring based on content uniqueness let novelty = idea.importance || 0.6; // Boost novelty for certain keywords const content = idea.content.toLowerCase(); if ( content.includes("novel") || content.includes("innovative") || content.includes("unique") || content.includes("unconventional") ) { novelty += 0.1; } if (content.includes("what if") || content.includes("imagine")) { novelty += 0.15; } // Feasibility consideration let feasibility = 0.7; if (problem.constraints && problem.constraints.length > 0) { // Check if idea acknowledges constraints const acknowledgesConstraints = problem.constraints.some((constraint) => content.includes(constraint.toLowerCase()) ); if (acknowledgesConstraints) { feasibility += 0.2; } else { feasibility -= 0.1; } } // Balance novelty with feasibility const importance = Math.min(1.0, novelty * 0.7 + feasibility * 0.3); return { ...idea, importance: Math.max(0.1, Math.min(1.0, importance)), }; }); } /** * Adapt ideas to constraints while maintaining creativity with term reference tracking * * @param _ideas - Existing ideas (unused in current implementation) * @param problem - Problem with constraints * @param keyTerms - Extracted key terms for problem-specific adaptations * @returns Constraint-aware insights with referenced terms tracked */ private adaptToConstraints(_ideas: Insight[], problem: Problem, keyTerms: KeyTerms): Insight[] { const adapted: Insight[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "the solution"; if (problem.constraints && problem.constraints.length > 0) { const constraint = problem.constraints[0]; const workaroundContent = `Creative workaround for ${primaryTerm}: leverage ${constraint} as a design constraint that drives innovation`; adapted.push({ content: workaroundContent, source: StreamType.CREATIVE, confidence: 0.7, importance: 0.75, referencedTerms: this.keyTermExtractor.findReferencedTerms(workaroundContent, keyTerms), }); // Show optimistic, possibility-focused thinking with specific terms const optimisticContent = `Despite ${constraint}, ${primaryTerm} can achieve goals through creative ${keyTerms.domainTerms[0] || "resource"} allocation`; adapted.push({ content: optimisticContent, source: StreamType.CREATIVE, confidence: 0.65, importance: 0.7, referencedTerms: this.keyTermExtractor.findReferencedTerms(optimisticContent, keyTerms), }); } return adapted; } /** * Generate conclusion from creative analysis with validated term references * * @param problem - Original problem * @param ideas - Generated ideas * @param keyTerms - Extracted key terms for problem-specific conclusion * @returns Conclusion statement with guaranteed key term reference */ private generateConclusion(problem: Problem, ideas: Insight[], keyTerms: KeyTerms): string { const parts: string[] = []; const primaryTerm = keyTerms.primarySubject || keyTerms.terms[0] || "the challenge"; // Count highly novel ideas const highNoveltyCount = ideas.filter((i) => i.importance > 0.7).length; if (highNoveltyCount > 0) { parts.push( `${highNoveltyCount} highly innovative solution${highNoveltyCount > 1 ? "s" : ""} for ${primaryTerm} identified` ); } else { parts.push(`several creative approaches for ${primaryTerm} generated`); } // Address goals with specific terms if (problem.goals && problem.goals.length > 0) { parts.push(`that could ${problem.goals[0].toLowerCase()}`); } else if (keyTerms.actionVerbs.length > 0) { parts.push(`that could ${keyTerms.actionVerbs[0]} ${primaryTerm}`); } // Note feasibility with specific constraints if (problem.constraints && problem.constraints.length > 0) { parts.push(`while working within ${problem.constraints[0]}`); } else { parts.push("with strong potential for implementation"); } // Validate and ensure conclusion contains at least one key term const conclusion = parts.join(" "); return this.keyTermExtractor.ensureTermReference(conclusion, keyTerms); } /** * Calculate confidence score * * @param problem - Problem being analyzed * @param ideas - Generated ideas * @returns Confidence score (0-1) */ private calculateConfidence(problem: Problem, ideas: Insight[]): number { let confidence = 0.7; // Creative stream is generally confident in generating ideas // Boost confidence if we have many ideas if (ideas.length >= 5) { confidence += 0.1; } // Boost confidence if we have high novelty ideas const highNoveltyCount = ideas.filter((i) => i.importance > 0.7).length; if (highNoveltyCount >= 2) { confidence += 0.1; } // Reduce confidence if problem is very constrained if (problem.constraints && problem.constraints.length > 3) { confidence -= 0.15; } // Reduce confidence if context is limited or missing if (!problem.context || problem.context.trim().length === 0) { confidence -= 0.25; // Larger penalty for missing/empty context } else if (problem.context.length < 20) { confidence -= 0.2; // Penalty for very limited context } else if (problem.context.length < 50) { confidence -= 0.1; } return Math.max(0.1, Math.min(1.0, confidence)); } } /** * Creative Reasoning Stream * * Implements a reasoning stream that performs innovative, divergent thinking * with progress tracking, timeout management, and cancellation support. */ export class CreativeReasoningStream implements ReasoningStream { public readonly id: string; public readonly type: StreamType; public readonly processor: StreamProcessor; public readonly timeout: number; private progress: number = 0; private cancelled: boolean = false; private processing: boolean = false; /** * Create creative reasoning stream * * @param timeout - Timeout in milliseconds (default: 10000ms) */ constructor(timeout: number = 10000) { this.id = `creative-stream-${Date.now()}`; this.type = StreamType.CREATIVE; this.processor = new CreativeStreamProcessor(); this.timeout = timeout; } /** * Process a problem using creative reasoning * * @param problem - Problem to analyze * @returns Promise resolving to stream result */ async process(problem: Problem): Promise<StreamResult> { if (this.processing) { throw new Error("Stream is already processing"); } this.processing = true; this.progress = 0; this.cancelled = false; const startTime = Date.now(); try { // Create timeout promise const timeoutPromise = new Promise<StreamResult>((resolve) => { setTimeout(() => { if (!this.cancelled) { resolve({ streamId: this.id, streamType: this.type, conclusion: "Creative ideation incomplete due to timeout", reasoning: ["Processing exceeded time limit"], insights: [], confidence: 0.3, processingTime: this.timeout, status: StreamStatus.TIMEOUT, }); } }, this.timeout); }); // Create processing promise with progress tracking const processingPromise = this.processWithProgress(problem); // Race between processing and timeout let result = await Promise.race([processingPromise, timeoutPromise]); // Check if cancelled after processing completes (handles late cancellation) if (this.cancelled && result.status !== StreamStatus.CANCELLED) { result = { streamId: this.id, streamType: this.type, conclusion: "", reasoning: result.reasoning || [], insights: result.insights || [], confidence: 0, processingTime: Date.now() - startTime, status: StreamStatus.CANCELLED, }; } if (result.status === StreamStatus.COMPLETED) { this.progress = 1.0; } return result; } finally { this.processing = false; } } /** * Process with progress tracking * * @param problem - Problem to analyze * @returns Promise resolving to stream result */ private async processWithProgress(problem: Problem): Promise<StreamResult> { // Simulate progress updates during processing const progressInterval = setInterval(() => { if (!this.cancelled && this.progress < 0.9) { this.progress += 0.1; } }, this.timeout / 10); try { const result = await this.processor.process(problem); clearInterval(progressInterval); // Check if cancelled after processing if (this.cancelled) { return { streamId: this.id, streamType: this.type, conclusion: "", reasoning: result.reasoning || [], insights: result.insights || [], confidence: 0, processingTime: result.processingTime, status: StreamStatus.CANCELLED, }; } this.progress = 1.0; return result; } catch (error) { clearInterval(progressInterval); throw error; } } /** * Get current processing progress * * @returns Progress value between 0 and 1 */ getProgress(): number { return this.progress; } /** * Cancel stream processing */ cancel(): void { this.cancelled = true; this.progress = 0; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server