Skip to main content
Glama
reasoning-workflow.test.ts26.1 kB
/** * Reasoning Workflow Integration Tests (Mocked) * * Tests the interaction between Orchestrator, Streams, and SynthesisEngine * using mocks for external dependencies. * * This is an integration test that verifies internal module interactions work correctly, * NOT a test of external service integration. * * Requirements: 12.2, 12.3, 12.4 */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { Problem } from "../../framework/types"; import type { ReasoningContext } from "../../reasoning/types"; // Mock emotion model for emotion detection components function createMockEmotionModel() { return { name: "mock-emotion-model", version: "1.0.0", analyzeValence: vi.fn().mockReturnValue(0.5), analyzeArousal: vi.fn().mockReturnValue(0.5), analyzeDominance: vi.fn().mockReturnValue(0.5), classifyEmotions: vi.fn().mockReturnValue([]), }; } describe("Reasoning Workflow Integration (Mocked)", () => { let mockEmotionModel: ReturnType<typeof createMockEmotionModel>; beforeEach(() => { vi.clearAllMocks(); mockEmotionModel = createMockEmotionModel(); }); afterEach(() => { vi.restoreAllMocks(); }); describe("Complete Reasoning Pipeline", () => { it("should coordinate problem classification, framework selection, and reasoning execution", async () => { // Import real components (they don't have external dependencies) const { ProblemClassifier } = await import("../../framework/problem-classifier"); const { FrameworkRegistry } = await import("../../framework/framework-registry"); const { FrameworkLearningSystem } = await import("../../framework/framework-learning"); const { FrameworkSelector } = await import("../../framework/framework-selector"); // Initialize components const problemClassifier = new ProblemClassifier(); const registry = FrameworkRegistry.getInstance(); const learningSystem = new FrameworkLearningSystem(); const frameworkSelector = new FrameworkSelector(problemClassifier, registry, learningSystem); // Define test problem const problem: Problem = { id: "test-problem-1", description: "How can we improve database query performance?", context: "Production database with scaling challenges", constraints: ["Cannot change schema", "Must maintain compatibility"], goals: ["Reduce query time", "Improve user experience"], }; // Step 1: Classify problem const classification = problemClassifier.classifyProblem(problem); expect(classification).toBeDefined(); expect(classification.complexity).toMatch(/simple|moderate|complex/); expect(classification.uncertainty).toMatch(/low|medium|high/); // Step 2: Select framework const context = { problem, evidence: [], constraints: problem.constraints || [], goals: problem.goals || [], }; const selection = frameworkSelector.selectFramework(problem, context); expect(selection).toBeDefined(); expect(selection.primaryFramework).toBeDefined(); expect(selection.confidence).toBeGreaterThan(0); expect(selection.confidence).toBeLessThanOrEqual(1); // Step 3: Verify framework selection is appropriate for problem type expect(selection.primaryFramework.name).toBeDefined(); }); it("should execute parallel reasoning streams and synthesize results", async () => { const { ParallelReasoningOrchestrator } = await import("../../reasoning/orchestrator"); const { AnalyticalReasoningStream } = await import( "../../reasoning/streams/analytical-stream" ); const { CreativeReasoningStream } = await import("../../reasoning/streams/creative-stream"); const { CriticalReasoningStream } = await import("../../reasoning/streams/critical-stream"); const { SyntheticReasoningStream } = await import("../../reasoning/streams/synthetic-stream"); const orchestrator = new ParallelReasoningOrchestrator(); const streams = [ new AnalyticalReasoningStream(), new CreativeReasoningStream(), new CriticalReasoningStream(), new SyntheticReasoningStream(), ]; const problem: Problem = { id: "test-problem-2", description: "Design a new feature for real-time collaboration", context: "Web application with 10k+ users", constraints: ["Must work with existing architecture", "Budget limit"], goals: ["Enable real-time collaboration", "Maintain performance"], }; // Execute parallel reasoning const result = await orchestrator.executeStreams(problem, streams, 30000); // Verify synthesis result structure expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(result.insights).toBeDefined(); expect(result.recommendations).toBeDefined(); expect(result.confidence).toBeGreaterThan(0); expect(result.confidence).toBeLessThanOrEqual(1); // Verify insights from multiple streams expect(result.insights.length).toBeGreaterThan(0); // Verify recommendations have sources for (const rec of result.recommendations) { expect(rec.sources).toBeDefined(); expect(rec.sources.length).toBeGreaterThan(0); } }, 35000); }); describe("Confidence Assessment Integration", () => { it("should assess confidence for reasoning results", async () => { const { MultiDimensionalConfidenceAssessor } = await import( "../../confidence/multi-dimensional-assessor" ); const confidenceAssessor = new MultiDimensionalConfidenceAssessor(); const problem: Problem = { id: "test-problem-3", description: "Should we migrate to microservices?", context: "Monolithic application with scaling challenges", constraints: ["Limited team size"], goals: ["Improve scalability"], }; const reasoningContext: ReasoningContext = { problem, evidence: [ "Evidence 1: Current system struggles with load", "Evidence 2: Team has microservices experience", ], constraints: problem.constraints || [], goals: problem.goals || [], }; // Assess confidence const confidence = await confidenceAssessor.assessConfidence(reasoningContext); expect(confidence).toBeDefined(); expect(confidence.overallConfidence).toBeGreaterThan(0); expect(confidence.overallConfidence).toBeLessThanOrEqual(1); expect(confidence.evidenceQuality).toBeDefined(); expect(confidence.reasoningCoherence).toBeDefined(); expect(confidence.completeness).toBeDefined(); }); it("should identify uncertainty in high-risk problems", async () => { const { MultiDimensionalConfidenceAssessor } = await import( "../../confidence/multi-dimensional-assessor" ); const confidenceAssessor = new MultiDimensionalConfidenceAssessor(); const problem: Problem = { id: "test-problem-4", description: "Predict market trends for next quarter", context: "Highly volatile market conditions", constraints: ["Limited historical data", "Many unknown factors"], goals: ["Maximize returns", "Minimize risk"], }; const reasoningContext: ReasoningContext = { problem, evidence: ["Limited data available"], constraints: problem.constraints || [], goals: problem.goals || [], }; const confidence = await confidenceAssessor.assessConfidence(reasoningContext); // High uncertainty problem should have lower confidence expect(confidence.overallConfidence).toBeLessThan(0.9); expect(confidence.uncertaintyType).toMatch(/epistemic|aleatoric|ambiguity/); }); }); describe("Bias Detection Integration", () => { it("should detect biases in reasoning chains", async () => { const { BiasPatternRecognizer } = await import("../../bias/bias-pattern-recognizer"); const biasRecognizer = new BiasPatternRecognizer(); // Create a reasoning chain with potential biases const reasoningChain = { id: "test-chain-1", steps: [ { id: "step-1", type: "inference" as const, content: "All data supports our hypothesis", timestamp: new Date(), }, ], branches: [], assumptions: [ { id: "assumption-1", content: "We should continue because we've already invested", explicit: true, confidence: 0.8, }, ], inferences: [ { id: "inference-1", content: "Must continue to justify investment", premises: ["Significant investment made"], confidence: 0.7, type: "deductive" as const, }, ], evidence: [ { id: "evidence-1", content: "Significant investment made", source: "context", reliability: 0.8, }, ], conclusion: "Continue with current approach", }; const detectedBiases = biasRecognizer.detectBiases(reasoningChain); expect(detectedBiases).toBeDefined(); expect(Array.isArray(detectedBiases)).toBe(true); // If biases detected, verify structure if (detectedBiases.length > 0) { for (const bias of detectedBiases) { expect(bias.type).toBeDefined(); expect(bias.severity).toBeGreaterThan(0); expect(bias.severity).toBeLessThanOrEqual(1); expect(bias.evidence).toBeDefined(); } } }); it("should detect multiple biases in comprehensive test case", async () => { const { BiasPatternRecognizer } = await import("../../bias/bias-pattern-recognizer"); const biasRecognizer = new BiasPatternRecognizer(); const testCase = "All the data clearly supports my hypothesis. I've been working on this for 6 months " + "and invested significant resources, so we should definitely continue. Everyone else " + "is doing it this way."; const detectedBiases = biasRecognizer.detectBiasesFromText(testCase); // Should detect at least 3 biases expect(detectedBiases.length).toBeGreaterThanOrEqual(3); // Verify confirmation bias const confirmationBias = detectedBiases.find((b) => b.type === "confirmation"); expect(confirmationBias).toBeDefined(); // Verify sunk cost fallacy const sunkCostBias = detectedBiases.find((b) => b.type === "sunk_cost"); expect(sunkCostBias).toBeDefined(); // Verify bandwagon effect (mapped to representativeness) const bandwagonBias = detectedBiases.find((b) => b.type === "representativeness"); expect(bandwagonBias).toBeDefined(); }); it("should apply bias correction when biases are detected", async () => { const { BiasPatternRecognizer } = await import("../../bias/bias-pattern-recognizer"); const { BiasCorrectionEngine } = await import("../../bias/bias-correction-engine"); const biasRecognizer = new BiasPatternRecognizer(); const correctionEngine = new BiasCorrectionEngine(); const reasoningChain = { id: "test-chain-2", steps: [ { id: "step-1", type: "inference" as const, content: "We should continue because we've invested significantly", timestamp: new Date(), }, ], branches: [], assumptions: [ { id: "assumption-1", content: "Sunk costs justify continuation", explicit: true, confidence: 0.8, }, ], inferences: [ { id: "inference-1", content: "Must continue to justify investment", premises: ["Significant investment made"], confidence: 0.7, type: "deductive" as const, }, ], evidence: [ { id: "evidence-1", content: "Significant investment made", source: "context", reliability: 0.8, }, ], conclusion: "Continue with current approach", }; const detectedBiases = biasRecognizer.detectBiases(reasoningChain); const sunkCostBias = detectedBiases.find((b) => b.type === "sunk_cost"); if (sunkCostBias) { const corrected = correctionEngine.correctBias(sunkCostBias, reasoningChain); expect(corrected).toBeDefined(); expect(corrected.corrected).toBeDefined(); expect(corrected.correctionsApplied).toBeDefined(); } }); }); describe("Emotion Detection Integration", () => { it("should detect emotions in problem context", async () => { const { CircumplexEmotionAnalyzer } = await import("../../emotion/circumplex-analyzer"); const { DiscreteEmotionClassifier } = await import( "../../emotion/discrete-emotion-classifier" ); const emotionAnalyzer = new CircumplexEmotionAnalyzer(mockEmotionModel); const emotionClassifier = new DiscreteEmotionClassifier(mockEmotionModel); const emotionalProblem = "I'm really frustrated with our system's performance. Users are complaining."; // Detect circumplex dimensions const circumplex = emotionAnalyzer.analyzeCircumplex(emotionalProblem); expect(circumplex).toBeDefined(); expect(circumplex.valence).toBeDefined(); expect(circumplex.arousal).toBeDefined(); expect(circumplex.confidence).toBeGreaterThan(0); // Detect discrete emotions const emotions = emotionClassifier.classify(emotionalProblem); expect(emotions).toBeDefined(); }); it("should process contextual emotional factors", async () => { const { ContextualEmotionProcessor } = await import("../../emotion/contextual-processor"); // ProfessionalContext type is used inline below await import("../../emotion/types"); const processor = new ContextualEmotionProcessor(mockEmotionModel); const text = "I'm feeling okay about this situation"; const professionalContext = { setting: "formal" as const, relationship: "peer" as const, domain: "technology", }; const result = processor.processWithContext(text, { professionalContext }); expect(result).toBeDefined(); expect(result.circumplex).toBeDefined(); expect(result.circumplex.valence).toBeDefined(); expect(result.circumplex.arousal).toBeDefined(); expect(result.circumplex.dominance).toBeDefined(); expect(result.confidence).toBeGreaterThan(0); }); }); describe("Error Handling Integration", () => { it("should handle invalid problem gracefully", async () => { const { ProblemClassifier } = await import("../../framework/problem-classifier"); const { FrameworkRegistry } = await import("../../framework/framework-registry"); const { FrameworkLearningSystem } = await import("../../framework/framework-learning"); const { FrameworkSelector } = await import("../../framework/framework-selector"); const problemClassifier = new ProblemClassifier(); const registry = FrameworkRegistry.getInstance(); const learningSystem = new FrameworkLearningSystem(); const frameworkSelector = new FrameworkSelector(problemClassifier, registry, learningSystem); const invalidProblem: Problem = { id: "test-problem-invalid", description: "", // Empty description context: "", constraints: [], goals: [], }; // Should throw validation error expect(() => problemClassifier.classifyProblem(invalidProblem)).toThrow( "Problem must have id and description" ); const invalidContext = { problem: invalidProblem, evidence: [], constraints: [], goals: [], }; expect(() => frameworkSelector.selectFramework(invalidProblem, invalidContext)).toThrow(); }); it("should handle reasoning timeout gracefully", async () => { const { ParallelReasoningOrchestrator } = await import("../../reasoning/orchestrator"); const { AnalyticalReasoningStream } = await import( "../../reasoning/streams/analytical-stream" ); const { CreativeReasoningStream } = await import("../../reasoning/streams/creative-stream"); const { CriticalReasoningStream } = await import("../../reasoning/streams/critical-stream"); const { SyntheticReasoningStream } = await import("../../reasoning/streams/synthetic-stream"); const orchestrator = new ParallelReasoningOrchestrator(); const streams = [ new AnalyticalReasoningStream(), new CreativeReasoningStream(), new CriticalReasoningStream(), new SyntheticReasoningStream(), ]; const problem: Problem = { id: "test-problem-timeout", description: "Complex problem that might timeout", context: "Testing timeout handling", constraints: ["Time constraint"], goals: ["Test timeout"], }; // Use very short timeout const result = await orchestrator.executeStreams(problem, streams, 100); // Should return partial results even if timeout expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); }, 5000); it("should recover from individual stream failures", async () => { const { ParallelReasoningOrchestrator } = await import("../../reasoning/orchestrator"); const { AnalyticalReasoningStream } = await import( "../../reasoning/streams/analytical-stream" ); const { CreativeReasoningStream } = await import("../../reasoning/streams/creative-stream"); const { CriticalReasoningStream } = await import("../../reasoning/streams/critical-stream"); const { SyntheticReasoningStream } = await import("../../reasoning/streams/synthetic-stream"); const orchestrator = new ParallelReasoningOrchestrator(); const streams = [ new AnalyticalReasoningStream(), new CreativeReasoningStream(), new CriticalReasoningStream(), new SyntheticReasoningStream(), ]; const problem: Problem = { id: "test-problem-recovery", description: "Test problem for stream failure recovery", context: "Testing error recovery", constraints: ["Error handling"], goals: ["Graceful degradation"], }; const result = await orchestrator.executeStreams(problem, streams, 30000); // Should complete even if some streams fail expect(result).toBeDefined(); expect(result.conclusion).toBeDefined(); expect(result.insights.length).toBeGreaterThan(0); }, 35000); }); describe("Performance Validation", () => { it("should complete reasoning workflow within reasonable time", async () => { const { ProblemClassifier } = await import("../../framework/problem-classifier"); const { FrameworkRegistry } = await import("../../framework/framework-registry"); const { FrameworkLearningSystem } = await import("../../framework/framework-learning"); const { FrameworkSelector } = await import("../../framework/framework-selector"); const { ParallelReasoningOrchestrator } = await import("../../reasoning/orchestrator"); const { MultiDimensionalConfidenceAssessor } = await import( "../../confidence/multi-dimensional-assessor" ); const { AnalyticalReasoningStream } = await import( "../../reasoning/streams/analytical-stream" ); const { CreativeReasoningStream } = await import("../../reasoning/streams/creative-stream"); const { CriticalReasoningStream } = await import("../../reasoning/streams/critical-stream"); const { SyntheticReasoningStream } = await import("../../reasoning/streams/synthetic-stream"); const problemClassifier = new ProblemClassifier(); const registry = FrameworkRegistry.getInstance(); const learningSystem = new FrameworkLearningSystem(); const frameworkSelector = new FrameworkSelector(problemClassifier, registry, learningSystem); const orchestrator = new ParallelReasoningOrchestrator(); const confidenceAssessor = new MultiDimensionalConfidenceAssessor(); const problem: Problem = { id: "test-problem-perf", description: "How should we prioritize our product roadmap?", context: "Multiple competing features, limited resources", constraints: ["Team of 5 engineers", "3-month timeline"], goals: ["Maximize user value", "Meet business objectives"], }; const start = Date.now(); // Execute full workflow const classification = problemClassifier.classifyProblem(problem); const context = { problem, evidence: [], constraints: problem.constraints || [], goals: problem.goals || [], }; const selection = frameworkSelector.selectFramework(problem, context); const streams = [ new AnalyticalReasoningStream(), new CreativeReasoningStream(), new CriticalReasoningStream(), new SyntheticReasoningStream(), ]; const reasoningResult = await orchestrator.executeStreams(problem, streams, 30000); const reasoningContext: ReasoningContext = { problem, evidence: reasoningResult.insights.map((i) => i.content), constraints: problem.constraints || [], goals: problem.goals || [], }; const confidence = await confidenceAssessor.assessConfidence(reasoningContext); const duration = Date.now() - start; // Verify all components completed expect(classification).toBeDefined(); expect(selection).toBeDefined(); expect(reasoningResult).toBeDefined(); expect(confidence).toBeDefined(); // Should complete within 30 seconds expect(duration).toBeLessThan(30000); }, 35000); it("should meet confidence assessment latency target", async () => { const { MultiDimensionalConfidenceAssessor } = await import( "../../confidence/multi-dimensional-assessor" ); const confidenceAssessor = new MultiDimensionalConfidenceAssessor(); const problem: Problem = { id: "test-problem-latency", description: "Test problem for performance", context: "Performance test context", constraints: ["Test constraint"], goals: ["Test goal"], }; const reasoningContext: ReasoningContext = { problem, evidence: ["Evidence 1", "Evidence 2", "Evidence 3"], constraints: problem.constraints || [], goals: problem.goals || [], }; const latencies: number[] = []; // Measure confidence assessment latency for (let i = 0; i < 10; i++) { const start = Date.now(); await confidenceAssessor.assessConfidence(reasoningContext); const latency = Date.now() - start; latencies.push(latency); } // Calculate average latency const avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length; expect(avgLatency).toBeLessThan(100); // <100ms target }); it("should maintain bias detection overhead below 15%", async () => { const { ParallelReasoningOrchestrator } = await import("../../reasoning/orchestrator"); const { BiasPatternRecognizer } = await import("../../bias/bias-pattern-recognizer"); const { AnalyticalReasoningStream } = await import( "../../reasoning/streams/analytical-stream" ); const { CreativeReasoningStream } = await import("../../reasoning/streams/creative-stream"); const { CriticalReasoningStream } = await import("../../reasoning/streams/critical-stream"); const { SyntheticReasoningStream } = await import("../../reasoning/streams/synthetic-stream"); const orchestrator = new ParallelReasoningOrchestrator(); const biasRecognizer = new BiasPatternRecognizer(); const problem: Problem = { id: "test-problem-overhead", description: "Performance test for bias detection overhead", context: "Testing bias detection performance impact", constraints: ["Performance constraint"], goals: ["Measure overhead"], }; const streams = [ new AnalyticalReasoningStream(), new CreativeReasoningStream(), new CriticalReasoningStream(), new SyntheticReasoningStream(), ]; // Measure reasoning time const startReasoning = Date.now(); const result = await orchestrator.executeStreams(problem, streams, 30000); const reasoningDuration = Date.now() - startReasoning; // Measure bias detection time const reasoningChain = { id: "test-chain-3", steps: [ { id: "step-1", type: "inference" as const, content: result.conclusion, timestamp: new Date(), }, ], branches: [], assumptions: [], inferences: [], evidence: [], conclusion: result.conclusion, }; const startBias = Date.now(); biasRecognizer.detectBiases(reasoningChain); const biasDuration = Date.now() - startBias; // Bias detection should be fast in absolute terms (< 200ms) // This is more reliable than percentage-based checks in mocked environments // where reasoning time can be artificially short expect(biasDuration).toBeLessThan(200); // Only check percentage overhead if reasoning took meaningful time (> 100ms) // to avoid flaky results from near-zero division if (reasoningDuration > 100) { const overhead = (biasDuration / reasoningDuration) * 100; expect(overhead).toBeLessThan(15); } }, 35000); }); });

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