Skip to main content
Glama
synthetic-stream.test.ts34.7 kB
/** * Tests for Synthetic Reasoning Stream * * Validates integrative, holistic thinking with pattern recognition, * connection mapping, theme extraction, and synthesis capabilities. */ import { beforeEach, describe, expect, it, vi } from "vitest"; import { SyntheticReasoningStream, SyntheticStreamProcessor, } from "../../../../reasoning/streams/synthetic-stream"; import { StreamStatus, StreamType, type Problem } from "../../../../reasoning/types"; describe("SyntheticStreamProcessor", () => { let processor: SyntheticStreamProcessor; beforeEach(() => { processor = new SyntheticStreamProcessor(); }); describe("getStreamType", () => { it("should return SYNTHETIC stream type", () => { expect(processor.getStreamType()).toBe(StreamType.SYNTHETIC); }); }); describe("process - Pattern Recognition", () => { it("should identify systemic patterns in problem", async () => { const problem: Problem = { id: "test-1", description: "System shows recurring failures and cascading effects", context: "Multiple components fail in sequence, suggesting systemic issues", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.insights.length).toBeGreaterThan(0); expect(result.reasoning.some((r) => r.includes("pattern"))).toBe(true); }); it("should add pattern analysis reasoning for cause-effect patterns", async () => { const problem: Problem = { id: "test-pattern-cause", description: "System with clear cause and effect relationships", context: "Multiple factors with various patterns", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify pattern analysis reasoning is added (covers line 75-76) expect(result.reasoning.some((r) => r.includes("Pattern analysis:"))).toBe(true); }); it("should identify cause-effect patterns", async () => { const problem: Problem = { id: "test-2", description: "When A happens, B always follows, causing C", context: "Clear cause and effect relationships observed", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("pattern"))).toBe(true); }); it("should identify feedback loops in context", async () => { const problem: Problem = { id: "test-feedback", description: "System with feedback mechanisms", context: "The cycle reinforces itself creating a feedback loop", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.insights.some((i) => i.content.toLowerCase().includes("feedback"))).toBe(true); }); }); describe("process - Connection Mapping", () => { it("should map connections between concepts", async () => { const problem: Problem = { id: "test-3", description: "Factor X affects Y which influences Z", context: "Multiple factors are interconnected and affect each other", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.includes("connection"))).toBe(true); }); it("should identify hidden relationships", async () => { const problem: Problem = { id: "test-4", description: "Subtle indirect effects between components", context: "Hidden dependencies create unexpected behaviors", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("hidden"))).toBe(true); }); it("should identify interdependencies", async () => { const problem: Problem = { id: "test-5", description: "Components depend on each other mutually", context: "Interdependent systems with mutual dependencies", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("interdepend"))).toBe(true); }); it("should map influence networks with multiple constraints", async () => { const problem: Problem = { id: "test-influence", description: "Multiple constraints create complex influence patterns", context: "Various limitations interact", constraints: ["constraint1", "constraint2"], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify that connections are mapped (influence network is part of connections) expect(result.reasoning.some((r) => r.toLowerCase().includes("connection"))).toBe(true); }); }); describe("process - Theme Extraction", () => { it("should extract meta-level themes", async () => { const problem: Problem = { id: "test-6", description: "Higher level patterns emerge from details", context: "Meta-level themes tie everything together at a broader level", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("meta"))).toBe(true); }); it("should identify emergent properties", async () => { const problem: Problem = { id: "test-7", description: "The whole is greater than sum of parts", context: "Emergent behaviors arise from component interactions", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("emergent"))).toBe(true); }); }); describe("process - Integrative Thinking", () => { it("should integrate paradoxes and tensions", async () => { const problem: Problem = { id: "test-8", description: "Paradoxical situation with competing tensions", context: "Both perspectives are valid but seem contradictory", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.toLowerCase().includes("paradox"))).toBe(true); }); it("should synthesize multiple perspectives with sufficient insights", async () => { const problem: Problem = { id: "test-synthesis", description: "Complex problem with many patterns, connections, and themes", context: "Rich context with multiple interconnected factors, various patterns, several themes, and systemic complexity", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify synthesis happens through insights expect(result.insights.some((i) => i.content.toLowerCase().includes("synthesis"))).toBe(true); }); it("should bridge cross-domain insights with rich context", async () => { const problem: Problem = { id: "test-cross-domain", description: "Problem spanning multiple domains", context: "This problem involves technical, organizational, and strategic considerations that must be integrated across different domains and perspectives to achieve a comprehensive understanding", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify integration happens - context > 100 chars triggers integration expect(result.insights.length).toBeGreaterThan(0); expect(result.confidence).toBeGreaterThan(0); }); }); describe("process - Temporal Dynamics", () => { it("should consider temporal dynamics when context is provided", async () => { const problem: Problem = { id: "test-9", description: "System evolves over time", context: "Dynamic interactions change as system evolves", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.includes("time"))).toBe(true); }); it("should skip temporal analysis when context is empty", async () => { const problem: Problem = { id: "test-10", description: "System without temporal context", context: "", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Should still complete successfully expect(result.confidence).toBeGreaterThan(0); }); it("should consider time pressure for high urgency problems", async () => { const problem: Problem = { id: "test-urgency", description: "Urgent problem requiring quick action", context: "Time-sensitive situation with rapid evolution", constraints: [], goals: [], urgency: "high", }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Should mention time or temporal dynamics in insights or reasoning const hasTimeReference = result.insights.some((i) => i.content.toLowerCase().includes("time")) || result.reasoning.some( (r) => r.toLowerCase().includes("time") || r.toLowerCase().includes("temporal") ); expect(hasTimeReference).toBe(true); }); }); describe("process - Confidence Calculation", () => { it("should reduce confidence for missing context", async () => { const problem: Problem = { id: "test-11", description: "Problem without context", context: "", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.confidence).toBeLessThan(0.7); // Penalty for missing context }); it("should reduce confidence for very limited context", async () => { const problem: Problem = { id: "test-12", description: "Problem with minimal context", context: "Short", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.confidence).toBeLessThan(0.8); // Penalty for limited context }); it("should reduce confidence for moderately limited context", async () => { const problem: Problem = { id: "test-13", description: "Problem with some context", context: "This is a bit more context but still limited", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.confidence).toBeGreaterThan(0); }); it("should reduce confidence for highly constrained problems", async () => { const problem: Problem = { id: "test-14", description: "Highly constrained problem", context: "Problem with many constraints limiting solution space", constraints: ["constraint1", "constraint2", "constraint3", "constraint4"], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.confidence).toBeGreaterThan(0); }); }); describe("process - Error Handling", () => { it("should throw error for invalid problem (missing id)", async () => { const problem: any = { description: "Problem without ID", context: "Some context", }; await expect(processor.process(problem)).rejects.toThrow("Invalid problem"); }); it("should throw error for invalid problem (missing description)", async () => { const problem: any = { id: "test-15", context: "Some context", }; await expect(processor.process(problem)).rejects.toThrow("Invalid problem"); }); it("should throw error for null problem", async () => { await expect(processor.process(null as any)).rejects.toThrow("Invalid problem"); }); it("should return FAILED status when processing throws unexpected error", async () => { const problem: Problem = { id: "test-error", description: "Problem that will cause internal error", context: "Test context", constraints: [], goals: [], }; // Mock identifyPatterns to throw an error const originalIdentifyPatterns = (processor as any).identifyPatterns; (processor as any).identifyPatterns = () => { throw new Error("Unexpected processing error"); }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.FAILED); expect(result.confidence).toBe(0); expect(result.conclusion).toBe(""); expect(result.error).toBeDefined(); expect(result.error?.message).toContain("Unexpected processing error"); // Restore original method (processor as any).identifyPatterns = originalIdentifyPatterns; }); }); describe("process - Result Structure", () => { it("should return top 10 insights sorted by importance", async () => { const problem: Problem = { id: "test-16", description: "Complex problem with many patterns, connections, and themes", context: "Rich context with systemic patterns, cause-effect relationships, hidden dependencies, emergent properties, and meta-level themes", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.insights.length).toBeLessThanOrEqual(10); // Verify insights are sorted by importance for (let i = 1; i < result.insights.length; i++) { expect(result.insights[i - 1].importance).toBeGreaterThanOrEqual( result.insights[i].importance ); } }); it("should include processing time", async () => { const problem: Problem = { id: "test-17", description: "Test problem", context: "Test context", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.processingTime).toBeGreaterThan(0); }); }); describe("process - Holistic Perspective", () => { it("should generate holistic perspective with complex system assessment", async () => { const problem: Problem = { id: "test-holistic-complex", description: "Highly complex problem with many interconnected elements", context: "This is a very complex situation with multiple layers of interaction, numerous stakeholders, various constraints, and dynamic relationships that evolve over time", constraints: ["constraint1", "constraint2"], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect( result.reasoning.some((r) => r.includes("big picture") || r.includes("Big picture")) ).toBe(true); // Should mention constraints or boundaries const hasBoundaryReference = result.reasoning.some( (r) => r.includes("boundaries") || r.includes("constraint") || r.includes("operating within") ); expect(hasBoundaryReference).toBe(true); }); it("should generate holistic perspective for simpler interconnected systems", async () => { const problem: Problem = { id: "test-holistic-simple", description: "Interconnected problem", context: "Some context", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.includes("big picture"))).toBe(true); }); }); describe("process - Leverage Points", () => { it("should identify leverage points with high importance insights", async () => { const problem: Problem = { id: "test-leverage", description: "Problem with critical intervention points", context: "Multiple interconnected factors with various patterns, several connections, and emergent themes", constraints: [], goals: ["goal1", "goal2"], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.reasoning.some((r) => r.includes("leverage"))).toBe(true); }); it("should align leverage points with goals when present", async () => { const problem: Problem = { id: "test-leverage-goals", description: "Problem with clear goals", context: "Context with patterns and connections", constraints: [], goals: ["achieve outcome A", "improve metric B"], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify leverage points are identified in reasoning expect(result.reasoning.some((r) => r.toLowerCase().includes("leverage"))).toBe(true); }); }); describe("process - Conclusion Generation", () => { it("should generate conclusion for highly complex systems", async () => { const problem: Problem = { id: "test-conclusion-complex", description: "Very complex problem", context: "Rich context with multiple patterns, connections, themes, and integrative insights", constraints: [], goals: ["goal1"], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.conclusion).toContain("complex"); expect(result.conclusion).toContain("strategic"); }); it("should generate conclusion for moderately complex systems", async () => { const problem: Problem = { id: "test-conclusion-moderate", description: "Moderately complex problem", context: "Some patterns and connections", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.conclusion).toContain("system"); }); it("should generate conclusion for simpler interconnected systems", async () => { const problem: Problem = { id: "test-conclusion-simple", description: "Simple interconnected problem", context: "Basic context", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify conclusion contains "system" (can be "interconnected system" or "complex system") expect(result.conclusion).toContain("system"); }); it("should mention leverage points in conclusion when present", async () => { const problem: Problem = { id: "test-conclusion-leverage", description: "Problem with leverage points", context: "Multiple patterns, connections, themes creating high importance insights", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.conclusion).toContain("leverage"); }); }); describe("process - Additional Coverage for Uncovered Branches", () => { it("should add connection insight for affects/relates/influences keywords", async () => { const problem: Problem = { id: "test-connection-affects", description: "Factor X affects Y which relates to Z and influences outcome", context: "Multiple interconnected factors with various relationships", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify connection insight reasoning is added (covers line 75-76) expect(result.reasoning.some((r) => r.includes("Connection insight:"))).toBe(true); }); it("should add emergent insight reasoning for themes", async () => { const problem: Problem = { id: "test-emergent-theme", description: "System with emergent properties", context: "The whole exhibits behaviors that emerge from interactions", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify emergent insight reasoning is added expect(result.reasoning.some((r) => r.includes("Emergent insight:"))).toBe(true); }); it("should add integration reasoning for paradoxes", async () => { const problem: Problem = { id: "test-integration-paradox", description: "Problem with paradoxical elements", context: "Multiple patterns, connections, and themes with paradoxical tensions", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify integration reasoning is added (covers line 457-458) expect(result.reasoning.some((r) => r.includes("Integration:"))).toBe(true); }); it("should generate holistic perspective without constraints", async () => { const problem: Problem = { id: "test-holistic-no-constraints", description: "Simple problem", context: "Basic", // Very short context (< 150 chars) constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify holistic perspective is generated (covers line 447-448) // The holistic view should be in insights with "big picture" const holisticInsight = result.insights.find((i) => i.content.includes("big picture")); expect(holisticInsight).toBeDefined(); // With short context, should use "interconnected situation" or "complex adaptive system" expect( holisticInsight?.content.includes("interconnected situation") || holisticInsight?.content.includes("complex adaptive system") ).toBe(true); }); it("should include boundary details in holistic perspective with constraints", async () => { const problem: Problem = { id: "test-holistic-boundaries", description: "Complex system with defined boundaries", context: "Very rich context with multiple layers, stakeholders, and dynamic relationships that evolve", constraints: ["budget limit", "time constraint"], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify boundaries are mentioned in reasoning (covers line 551-554) expect(result.reasoning.some((r) => r.includes("boundaries"))).toBe(true); }); it("should include leverage point details in conclusion with multiple high-importance insights", async () => { const problem: Problem = { id: "test-conclusion-leverage-details", description: "Problem with multiple critical leverage points", context: "Rich context with systemic patterns, cause-effect relationships, hidden dependencies, emergent properties, meta-level themes, and integrative insights", constraints: [], goals: ["goal1"], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify leverage points are mentioned in conclusion (covers line 694-704) expect(result.conclusion).toContain("leverage"); expect(result.conclusion).toContain("strategic"); }); it("should apply context length penalty for very short context", async () => { const problem: Problem = { id: "test-confidence-short-context", description: "Problem with very short context", context: "Short", // Less than 20 chars constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify confidence is reduced for very short context (covers line 752-754) // Base 0.75 - 0.25 penalty = 0.5, but can get boosts from insights // So we just verify it's less than base confidence with good context expect(result.confidence).toBeLessThan(0.85); }); it("should apply context length penalty for limited context", async () => { const problem: Problem = { id: "test-confidence-limited-context", description: "Problem with limited context", context: "This is limited context text", // Between 20-50 chars constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify confidence is reduced for limited context // Base 0.75 - 0.15 penalty = 0.6, but can get boosts from insights // So we just verify it's less than base confidence with good context expect(result.confidence).toBeLessThan(0.9); }); it("should generate conclusion without leverage points when no high-importance insights", async () => { const problem: Problem = { id: "test-conclusion-no-leverage", description: "Simple problem", context: "Basic context", constraints: [], goals: [], }; const result = await processor.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); // Verify conclusion is generated without leverage points (covers line 684-694) expect(result.conclusion).toBeTruthy(); expect(result.conclusion).toContain("system"); }); }); }); describe("SyntheticReasoningStream", () => { let stream: SyntheticReasoningStream; beforeEach(() => { stream = new SyntheticReasoningStream(5000); }); describe("Constructor", () => { it("should initialize with correct properties", () => { expect(stream.id).toContain("synthetic-stream"); expect(stream.type).toBe(StreamType.SYNTHETIC); expect(stream.timeout).toBe(5000); expect(stream.processor).toBeInstanceOf(SyntheticStreamProcessor); }); it("should use default timeout when not specified", () => { const defaultStream = new SyntheticReasoningStream(); expect(defaultStream.timeout).toBe(10000); }); }); describe("process", () => { it("should process problem successfully", async () => { const problem: Problem = { id: "test-18", description: "Test problem for stream", context: "Test context with patterns and connections", constraints: [], goals: [], }; const result = await stream.process(problem); expect(result.status).toBe(StreamStatus.COMPLETED); expect(result.streamId).toContain("synthetic-"); expect(result.streamType).toBe(StreamType.SYNTHETIC); }); it("should throw error if already processing", async () => { const problem: Problem = { id: "test-19", description: "Test problem", context: "Test context", constraints: [], goals: [], }; // Start processing const promise1 = stream.process(problem); // Try to process again while first is still running await expect(stream.process(problem)).rejects.toThrow("already processing"); // Wait for first to complete await promise1; }); it("should handle timeout", async () => { const shortTimeoutStream = new SyntheticReasoningStream(10); // Very short timeout const problem: Problem = { id: "test-20", description: "Problem that will timeout", context: "Context", constraints: [], goals: [], }; // Mock processor to take longer than timeout vi.spyOn(shortTimeoutStream.processor, "process").mockImplementation( () => new Promise((resolve) => { setTimeout( () => resolve({ streamId: "test", streamType: StreamType.SYNTHETIC, conclusion: "Done", reasoning: [], insights: [], confidence: 0.8, processingTime: 100, status: StreamStatus.COMPLETED, }), 100 ); }) ); const result = await shortTimeoutStream.process(problem); expect(result.status).toBe(StreamStatus.TIMEOUT); expect(result.confidence).toBe(0.3); }); it("should handle cancellation after processing completes", async () => { const problem: Problem = { id: "test-21", description: "Test problem", context: "Test context", constraints: [], goals: [], }; // Start processing const processPromise = stream.process(problem); // Cancel immediately stream.cancel(); const result = await processPromise; expect(result.status).toBe(StreamStatus.CANCELLED); expect(result.confidence).toBe(0); }); it("should track progress during processing", async () => { const problem: Problem = { id: "test-22", description: "Test problem", context: "Test context", constraints: [], goals: [], }; const processPromise = stream.process(problem); // Wait a bit and check progress await new Promise((resolve) => setTimeout(resolve, 100)); const midProgress = stream.getProgress(); await processPromise; const finalProgress = stream.getProgress(); expect(midProgress).toBeGreaterThanOrEqual(0); expect(finalProgress).toBe(1.0); }); }); describe("getProgress", () => { it("should return 0 initially", () => { expect(stream.getProgress()).toBe(0); }); it("should return 1.0 after successful completion", async () => { const problem: Problem = { id: "test-23", description: "Test problem", context: "Test context", constraints: [], goals: [], }; await stream.process(problem); expect(stream.getProgress()).toBe(1.0); }); }); describe("cancel", () => { it("should cancel processing", async () => { const problem: Problem = { id: "test-24", description: "Test problem", context: "Test context", constraints: [], goals: [], }; const processPromise = stream.process(problem); stream.cancel(); const result = await processPromise; expect(result.status).toBe(StreamStatus.CANCELLED); }); it("should handle late cancellation after processing completes", async () => { const problem: Problem = { id: "test-late-cancel", description: "Test problem for late cancellation", context: "Test context", constraints: [], goals: [], }; // Mock processor to complete after a delay vi.spyOn(stream.processor, "process").mockImplementation( () => new Promise((resolve) => { setTimeout(() => { resolve({ streamId: "test", streamType: StreamType.SYNTHETIC, conclusion: "Completed", reasoning: ["Step 1", "Step 2"], insights: [ { content: "Test insight", source: StreamType.SYNTHETIC, confidence: 0.8, importance: 0.7, }, ], confidence: 0.8, processingTime: 50, status: StreamStatus.COMPLETED, }); }, 50); }) ); const processPromise = stream.process(problem); // Cancel immediately - this will set cancelled flag before processing completes stream.cancel(); const result = await processPromise; // Should be cancelled even if processing completed expect(result.status).toBe(StreamStatus.CANCELLED); expect(result.confidence).toBe(0); expect(result.conclusion).toBe(""); // Should preserve reasoning and insights from completed processing expect(result.reasoning).toBeDefined(); expect(result.insights).toBeDefined(); }); it("should be safe to call multiple times", () => { expect(() => { stream.cancel(); stream.cancel(); stream.cancel(); }).not.toThrow(); }); }); describe("error handling in processWithProgress", () => { it("should handle errors thrown during processing", async () => { const problem: Problem = { id: "test-error-processing", description: "Test problem that will cause error", context: "Test context", constraints: [], goals: [], }; // Mock processor to throw an error vi.spyOn(stream.processor, "process").mockRejectedValue( new Error("Processing failed unexpectedly") ); await expect(stream.process(problem)).rejects.toThrow("Processing failed unexpectedly"); }); }); });

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