@framers/agentos 0.1.113 → 0.1.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -5
- package/dist/api/AgentOS.d.ts +45 -12
- package/dist/api/AgentOS.d.ts.map +1 -1
- package/dist/api/AgentOS.js +225 -78
- package/dist/api/AgentOS.js.map +1 -1
- package/dist/api/AgentOSOrchestrator.d.ts +8 -0
- package/dist/api/AgentOSOrchestrator.d.ts.map +1 -1
- package/dist/api/AgentOSOrchestrator.js +350 -59
- package/dist/api/AgentOSOrchestrator.js.map +1 -1
- package/dist/api/StreamChunkEmitter.d.ts.map +1 -1
- package/dist/api/StreamChunkEmitter.js +2 -0
- package/dist/api/StreamChunkEmitter.js.map +1 -1
- package/dist/api/agency.d.ts.map +1 -1
- package/dist/api/agency.js +47 -1
- package/dist/api/agency.js.map +1 -1
- package/dist/api/agent.d.ts +18 -5
- package/dist/api/agent.d.ts.map +1 -1
- package/dist/api/agent.js +48 -9
- package/dist/api/agent.js.map +1 -1
- package/dist/api/agentExport.d.ts +202 -0
- package/dist/api/agentExport.d.ts.map +1 -0
- package/dist/api/agentExport.js +323 -0
- package/dist/api/agentExport.js.map +1 -0
- package/dist/api/editImage.d.ts +119 -0
- package/dist/api/editImage.d.ts.map +1 -0
- package/dist/api/editImage.js +150 -0
- package/dist/api/editImage.js.map +1 -0
- package/dist/api/embedText.d.ts +137 -0
- package/dist/api/embedText.d.ts.map +1 -0
- package/dist/api/embedText.js +229 -0
- package/dist/api/embedText.js.map +1 -0
- package/dist/api/externalToolRegistry.d.ts +44 -0
- package/dist/api/externalToolRegistry.d.ts.map +1 -0
- package/dist/api/externalToolRegistry.js +245 -0
- package/dist/api/externalToolRegistry.js.map +1 -0
- package/dist/api/generateImage.d.ts +1 -1
- package/dist/api/generateImage.d.ts.map +1 -1
- package/dist/api/generateImage.js +17 -13
- package/dist/api/generateImage.js.map +1 -1
- package/dist/api/generateObject.d.ts +185 -0
- package/dist/api/generateObject.d.ts.map +1 -0
- package/dist/api/generateObject.js +249 -0
- package/dist/api/generateObject.js.map +1 -0
- package/dist/api/generateText.d.ts +13 -3
- package/dist/api/generateText.d.ts.map +1 -1
- package/dist/api/generateText.js +20 -5
- package/dist/api/generateText.js.map +1 -1
- package/dist/api/interfaces/IAgentOS.d.ts +29 -1
- package/dist/api/interfaces/IAgentOS.d.ts.map +1 -1
- package/dist/api/model.d.ts +7 -7
- package/dist/api/model.d.ts.map +1 -1
- package/dist/api/model.js +22 -16
- package/dist/api/model.js.map +1 -1
- package/dist/api/processRequestWithExternalTools.d.ts +26 -0
- package/dist/api/processRequestWithExternalTools.d.ts.map +1 -0
- package/dist/api/processRequestWithExternalTools.js +52 -0
- package/dist/api/processRequestWithExternalTools.js.map +1 -0
- package/dist/api/processRequestWithRegisteredTools.d.ts +56 -0
- package/dist/api/processRequestWithRegisteredTools.d.ts.map +1 -0
- package/dist/api/processRequestWithRegisteredTools.js +125 -0
- package/dist/api/processRequestWithRegisteredTools.js.map +1 -0
- package/dist/api/provider-defaults.d.ts.map +1 -1
- package/dist/api/provider-defaults.js +28 -0
- package/dist/api/provider-defaults.js.map +1 -1
- package/dist/api/resumeExternalToolRequestWithRegisteredTools.d.ts +71 -0
- package/dist/api/resumeExternalToolRequestWithRegisteredTools.d.ts.map +1 -0
- package/dist/api/resumeExternalToolRequestWithRegisteredTools.js +159 -0
- package/dist/api/resumeExternalToolRequestWithRegisteredTools.js.map +1 -0
- package/dist/api/strategies/agentGraphBuilder.d.ts +170 -0
- package/dist/api/strategies/agentGraphBuilder.d.ts.map +1 -0
- package/dist/api/strategies/agentGraphBuilder.js +299 -0
- package/dist/api/strategies/agentGraphBuilder.js.map +1 -0
- package/dist/api/strategies/graphCompiler.d.ts +84 -0
- package/dist/api/strategies/graphCompiler.d.ts.map +1 -0
- package/dist/api/strategies/graphCompiler.js +617 -0
- package/dist/api/strategies/graphCompiler.js.map +1 -0
- package/dist/api/strategies/hierarchical.d.ts.map +1 -1
- package/dist/api/strategies/hierarchical.js +2 -1
- package/dist/api/strategies/hierarchical.js.map +1 -1
- package/dist/api/strategies/index.d.ts +3 -0
- package/dist/api/strategies/index.d.ts.map +1 -1
- package/dist/api/strategies/index.js +2 -0
- package/dist/api/strategies/index.js.map +1 -1
- package/dist/api/strategies/shared.d.ts +1 -1
- package/dist/api/strategies/shared.d.ts.map +1 -1
- package/dist/api/strategies/shared.js +3 -2
- package/dist/api/strategies/shared.js.map +1 -1
- package/dist/api/streamObject.d.ts +166 -0
- package/dist/api/streamObject.d.ts.map +1 -0
- package/dist/api/streamObject.js +268 -0
- package/dist/api/streamObject.js.map +1 -0
- package/dist/api/streamText.d.ts +1 -1
- package/dist/api/streamText.d.ts.map +1 -1
- package/dist/api/streamText.js +26 -8
- package/dist/api/streamText.js.map +1 -1
- package/dist/api/toolAdapter.d.ts +44 -8
- package/dist/api/toolAdapter.d.ts.map +1 -1
- package/dist/api/toolAdapter.js +224 -45
- package/dist/api/toolAdapter.js.map +1 -1
- package/dist/api/types/AgentOSExternalToolRequest.d.ts +35 -0
- package/dist/api/types/AgentOSExternalToolRequest.d.ts.map +1 -0
- package/dist/api/types/AgentOSExternalToolRequest.js +2 -0
- package/dist/api/types/AgentOSExternalToolRequest.js.map +1 -0
- package/dist/api/types/AgentOSResponse.d.ts +25 -0
- package/dist/api/types/AgentOSResponse.d.ts.map +1 -1
- package/dist/api/types/AgentOSResponse.js +20 -0
- package/dist/api/types/AgentOSResponse.js.map +1 -1
- package/dist/api/types/AgentOSToolResult.d.ts +11 -0
- package/dist/api/types/AgentOSToolResult.d.ts.map +1 -0
- package/dist/api/types/AgentOSToolResult.js +2 -0
- package/dist/api/types/AgentOSToolResult.js.map +1 -0
- package/dist/api/types.d.ts +28 -4
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/api/upscaleImage.d.ts +92 -0
- package/dist/api/upscaleImage.d.ts.map +1 -0
- package/dist/api/upscaleImage.js +133 -0
- package/dist/api/upscaleImage.js.map +1 -0
- package/dist/api/variateImage.d.ts +102 -0
- package/dist/api/variateImage.d.ts.map +1 -0
- package/dist/api/variateImage.js +154 -0
- package/dist/api/variateImage.js.map +1 -0
- package/dist/cognitive_substrate/GMI.d.ts +16 -2
- package/dist/cognitive_substrate/GMI.d.ts.map +1 -1
- package/dist/cognitive_substrate/GMI.js +188 -56
- package/dist/cognitive_substrate/GMI.js.map +1 -1
- package/dist/cognitive_substrate/IGMI.d.ts +10 -0
- package/dist/cognitive_substrate/IGMI.d.ts.map +1 -1
- package/dist/cognitive_substrate/IGMI.js.map +1 -1
- package/dist/config/AgentOSConfig.d.ts +19 -2
- package/dist/config/AgentOSConfig.d.ts.map +1 -1
- package/dist/config/AgentOSConfig.js +46 -29
- package/dist/config/AgentOSConfig.js.map +1 -1
- package/dist/core/guardrails/IGuardrailService.d.ts +1 -1
- package/dist/core/images/IImageProvider.d.ts +93 -0
- package/dist/core/images/IImageProvider.d.ts.map +1 -1
- package/dist/core/images/IImageProvider.js.map +1 -1
- package/dist/core/images/ImageOperationError.d.ts +52 -0
- package/dist/core/images/ImageOperationError.d.ts.map +1 -0
- package/dist/core/images/ImageOperationError.js +58 -0
- package/dist/core/images/ImageOperationError.js.map +1 -0
- package/dist/core/images/imageToBuffer.d.ts +41 -0
- package/dist/core/images/imageToBuffer.d.ts.map +1 -0
- package/dist/core/images/imageToBuffer.js +95 -0
- package/dist/core/images/imageToBuffer.js.map +1 -0
- package/dist/core/images/index.d.ts +4 -0
- package/dist/core/images/index.d.ts.map +1 -1
- package/dist/core/images/index.js +8 -0
- package/dist/core/images/index.js.map +1 -1
- package/dist/core/images/providers/FalImageProvider.d.ts +208 -0
- package/dist/core/images/providers/FalImageProvider.d.ts.map +1 -0
- package/dist/core/images/providers/FalImageProvider.js +301 -0
- package/dist/core/images/providers/FalImageProvider.js.map +1 -0
- package/dist/core/images/providers/FluxImageProvider.d.ts +197 -0
- package/dist/core/images/providers/FluxImageProvider.d.ts.map +1 -0
- package/dist/core/images/providers/FluxImageProvider.js +271 -0
- package/dist/core/images/providers/FluxImageProvider.js.map +1 -0
- package/dist/core/images/providers/OpenAIImageProvider.d.ts +33 -1
- package/dist/core/images/providers/OpenAIImageProvider.d.ts.map +1 -1
- package/dist/core/images/providers/OpenAIImageProvider.js +125 -0
- package/dist/core/images/providers/OpenAIImageProvider.js.map +1 -1
- package/dist/core/images/providers/ReplicateImageProvider.d.ts +26 -1
- package/dist/core/images/providers/ReplicateImageProvider.d.ts.map +1 -1
- package/dist/core/images/providers/ReplicateImageProvider.js +118 -0
- package/dist/core/images/providers/ReplicateImageProvider.js.map +1 -1
- package/dist/core/images/providers/StabilityImageProvider.d.ts +41 -1
- package/dist/core/images/providers/StabilityImageProvider.d.ts.map +1 -1
- package/dist/core/images/providers/StabilityImageProvider.js +180 -7
- package/dist/core/images/providers/StabilityImageProvider.js.map +1 -1
- package/dist/core/images/providers/StableDiffusionLocalProvider.d.ts +29 -1
- package/dist/core/images/providers/StableDiffusionLocalProvider.d.ts.map +1 -1
- package/dist/core/images/providers/StableDiffusionLocalProvider.js +124 -0
- package/dist/core/images/providers/StableDiffusionLocalProvider.js.map +1 -1
- package/dist/core/llm/IPromptEngine.d.ts +2 -2
- package/dist/core/llm/IPromptEngine.d.ts.map +1 -1
- package/dist/core/llm/IPromptEngine.js +2 -2
- package/dist/core/llm/IPromptEngine.js.map +1 -1
- package/dist/core/llm/providers/AIModelProviderManager.d.ts +7 -1
- package/dist/core/llm/providers/AIModelProviderManager.d.ts.map +1 -1
- package/dist/core/llm/providers/AIModelProviderManager.js +24 -0
- package/dist/core/llm/providers/AIModelProviderManager.js.map +1 -1
- package/dist/core/llm/providers/errors/AnthropicProviderError.d.ts +42 -0
- package/dist/core/llm/providers/errors/AnthropicProviderError.d.ts.map +1 -0
- package/dist/core/llm/providers/errors/AnthropicProviderError.js +45 -0
- package/dist/core/llm/providers/errors/AnthropicProviderError.js.map +1 -0
- package/dist/core/llm/providers/errors/GeminiProviderError.d.ts +45 -0
- package/dist/core/llm/providers/errors/GeminiProviderError.d.ts.map +1 -0
- package/dist/core/llm/providers/errors/GeminiProviderError.js +46 -0
- package/dist/core/llm/providers/errors/GeminiProviderError.js.map +1 -0
- package/dist/core/llm/providers/errors/OllamaProviderError.d.ts +1 -1
- package/dist/core/llm/providers/errors/OllamaProviderError.d.ts.map +1 -1
- package/dist/core/llm/providers/errors/OllamaProviderError.js +1 -1
- package/dist/core/llm/providers/errors/OllamaProviderError.js.map +1 -1
- package/dist/core/llm/providers/errors/OpenAIProviderError.d.ts +1 -1
- package/dist/core/llm/providers/errors/OpenAIProviderError.js +1 -1
- package/dist/core/llm/providers/errors/OpenRouterProviderError.d.ts +1 -1
- package/dist/core/llm/providers/errors/OpenRouterProviderError.js +1 -1
- package/dist/core/llm/providers/implementations/AnthropicProvider.d.ts +340 -0
- package/dist/core/llm/providers/implementations/AnthropicProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/AnthropicProvider.js +959 -0
- package/dist/core/llm/providers/implementations/AnthropicProvider.js.map +1 -0
- package/dist/core/llm/providers/implementations/GeminiProvider.d.ts +339 -0
- package/dist/core/llm/providers/implementations/GeminiProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/GeminiProvider.js +1004 -0
- package/dist/core/llm/providers/implementations/GeminiProvider.js.map +1 -0
- package/dist/core/llm/providers/implementations/GroqProvider.d.ts +105 -0
- package/dist/core/llm/providers/implementations/GroqProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/GroqProvider.js +134 -0
- package/dist/core/llm/providers/implementations/GroqProvider.js.map +1 -0
- package/dist/core/llm/providers/implementations/MistralProvider.d.ts +105 -0
- package/dist/core/llm/providers/implementations/MistralProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/MistralProvider.js +146 -0
- package/dist/core/llm/providers/implementations/MistralProvider.js.map +1 -0
- package/dist/core/llm/providers/implementations/TogetherProvider.d.ts +107 -0
- package/dist/core/llm/providers/implementations/TogetherProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/TogetherProvider.js +138 -0
- package/dist/core/llm/providers/implementations/TogetherProvider.js.map +1 -0
- package/dist/core/llm/providers/implementations/XAIProvider.d.ts +102 -0
- package/dist/core/llm/providers/implementations/XAIProvider.d.ts.map +1 -0
- package/dist/core/llm/providers/implementations/XAIProvider.js +123 -0
- package/dist/core/llm/providers/implementations/XAIProvider.js.map +1 -0
- package/dist/core/orchestration/AgentOrchestrator.d.ts.map +1 -1
- package/dist/core/orchestration/AgentOrchestrator.js +26 -5
- package/dist/core/orchestration/AgentOrchestrator.js.map +1 -1
- package/dist/core/tools/IToolOrchestrator.d.ts +2 -2
- package/dist/core/tools/IToolOrchestrator.d.ts.map +1 -1
- package/dist/core/tools/ToolExecutor.d.ts +3 -0
- package/dist/core/tools/ToolExecutor.d.ts.map +1 -1
- package/dist/core/tools/ToolExecutor.js +2 -1
- package/dist/core/tools/ToolExecutor.js.map +1 -1
- package/dist/core/tools/ToolOrchestrator.d.ts +7 -7
- package/dist/core/tools/ToolOrchestrator.d.ts.map +1 -1
- package/dist/core/tools/ToolOrchestrator.js +135 -36
- package/dist/core/tools/ToolOrchestrator.js.map +1 -1
- package/dist/core/tools/permissions/ToolPermissionManager.d.ts +6 -5
- package/dist/core/tools/permissions/ToolPermissionManager.d.ts.map +1 -1
- package/dist/core/tools/permissions/ToolPermissionManager.js +47 -21
- package/dist/core/tools/permissions/ToolPermissionManager.js.map +1 -1
- package/dist/core/vision/VisionPipeline.d.ts +437 -0
- package/dist/core/vision/VisionPipeline.d.ts.map +1 -0
- package/dist/core/vision/VisionPipeline.js +1113 -0
- package/dist/core/vision/VisionPipeline.js.map +1 -0
- package/dist/core/vision/index.d.ts +97 -0
- package/dist/core/vision/index.d.ts.map +1 -0
- package/dist/core/vision/index.js +182 -0
- package/dist/core/vision/index.js.map +1 -0
- package/dist/core/vision/providers/LLMVisionProvider.d.ts +135 -0
- package/dist/core/vision/providers/LLMVisionProvider.d.ts.map +1 -0
- package/dist/core/vision/providers/LLMVisionProvider.js +136 -0
- package/dist/core/vision/providers/LLMVisionProvider.js.map +1 -0
- package/dist/core/vision/providers/PipelineVisionProvider.d.ts +154 -0
- package/dist/core/vision/providers/PipelineVisionProvider.d.ts.map +1 -0
- package/dist/core/vision/providers/PipelineVisionProvider.js +160 -0
- package/dist/core/vision/providers/PipelineVisionProvider.js.map +1 -0
- package/dist/core/vision/types.d.ts +286 -0
- package/dist/core/vision/types.d.ts.map +1 -0
- package/dist/core/vision/types.js +24 -0
- package/dist/core/vision/types.js.map +1 -0
- package/dist/discovery/CapabilityDiscoveryEngine.d.ts +1 -1
- package/dist/discovery/CapabilityDiscoveryEngine.d.ts.map +1 -1
- package/dist/discovery/CapabilityDiscoveryEngine.js +1 -1
- package/dist/discovery/CapabilityDiscoveryEngine.js.map +1 -1
- package/dist/emergent/ComposableToolBuilder.d.ts +15 -4
- package/dist/emergent/ComposableToolBuilder.d.ts.map +1 -1
- package/dist/emergent/ComposableToolBuilder.js +29 -14
- package/dist/emergent/ComposableToolBuilder.js.map +1 -1
- package/dist/emergent/EmergentCapabilityEngine.d.ts +3 -3
- package/dist/emergent/EmergentCapabilityEngine.d.ts.map +1 -1
- package/dist/emergent/EmergentCapabilityEngine.js +15 -12
- package/dist/emergent/EmergentCapabilityEngine.js.map +1 -1
- package/dist/emergent/EmergentJudge.d.ts +20 -0
- package/dist/emergent/EmergentJudge.d.ts.map +1 -1
- package/dist/emergent/EmergentJudge.js +121 -26
- package/dist/emergent/EmergentJudge.js.map +1 -1
- package/dist/emergent/EmergentToolRegistry.d.ts +17 -0
- package/dist/emergent/EmergentToolRegistry.d.ts.map +1 -1
- package/dist/emergent/EmergentToolRegistry.js +26 -0
- package/dist/emergent/EmergentToolRegistry.js.map +1 -1
- package/dist/emergent/ForgeToolMetaTool.d.ts +1 -1
- package/dist/emergent/ForgeToolMetaTool.d.ts.map +1 -1
- package/dist/emergent/ForgeToolMetaTool.js +15 -2
- package/dist/emergent/ForgeToolMetaTool.js.map +1 -1
- package/dist/emergent/SandboxedToolForge.d.ts +2 -2
- package/dist/emergent/SandboxedToolForge.d.ts.map +1 -1
- package/dist/emergent/SandboxedToolForge.js +13 -23
- package/dist/emergent/SandboxedToolForge.js.map +1 -1
- package/dist/emergent/SkillExporter.d.ts +119 -0
- package/dist/emergent/SkillExporter.d.ts.map +1 -0
- package/dist/emergent/SkillExporter.js +344 -0
- package/dist/emergent/SkillExporter.js.map +1 -0
- package/dist/emergent/index.d.ts +1 -0
- package/dist/emergent/index.d.ts.map +1 -1
- package/dist/emergent/index.js +1 -0
- package/dist/emergent/index.js.map +1 -1
- package/dist/emergent/types.d.ts +4 -4
- package/dist/index.d.ts +30 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/memory/index.d.ts +10 -8
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/ingestion/DoclingLoader.d.ts +3 -3
- package/dist/memory/ingestion/DoclingLoader.d.ts.map +1 -1
- package/dist/memory/ingestion/DoclingLoader.js +12 -8
- package/dist/memory/ingestion/DoclingLoader.js.map +1 -1
- package/dist/memory/ingestion/FolderScanner.d.ts +7 -7
- package/dist/memory/ingestion/FolderScanner.d.ts.map +1 -1
- package/dist/memory/ingestion/FolderScanner.js +6 -6
- package/dist/memory/ingestion/FolderScanner.js.map +1 -1
- package/dist/memory/ingestion/LoaderRegistry.d.ts +8 -8
- package/dist/memory/ingestion/LoaderRegistry.d.ts.map +1 -1
- package/dist/memory/ingestion/LoaderRegistry.js +9 -11
- package/dist/memory/ingestion/LoaderRegistry.js.map +1 -1
- package/dist/memory/ingestion/MultimodalAggregator.d.ts +1 -1
- package/dist/memory/ingestion/MultimodalAggregator.js +1 -1
- package/dist/memory/ingestion/OcrPdfLoader.d.ts +2 -2
- package/dist/memory/ingestion/OcrPdfLoader.d.ts.map +1 -1
- package/dist/memory/ingestion/OcrPdfLoader.js +12 -8
- package/dist/memory/ingestion/OcrPdfLoader.js.map +1 -1
- package/dist/memory/ingestion/PdfLoader.d.ts +8 -8
- package/dist/memory/ingestion/PdfLoader.d.ts.map +1 -1
- package/dist/memory/ingestion/PdfLoader.js +13 -10
- package/dist/memory/ingestion/PdfLoader.js.map +1 -1
- package/dist/memory/io/MarkdownExporter.d.ts +1 -1
- package/dist/memory/io/MarkdownExporter.d.ts.map +1 -1
- package/dist/memory/io/MarkdownExporter.js +1 -1
- package/dist/memory/io/MarkdownExporter.js.map +1 -1
- package/dist/memory/tools/MemoryAddTool.d.ts +2 -2
- package/dist/memory/tools/MemoryAddTool.d.ts.map +1 -1
- package/dist/memory/tools/MemoryAddTool.js +8 -3
- package/dist/memory/tools/MemoryAddTool.js.map +1 -1
- package/dist/memory/tools/MemorySearchTool.d.ts +3 -3
- package/dist/memory/tools/MemorySearchTool.d.ts.map +1 -1
- package/dist/memory/tools/MemorySearchTool.js +11 -9
- package/dist/memory/tools/MemorySearchTool.js.map +1 -1
- package/dist/memory/tools/scopeContext.d.ts +11 -0
- package/dist/memory/tools/scopeContext.d.ts.map +1 -0
- package/dist/memory/tools/scopeContext.js +46 -0
- package/dist/memory/tools/scopeContext.js.map +1 -0
- package/dist/orchestration/builders/AgentGraph.d.ts +12 -11
- package/dist/orchestration/builders/AgentGraph.d.ts.map +1 -1
- package/dist/orchestration/builders/AgentGraph.js +12 -11
- package/dist/orchestration/builders/AgentGraph.js.map +1 -1
- package/dist/orchestration/builders/VoiceNodeBuilder.d.ts +2 -2
- package/dist/orchestration/builders/VoiceNodeBuilder.d.ts.map +1 -1
- package/dist/orchestration/builders/VoiceNodeBuilder.js +2 -2
- package/dist/orchestration/builders/VoiceNodeBuilder.js.map +1 -1
- package/dist/orchestration/builders/WorkflowBuilder.d.ts +1 -1
- package/dist/orchestration/builders/WorkflowBuilder.d.ts.map +1 -1
- package/dist/orchestration/builders/WorkflowBuilder.js +1 -1
- package/dist/orchestration/builders/WorkflowBuilder.js.map +1 -1
- package/dist/orchestration/checkpoint/InMemoryCheckpointStore.d.ts +7 -54
- package/dist/orchestration/checkpoint/InMemoryCheckpointStore.d.ts.map +1 -1
- package/dist/orchestration/checkpoint/InMemoryCheckpointStore.js +8 -56
- package/dist/orchestration/checkpoint/InMemoryCheckpointStore.js.map +1 -1
- package/dist/orchestration/events/GraphEvent.d.ts +12 -12
- package/dist/orchestration/events/GraphEvent.d.ts.map +1 -1
- package/dist/orchestration/events/GraphEvent.js.map +1 -1
- package/dist/orchestration/runtime/GraphRuntime.d.ts.map +1 -1
- package/dist/orchestration/runtime/GraphRuntime.js +151 -1
- package/dist/orchestration/runtime/GraphRuntime.js.map +1 -1
- package/dist/orchestration/runtime/LoopController.d.ts +3 -3
- package/dist/orchestration/runtime/LoopController.d.ts.map +1 -1
- package/dist/orchestration/runtime/LoopController.js.map +1 -1
- package/dist/orchestration/runtime/StateManager.d.ts +3 -3
- package/dist/orchestration/runtime/StateManager.js +3 -3
- package/dist/orchestration/runtime/VoiceNodeExecutor.d.ts +6 -6
- package/dist/orchestration/runtime/VoiceNodeExecutor.d.ts.map +1 -1
- package/dist/orchestration/runtime/VoiceNodeExecutor.js +27 -10
- package/dist/orchestration/runtime/VoiceNodeExecutor.js.map +1 -1
- package/dist/orchestration/runtime/VoiceTransportAdapter.d.ts +5 -5
- package/dist/orchestration/runtime/VoiceTransportAdapter.js +5 -5
- package/dist/orchestration/runtime/VoiceTurnCollector.d.ts +2 -2
- package/dist/orchestration/runtime/VoiceTurnCollector.js +2 -2
- package/dist/query-router/KeywordFallback.d.ts +70 -0
- package/dist/query-router/KeywordFallback.d.ts.map +1 -0
- package/dist/query-router/KeywordFallback.js +132 -0
- package/dist/query-router/KeywordFallback.js.map +1 -0
- package/dist/query-router/QueryClassifier.d.ts +140 -0
- package/dist/query-router/QueryClassifier.d.ts.map +1 -0
- package/dist/query-router/QueryClassifier.js +223 -0
- package/dist/query-router/QueryClassifier.js.map +1 -0
- package/dist/query-router/QueryDispatcher.d.ts +139 -0
- package/dist/query-router/QueryDispatcher.d.ts.map +1 -0
- package/dist/query-router/QueryDispatcher.js +297 -0
- package/dist/query-router/QueryDispatcher.js.map +1 -0
- package/dist/query-router/QueryGenerator.d.ts +184 -0
- package/dist/query-router/QueryGenerator.d.ts.map +1 -0
- package/dist/query-router/QueryGenerator.js +241 -0
- package/dist/query-router/QueryGenerator.js.map +1 -0
- package/dist/query-router/QueryRouter.d.ts +292 -0
- package/dist/query-router/QueryRouter.d.ts.map +1 -0
- package/dist/query-router/QueryRouter.js +803 -0
- package/dist/query-router/QueryRouter.js.map +1 -0
- package/dist/query-router/TopicExtractor.d.ts +73 -0
- package/dist/query-router/TopicExtractor.d.ts.map +1 -0
- package/dist/query-router/TopicExtractor.js +95 -0
- package/dist/query-router/TopicExtractor.js.map +1 -0
- package/dist/query-router/index.d.ts +40 -0
- package/dist/query-router/index.d.ts.map +1 -0
- package/dist/query-router/index.js +46 -0
- package/dist/query-router/index.js.map +1 -0
- package/dist/query-router/types.d.ts +508 -0
- package/dist/query-router/types.d.ts.map +1 -0
- package/dist/query-router/types.js +39 -0
- package/dist/query-router/types.js.map +1 -0
- package/dist/rag/index.d.ts +5 -0
- package/dist/rag/index.d.ts.map +1 -1
- package/dist/rag/index.js +7 -0
- package/dist/rag/index.js.map +1 -1
- package/dist/rag/multimodal/LLMVisionAdapter.d.ts +43 -0
- package/dist/rag/multimodal/LLMVisionAdapter.d.ts.map +1 -0
- package/dist/rag/multimodal/LLMVisionAdapter.js +46 -0
- package/dist/rag/multimodal/LLMVisionAdapter.js.map +1 -0
- package/dist/rag/multimodal/MultimodalIndexer.d.ts +244 -0
- package/dist/rag/multimodal/MultimodalIndexer.d.ts.map +1 -0
- package/dist/rag/multimodal/MultimodalIndexer.js +411 -0
- package/dist/rag/multimodal/MultimodalIndexer.js.map +1 -0
- package/dist/rag/multimodal/MultimodalMemoryBridge.d.ts +448 -0
- package/dist/rag/multimodal/MultimodalMemoryBridge.d.ts.map +1 -0
- package/dist/rag/multimodal/MultimodalMemoryBridge.js +941 -0
- package/dist/rag/multimodal/MultimodalMemoryBridge.js.map +1 -0
- package/dist/rag/multimodal/SpeechProviderAdapter.d.ts +139 -0
- package/dist/rag/multimodal/SpeechProviderAdapter.d.ts.map +1 -0
- package/dist/rag/multimodal/SpeechProviderAdapter.js +143 -0
- package/dist/rag/multimodal/SpeechProviderAdapter.js.map +1 -0
- package/dist/rag/multimodal/createMultimodalIndexerFromResolver.d.ts +172 -0
- package/dist/rag/multimodal/createMultimodalIndexerFromResolver.d.ts.map +1 -0
- package/dist/rag/multimodal/createMultimodalIndexerFromResolver.js +152 -0
- package/dist/rag/multimodal/createMultimodalIndexerFromResolver.js.map +1 -0
- package/dist/rag/multimodal/index.d.ts +44 -0
- package/dist/rag/multimodal/index.d.ts.map +1 -0
- package/dist/rag/multimodal/index.js +42 -0
- package/dist/rag/multimodal/index.js.map +1 -0
- package/dist/rag/multimodal/types.d.ts +276 -0
- package/dist/rag/multimodal/types.d.ts.map +1 -0
- package/dist/rag/multimodal/types.js +26 -0
- package/dist/rag/multimodal/types.js.map +1 -0
- package/dist/social-posting/SocialPostManager.d.ts +3 -3
- package/dist/social-posting/SocialPostManager.d.ts.map +1 -1
- package/dist/social-posting/SocialPostManager.js +3 -5
- package/dist/social-posting/SocialPostManager.js.map +1 -1
- package/dist/speech/FallbackProxy.d.ts +6 -6
- package/dist/speech/FallbackProxy.d.ts.map +1 -1
- package/dist/speech/FallbackProxy.js +3 -3
- package/dist/speech/FallbackProxy.js.map +1 -1
- package/dist/speech/SpeechProviderResolver.d.ts +8 -8
- package/dist/speech/SpeechProviderResolver.d.ts.map +1 -1
- package/dist/speech/SpeechProviderResolver.js +22 -11
- package/dist/speech/SpeechProviderResolver.js.map +1 -1
- package/dist/speech/SpeechRuntime.d.ts +1 -5
- package/dist/speech/SpeechRuntime.d.ts.map +1 -1
- package/dist/speech/SpeechRuntime.js +17 -9
- package/dist/speech/SpeechRuntime.js.map +1 -1
- package/dist/speech/providers/AssemblyAISTTProvider.d.ts +4 -4
- package/dist/speech/providers/AssemblyAISTTProvider.js +4 -4
- package/dist/speech/providers/AzureSpeechTTSProvider.d.ts +3 -3
- package/dist/speech/providers/AzureSpeechTTSProvider.js +2 -2
- package/dist/speech/providers/AzureSpeechTTSProvider.js.map +1 -1
- package/dist/speech/providers/BuiltInAdaptiveVadProvider.d.ts +9 -9
- package/dist/speech/providers/BuiltInAdaptiveVadProvider.d.ts.map +1 -1
- package/dist/speech/providers/BuiltInAdaptiveVadProvider.js +5 -5
- package/dist/speech/providers/BuiltInAdaptiveVadProvider.js.map +1 -1
- package/dist/speech/providers/DeepgramBatchSTTProvider.d.ts +2 -2
- package/dist/speech/providers/DeepgramBatchSTTProvider.js +2 -2
- package/dist/speech/providers/OpenAITextToSpeechProvider.d.ts +3 -3
- package/dist/speech/providers/OpenAITextToSpeechProvider.js +2 -2
- package/dist/speech/providers/OpenAIWhisperSpeechToTextProvider.d.ts +1 -1
- package/dist/speech/providers/OpenAIWhisperSpeechToTextProvider.d.ts.map +1 -1
- package/dist/speech/providers/OpenAIWhisperSpeechToTextProvider.js +1 -1
- package/dist/speech/providers/OpenAIWhisperSpeechToTextProvider.js.map +1 -1
- package/dist/voice/TelephonyStreamTransport.d.ts +6 -6
- package/dist/voice/TelephonyStreamTransport.d.ts.map +1 -1
- package/dist/voice/TelephonyStreamTransport.js +5 -5
- package/dist/voice/TelephonyStreamTransport.js.map +1 -1
- package/dist/voice-pipeline/AcousticEndpointDetector.d.ts +4 -4
- package/dist/voice-pipeline/AcousticEndpointDetector.d.ts.map +1 -1
- package/dist/voice-pipeline/AcousticEndpointDetector.js +4 -4
- package/dist/voice-pipeline/AcousticEndpointDetector.js.map +1 -1
- package/dist/voice-pipeline/HardCutBargeinHandler.d.ts +3 -3
- package/dist/voice-pipeline/HardCutBargeinHandler.js +3 -3
- package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts +3 -3
- package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts.map +1 -1
- package/dist/voice-pipeline/HeuristicEndpointDetector.js +3 -3
- package/dist/voice-pipeline/HeuristicEndpointDetector.js.map +1 -1
- package/dist/voice-pipeline/SoftFadeBargeinHandler.d.ts +5 -5
- package/dist/voice-pipeline/SoftFadeBargeinHandler.js +1 -1
- package/dist/voice-pipeline/VoiceInterruptError.d.ts +6 -6
- package/dist/voice-pipeline/VoiceInterruptError.d.ts.map +1 -1
- package/dist/voice-pipeline/VoiceInterruptError.js +4 -4
- package/dist/voice-pipeline/VoiceInterruptError.js.map +1 -1
- package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts +9 -9
- package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts.map +1 -1
- package/dist/voice-pipeline/VoicePipelineOrchestrator.js +8 -8
- package/dist/voice-pipeline/VoicePipelineOrchestrator.js.map +1 -1
- package/dist/voice-pipeline/WebRTCStreamTransport.d.ts +421 -0
- package/dist/voice-pipeline/WebRTCStreamTransport.d.ts.map +1 -0
- package/dist/voice-pipeline/WebRTCStreamTransport.js +573 -0
- package/dist/voice-pipeline/WebRTCStreamTransport.js.map +1 -0
- package/dist/voice-pipeline/WebSocketStreamTransport.d.ts +8 -8
- package/dist/voice-pipeline/WebSocketStreamTransport.js +5 -5
- package/dist/voice-pipeline/index.d.ts +1 -0
- package/dist/voice-pipeline/index.d.ts.map +1 -1
- package/dist/voice-pipeline/index.js +2 -0
- package/dist/voice-pipeline/index.js.map +1 -1
- package/dist/voice-pipeline/types.d.ts +43 -43
- package/dist/voice-pipeline/types.d.ts.map +1 -1
- package/package.json +19 -1
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview QueryRouter — main orchestrator that wires together the
|
|
3
|
+
* QueryClassifier, QueryDispatcher, and QueryGenerator into a complete
|
|
4
|
+
* classify -> dispatch -> generate pipeline.
|
|
5
|
+
*
|
|
6
|
+
* @module @framers/agentos/query-router/QueryRouter
|
|
7
|
+
*
|
|
8
|
+
* The QueryRouter is the top-level entry point for the intelligent query
|
|
9
|
+
* routing system. Given a user query and optional conversation history, it:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Classifies** the query into a complexity tier (T0-T3) using the
|
|
12
|
+
* {@link QueryClassifier}.
|
|
13
|
+
* 2. **Dispatches** the classified query to the tier-appropriate retrieval
|
|
14
|
+
* pipeline via the {@link QueryDispatcher}, which orchestrates vector
|
|
15
|
+
* search, graph expansion, reranking, and deep research.
|
|
16
|
+
* 3. **Generates** a grounded answer with citations via the
|
|
17
|
+
* {@link QueryGenerator}, using the retrieved context chunks.
|
|
18
|
+
*
|
|
19
|
+
* The router also handles:
|
|
20
|
+
* - Corpus loading from markdown files on disk
|
|
21
|
+
* - Real vector embedding via EmbeddingManager + VectorStoreManager (in-memory)
|
|
22
|
+
* - Keyword fallback retrieval when embeddings are unavailable
|
|
23
|
+
* - Event emission for full pipeline observability
|
|
24
|
+
* - Lifecycle hooks (onClassification, onRetrieval) for consumer integration
|
|
25
|
+
*
|
|
26
|
+
* Embedding pipeline: The `init()` method attempts to initialize an
|
|
27
|
+
* AIModelProviderManager, EmbeddingManager, and VectorStoreManager to enable
|
|
28
|
+
* real vector search. If any step fails (e.g., no API key configured), the
|
|
29
|
+
* router falls back gracefully to {@link KeywordFallback} for all retrieval.
|
|
30
|
+
*/
|
|
31
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
32
|
+
import { join, extname } from 'node:path';
|
|
33
|
+
import { QueryClassifier } from './QueryClassifier.js';
|
|
34
|
+
import { QueryDispatcher } from './QueryDispatcher.js';
|
|
35
|
+
import { QueryGenerator } from './QueryGenerator.js';
|
|
36
|
+
import { TopicExtractor } from './TopicExtractor.js';
|
|
37
|
+
import { KeywordFallback } from './KeywordFallback.js';
|
|
38
|
+
import { DEFAULT_QUERY_ROUTER_CONFIG } from './types.js';
|
|
39
|
+
/** Regex for splitting markdown by h1-h3 headings. */
|
|
40
|
+
const HEADING_REGEX = /^#{1,3}\s+(.+)/;
|
|
41
|
+
/** Maximum character length for a single corpus chunk. */
|
|
42
|
+
const MAX_CHUNK_CHARS = 6000;
|
|
43
|
+
/** Minimum content length for a chunk to be included. */
|
|
44
|
+
const MIN_CHUNK_CHARS = 20;
|
|
45
|
+
/** Supported markdown file extensions for corpus loading. */
|
|
46
|
+
const MARKDOWN_EXTENSIONS = new Set(['.md', '.mdx']);
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// QueryRouter
|
|
49
|
+
// ============================================================================
|
|
50
|
+
/**
|
|
51
|
+
* Main orchestrator that wires together the QueryClassifier, QueryDispatcher,
|
|
52
|
+
* and QueryGenerator into a complete classify -> dispatch -> generate pipeline.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const router = new QueryRouter({
|
|
57
|
+
* knowledgeCorpus: ['./docs'],
|
|
58
|
+
* generationModel: 'gpt-4o-mini',
|
|
59
|
+
* generationModelDeep: 'gpt-4o',
|
|
60
|
+
* generationProvider: 'openai',
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* await router.init();
|
|
64
|
+
* const result = await router.route('How does authentication work?');
|
|
65
|
+
* console.log(result.answer);
|
|
66
|
+
* console.log(result.sources);
|
|
67
|
+
*
|
|
68
|
+
* await router.close();
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export class QueryRouter {
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new QueryRouter instance.
|
|
74
|
+
*
|
|
75
|
+
* Merges user-supplied configuration over {@link QUERY_ROUTER_DEFAULTS}.
|
|
76
|
+
* The router is NOT ready to use until {@link init} is called.
|
|
77
|
+
*
|
|
78
|
+
* @param config - Partial configuration; `knowledgeCorpus` is required.
|
|
79
|
+
*/
|
|
80
|
+
constructor(config) {
|
|
81
|
+
/** Loaded corpus chunks from disk. */
|
|
82
|
+
this.corpus = [];
|
|
83
|
+
/** Topic entries extracted from the corpus. */
|
|
84
|
+
this.topics = [];
|
|
85
|
+
/** Keyword-based fallback search engine. */
|
|
86
|
+
this.keywordFallback = null;
|
|
87
|
+
/** Chain-of-thought query classifier. */
|
|
88
|
+
this.classifier = null;
|
|
89
|
+
/** Tier-routing dispatcher. */
|
|
90
|
+
this.dispatcher = null;
|
|
91
|
+
/** LLM answer generator. */
|
|
92
|
+
this.generator = null;
|
|
93
|
+
/** Accumulated lifecycle events for observability. */
|
|
94
|
+
this.events = [];
|
|
95
|
+
/** Whether init() has been called successfully. */
|
|
96
|
+
this.initialized = false;
|
|
97
|
+
/** Embedding manager for generating vector embeddings. Null if not available. */
|
|
98
|
+
this.embeddingManager = null;
|
|
99
|
+
/** Vector store manager for persisting and querying embeddings. Null if not available. */
|
|
100
|
+
this.vectorStoreManager = null;
|
|
101
|
+
/** AI model provider manager used by the embedding manager. Null if not available. */
|
|
102
|
+
this.providerManager = null;
|
|
103
|
+
/** Embedding dimension for the configured model. Zero if embeddings unavailable. */
|
|
104
|
+
this.embeddingDimension = 0;
|
|
105
|
+
/**
|
|
106
|
+
* The data source ID used for corpus embeddings in the vector store.
|
|
107
|
+
* Matches the collection name configured during init().
|
|
108
|
+
*/
|
|
109
|
+
this.corpusDataSourceId = 'query-router-corpus';
|
|
110
|
+
this.config = {
|
|
111
|
+
...DEFAULT_QUERY_ROUTER_CONFIG,
|
|
112
|
+
...config,
|
|
113
|
+
deepResearchEnabled: config.deepResearchEnabled ?? Boolean(process.env.SERPER_API_KEY),
|
|
114
|
+
availableTools: config.availableTools ?? [...DEFAULT_QUERY_ROUTER_CONFIG.availableTools],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// ==========================================================================
|
|
118
|
+
// PUBLIC API
|
|
119
|
+
// ==========================================================================
|
|
120
|
+
/**
|
|
121
|
+
* Initialise the router: load corpus from disk, extract topics, build
|
|
122
|
+
* keyword fallback index, embed the corpus into a vector store, and
|
|
123
|
+
* instantiate classifier/dispatcher/generator.
|
|
124
|
+
*
|
|
125
|
+
* Must be called before `classify()`, `retrieve()`, or `route()`.
|
|
126
|
+
*
|
|
127
|
+
* The embedding step uses real EmbeddingManager + VectorStoreManager when
|
|
128
|
+
* an LLM provider is available (e.g., OPENAI_API_KEY is set). If embedding
|
|
129
|
+
* initialisation fails for any reason, the router falls back gracefully to
|
|
130
|
+
* KeywordFallback for all retrieval.
|
|
131
|
+
*/
|
|
132
|
+
async init() {
|
|
133
|
+
// 1. Load corpus chunks from the configured knowledge directories
|
|
134
|
+
this.corpus = this.loadCorpus(this.config.knowledgeCorpus);
|
|
135
|
+
// 2. Extract topics for the classifier's system prompt
|
|
136
|
+
const topicExtractor = new TopicExtractor();
|
|
137
|
+
this.topics = topicExtractor.extract(this.corpus);
|
|
138
|
+
const topicList = topicExtractor.formatForPrompt(this.topics);
|
|
139
|
+
// 3. Build keyword fallback index
|
|
140
|
+
this.keywordFallback = new KeywordFallback(this.corpus);
|
|
141
|
+
// 4. Attempt to embed corpus chunks into a real vector store.
|
|
142
|
+
// This is wrapped in a try/catch so failure is non-fatal — keyword
|
|
143
|
+
// fallback will still work for all retrieval operations.
|
|
144
|
+
await this.embedCorpus();
|
|
145
|
+
// 5. Instantiate the classifier
|
|
146
|
+
this.classifier = new QueryClassifier({
|
|
147
|
+
model: this.config.classifierModel,
|
|
148
|
+
provider: this.config.classifierProvider,
|
|
149
|
+
confidenceThreshold: this.config.confidenceThreshold,
|
|
150
|
+
maxTier: this.config.maxTier,
|
|
151
|
+
topicList,
|
|
152
|
+
toolList: this.formatToolList(this.config.availableTools),
|
|
153
|
+
apiKey: this.config.apiKey,
|
|
154
|
+
baseUrl: this.config.baseUrl,
|
|
155
|
+
});
|
|
156
|
+
// 6. Instantiate the generator
|
|
157
|
+
this.generator = new QueryGenerator({
|
|
158
|
+
model: this.config.generationModel,
|
|
159
|
+
modelDeep: this.config.generationModelDeep,
|
|
160
|
+
provider: this.config.generationProvider,
|
|
161
|
+
apiKey: this.config.apiKey,
|
|
162
|
+
baseUrl: this.config.baseUrl,
|
|
163
|
+
maxContextTokens: this.config.maxContextTokens,
|
|
164
|
+
});
|
|
165
|
+
// 7. Instantiate the dispatcher with callback dependencies
|
|
166
|
+
this.dispatcher = new QueryDispatcher({
|
|
167
|
+
vectorSearch: (query, topK) => this.vectorSearch(query, topK),
|
|
168
|
+
graphExpand: (seeds) => this.graphExpand(seeds),
|
|
169
|
+
rerank: (query, chunks, topN) => this.rerank(query, chunks, topN),
|
|
170
|
+
deepResearch: (query, sources) => this.deepResearch(query, sources),
|
|
171
|
+
emit: (event) => this.emit(event),
|
|
172
|
+
graphEnabled: this.config.graphEnabled,
|
|
173
|
+
deepResearchEnabled: this.config.deepResearchEnabled,
|
|
174
|
+
});
|
|
175
|
+
this.initialized = true;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Classify a query into a complexity tier without dispatching or generating.
|
|
179
|
+
*
|
|
180
|
+
* Useful when consumers want to inspect the classification before deciding
|
|
181
|
+
* whether to proceed with the full pipeline.
|
|
182
|
+
*
|
|
183
|
+
* @param query - The user's natural-language query.
|
|
184
|
+
* @param conversationHistory - Optional recent conversation messages.
|
|
185
|
+
* @returns The classification result with tier, confidence, and reasoning.
|
|
186
|
+
* @throws If the router has not been initialised via {@link init}.
|
|
187
|
+
*/
|
|
188
|
+
async classify(query, conversationHistory) {
|
|
189
|
+
this.ensureInitialized();
|
|
190
|
+
const start = Date.now();
|
|
191
|
+
this.emit({
|
|
192
|
+
type: 'classify:start',
|
|
193
|
+
query,
|
|
194
|
+
timestamp: start,
|
|
195
|
+
});
|
|
196
|
+
const trimmedHistory = conversationHistory?.slice(-this.config.conversationWindowSize);
|
|
197
|
+
const result = await this.classifier.classify(query, trimmedHistory);
|
|
198
|
+
if (result.reasoning.startsWith('Classification failed;')) {
|
|
199
|
+
this.emit({
|
|
200
|
+
type: 'classify:error',
|
|
201
|
+
error: new Error(result.reasoning),
|
|
202
|
+
timestamp: Date.now(),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
this.emit({
|
|
206
|
+
type: 'classify:complete',
|
|
207
|
+
result,
|
|
208
|
+
durationMs: Date.now() - start,
|
|
209
|
+
timestamp: Date.now(),
|
|
210
|
+
});
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Retrieve context at a specific tier, bypassing the classifier.
|
|
215
|
+
*
|
|
216
|
+
* Useful when the caller already knows the appropriate retrieval depth
|
|
217
|
+
* and wants to skip classification overhead.
|
|
218
|
+
*
|
|
219
|
+
* @param query - The user's natural-language query.
|
|
220
|
+
* @param tier - The complexity tier to retrieve at (0-3).
|
|
221
|
+
* @returns The retrieval result with chunks and optional graph/research data.
|
|
222
|
+
* @throws If the router has not been initialised via {@link init}.
|
|
223
|
+
*/
|
|
224
|
+
async retrieve(query, tier) {
|
|
225
|
+
this.ensureInitialized();
|
|
226
|
+
return this.dispatcher.dispatch(query, tier);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Full end-to-end pipeline: classify -> dispatch -> generate.
|
|
230
|
+
*
|
|
231
|
+
* This is the primary method for answering user queries. It:
|
|
232
|
+
* 1. Classifies the query to determine retrieval depth.
|
|
233
|
+
* 2. Dispatches retrieval at the classified tier.
|
|
234
|
+
* 3. Generates a grounded answer from the retrieved context.
|
|
235
|
+
* 4. Emits lifecycle events throughout for observability.
|
|
236
|
+
*
|
|
237
|
+
* @param query - The user's natural-language query.
|
|
238
|
+
* @param conversationHistory - Optional recent conversation messages.
|
|
239
|
+
* @returns The final query result with answer, classification, sources, and timing.
|
|
240
|
+
* @throws If the router has not been initialised via {@link init}.
|
|
241
|
+
*/
|
|
242
|
+
async route(query, conversationHistory) {
|
|
243
|
+
this.ensureInitialized();
|
|
244
|
+
const routeStart = Date.now();
|
|
245
|
+
// --- Phase 1: Classification ---
|
|
246
|
+
const classification = await this.classify(query, conversationHistory);
|
|
247
|
+
// Fire the onClassification hook if configured
|
|
248
|
+
if (this.config.onClassification) {
|
|
249
|
+
this.config.onClassification(classification);
|
|
250
|
+
}
|
|
251
|
+
// --- Phase 2: Retrieval ---
|
|
252
|
+
const retrievalEventStart = this.events.length;
|
|
253
|
+
const retrieval = await this.dispatcher.dispatch(query, classification.tier, classification.suggestedSources);
|
|
254
|
+
const retrievalEvents = this.events.slice(retrievalEventStart);
|
|
255
|
+
const fallbacksUsed = this.collectFallbacks(classification, retrievalEvents);
|
|
256
|
+
const tiersUsed = this.collectTiersUsed(classification, fallbacksUsed);
|
|
257
|
+
// Fire the onRetrieval hook if configured
|
|
258
|
+
if (this.config.onRetrieval) {
|
|
259
|
+
this.config.onRetrieval(retrieval);
|
|
260
|
+
}
|
|
261
|
+
// --- Phase 3: Generation ---
|
|
262
|
+
this.emit({
|
|
263
|
+
type: 'generate:start',
|
|
264
|
+
contextChunkCount: retrieval.chunks.length,
|
|
265
|
+
timestamp: Date.now(),
|
|
266
|
+
});
|
|
267
|
+
const generateResult = await this.generator.generate(query, classification.tier, retrieval.chunks, retrieval.researchSynthesis);
|
|
268
|
+
// Build source citations from the retrieved chunks
|
|
269
|
+
const sources = retrieval.chunks.map((chunk) => ({
|
|
270
|
+
path: chunk.sourcePath,
|
|
271
|
+
heading: chunk.heading,
|
|
272
|
+
relevanceScore: chunk.relevanceScore,
|
|
273
|
+
matchType: chunk.matchType,
|
|
274
|
+
}));
|
|
275
|
+
this.emit({
|
|
276
|
+
type: 'generate:complete',
|
|
277
|
+
answerLength: generateResult.answer.length,
|
|
278
|
+
citationCount: sources.length,
|
|
279
|
+
durationMs: Date.now() - routeStart,
|
|
280
|
+
timestamp: Date.now(),
|
|
281
|
+
});
|
|
282
|
+
// --- Assemble final result ---
|
|
283
|
+
const totalDuration = Date.now() - routeStart;
|
|
284
|
+
const result = {
|
|
285
|
+
answer: generateResult.answer,
|
|
286
|
+
classification,
|
|
287
|
+
sources,
|
|
288
|
+
durationMs: totalDuration,
|
|
289
|
+
tiersUsed,
|
|
290
|
+
fallbacksUsed,
|
|
291
|
+
};
|
|
292
|
+
this.emit({
|
|
293
|
+
type: 'route:complete',
|
|
294
|
+
result,
|
|
295
|
+
durationMs: totalDuration,
|
|
296
|
+
timestamp: Date.now(),
|
|
297
|
+
});
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Tear down resources and release references.
|
|
302
|
+
*
|
|
303
|
+
* Shuts down embedding and vector store managers if they were initialised,
|
|
304
|
+
* then nulls out all component references. Safe to call multiple times.
|
|
305
|
+
* After close(), the router must be re-initialised via {@link init} before
|
|
306
|
+
* further use.
|
|
307
|
+
*/
|
|
308
|
+
async close() {
|
|
309
|
+
// Shut down RAG modules if they were initialised
|
|
310
|
+
try {
|
|
311
|
+
if (this.embeddingManager && typeof this.embeddingManager.shutdown === 'function') {
|
|
312
|
+
await this.embeddingManager.shutdown();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
catch { /* best-effort cleanup */ }
|
|
316
|
+
try {
|
|
317
|
+
if (this.vectorStoreManager) {
|
|
318
|
+
await this.vectorStoreManager.shutdownAllProviders();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch { /* best-effort cleanup */ }
|
|
322
|
+
try {
|
|
323
|
+
if (this.providerManager) {
|
|
324
|
+
await this.providerManager.shutdown();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
catch { /* best-effort cleanup */ }
|
|
328
|
+
this.embeddingManager = null;
|
|
329
|
+
this.vectorStoreManager = null;
|
|
330
|
+
this.providerManager = null;
|
|
331
|
+
this.embeddingDimension = 0;
|
|
332
|
+
this.classifier = null;
|
|
333
|
+
this.dispatcher = null;
|
|
334
|
+
this.generator = null;
|
|
335
|
+
this.keywordFallback = null;
|
|
336
|
+
this.corpus = [];
|
|
337
|
+
this.topics = [];
|
|
338
|
+
this.events = [];
|
|
339
|
+
this.initialized = false;
|
|
340
|
+
}
|
|
341
|
+
// ==========================================================================
|
|
342
|
+
// PRIVATE — Corpus loading
|
|
343
|
+
// ==========================================================================
|
|
344
|
+
/**
|
|
345
|
+
* Load and chunk markdown files from the configured corpus directories.
|
|
346
|
+
*
|
|
347
|
+
* Recursively walks each directory, reads .md and .mdx files, and splits
|
|
348
|
+
* their content by h1-h3 headings. Each heading section becomes a
|
|
349
|
+
* CorpusChunk (capped at {@link MAX_CHUNK_CHARS} characters, minimum
|
|
350
|
+
* {@link MIN_CHUNK_CHARS} to filter out trivially small sections).
|
|
351
|
+
*
|
|
352
|
+
* @param paths - Array of directory paths to scan for markdown files.
|
|
353
|
+
* @returns Array of CorpusChunk objects ready for indexing.
|
|
354
|
+
*/
|
|
355
|
+
loadCorpus(paths) {
|
|
356
|
+
const chunks = [];
|
|
357
|
+
let chunkIndex = 0;
|
|
358
|
+
for (const dirPath of paths) {
|
|
359
|
+
if (!existsSync(dirPath)) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
this.walkDir(dirPath, (filePath) => {
|
|
363
|
+
const ext = extname(filePath);
|
|
364
|
+
if (!MARKDOWN_EXTENSIONS.has(ext)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
369
|
+
const sections = this.splitByHeadings(content, filePath);
|
|
370
|
+
for (const section of sections) {
|
|
371
|
+
if (section.content.length < MIN_CHUNK_CHARS) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
chunks.push({
|
|
375
|
+
id: `chunk_${chunkIndex++}`,
|
|
376
|
+
heading: section.heading,
|
|
377
|
+
content: section.content.slice(0, MAX_CHUNK_CHARS),
|
|
378
|
+
sourcePath: filePath,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// Skip unreadable files gracefully
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
return chunks;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Recursively walk a directory tree, invoking a callback for each file.
|
|
391
|
+
*
|
|
392
|
+
* @param dir - The directory to walk.
|
|
393
|
+
* @param callback - Function called with the absolute path of each file.
|
|
394
|
+
*/
|
|
395
|
+
walkDir(dir, callback) {
|
|
396
|
+
try {
|
|
397
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
398
|
+
for (const entry of entries) {
|
|
399
|
+
const fullPath = join(dir, entry.name);
|
|
400
|
+
if (entry.isDirectory()) {
|
|
401
|
+
this.walkDir(fullPath, callback);
|
|
402
|
+
}
|
|
403
|
+
else if (entry.isFile()) {
|
|
404
|
+
callback(fullPath);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// Skip inaccessible directories gracefully
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Split markdown content into sections by h1-h3 headings.
|
|
414
|
+
*
|
|
415
|
+
* Each section captures the heading text and the content between it and
|
|
416
|
+
* the next heading (or end of file). Content before the first heading is
|
|
417
|
+
* assigned a heading of "(intro)".
|
|
418
|
+
*
|
|
419
|
+
* @param content - The raw markdown file content.
|
|
420
|
+
* @param sourcePath - File path (used for the section's sourcePath field).
|
|
421
|
+
* @returns Array of sections with heading and content fields.
|
|
422
|
+
*/
|
|
423
|
+
splitByHeadings(content, sourcePath) {
|
|
424
|
+
const lines = content.split('\n');
|
|
425
|
+
const sections = [];
|
|
426
|
+
let currentHeading = '(intro)';
|
|
427
|
+
let currentLines = [];
|
|
428
|
+
for (const line of lines) {
|
|
429
|
+
const match = line.match(HEADING_REGEX);
|
|
430
|
+
if (match) {
|
|
431
|
+
// Flush the previous section
|
|
432
|
+
if (currentLines.length > 0) {
|
|
433
|
+
sections.push({
|
|
434
|
+
heading: currentHeading,
|
|
435
|
+
content: currentLines.join('\n').trim(),
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
currentHeading = match[1].trim();
|
|
439
|
+
currentLines = [];
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
currentLines.push(line);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
// Flush the final section
|
|
446
|
+
if (currentLines.length > 0) {
|
|
447
|
+
sections.push({
|
|
448
|
+
heading: currentHeading,
|
|
449
|
+
content: currentLines.join('\n').trim(),
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
return sections;
|
|
453
|
+
}
|
|
454
|
+
// ==========================================================================
|
|
455
|
+
// PRIVATE — Corpus embedding
|
|
456
|
+
// ==========================================================================
|
|
457
|
+
/**
|
|
458
|
+
* Embed all loaded corpus chunks into the vector store using real
|
|
459
|
+
* EmbeddingManager and VectorStoreManager instances.
|
|
460
|
+
*
|
|
461
|
+
* The method dynamically imports the RAG modules to keep them optional —
|
|
462
|
+
* if the imports fail or initialisation fails (e.g., no API key), the error
|
|
463
|
+
* is caught and logged as a warning. The router will continue to function
|
|
464
|
+
* using the KeywordFallback engine for all retrieval.
|
|
465
|
+
*
|
|
466
|
+
* Steps:
|
|
467
|
+
* 1. Dynamic-import AIModelProviderManager, EmbeddingManager, VectorStoreManager
|
|
468
|
+
* 2. Initialise the provider manager with the configured embedding provider
|
|
469
|
+
* 3. Initialise the embedding manager with the configured model
|
|
470
|
+
* 4. Initialise the vector store manager with an in-memory provider
|
|
471
|
+
* 5. Create a collection with the correct dimension
|
|
472
|
+
* 6. Embed all corpus chunks in batches of 50
|
|
473
|
+
* 7. Upsert the resulting VectorDocuments into the vector store
|
|
474
|
+
* 8. Cache embeddings on CorpusChunk.embedding for potential reuse
|
|
475
|
+
*/
|
|
476
|
+
async embedCorpus() {
|
|
477
|
+
if (this.corpus.length === 0) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
// Quick check: bail out early if there's obviously no API key configured.
|
|
481
|
+
// This avoids the overhead of dynamic imports and provider initialization
|
|
482
|
+
// in test environments and when no embedding provider is available.
|
|
483
|
+
const apiKey = this.config.apiKey || process.env.OPENAI_API_KEY || '';
|
|
484
|
+
if (!apiKey) {
|
|
485
|
+
console.debug('[QueryRouter] No embedding API key configured; skipping vector store embedding (keyword fallback active).');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
// --- Dynamic imports to keep RAG modules optional ---
|
|
490
|
+
const [{ AIModelProviderManager: AIModelProviderManagerClass }, { EmbeddingManager: EmbeddingManagerClass }, { VectorStoreManager: VectorStoreManagerClass },] = await Promise.all([
|
|
491
|
+
import('../core/llm/providers/AIModelProviderManager.js'),
|
|
492
|
+
import('../rag/EmbeddingManager.js'),
|
|
493
|
+
import('../rag/VectorStoreManager.js'),
|
|
494
|
+
]);
|
|
495
|
+
// --- 1. Initialise the AI model provider manager ---
|
|
496
|
+
const pm = new AIModelProviderManagerClass();
|
|
497
|
+
await pm.initialize({
|
|
498
|
+
providers: [
|
|
499
|
+
{
|
|
500
|
+
providerId: this.config.embeddingProvider,
|
|
501
|
+
enabled: true,
|
|
502
|
+
config: {
|
|
503
|
+
apiKey: this.config.apiKey || process.env.OPENAI_API_KEY || '',
|
|
504
|
+
...(this.config.baseUrl ? { baseUrl: this.config.baseUrl } : {}),
|
|
505
|
+
},
|
|
506
|
+
isDefault: true,
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
});
|
|
510
|
+
this.providerManager = pm;
|
|
511
|
+
// --- 2. Initialise the embedding manager ---
|
|
512
|
+
const em = new EmbeddingManagerClass();
|
|
513
|
+
const embeddingModelId = this.config.embeddingModel;
|
|
514
|
+
const embeddingProviderId = this.config.embeddingProvider;
|
|
515
|
+
// Determine dimension: use a known dimension for common models, or
|
|
516
|
+
// try to derive it by generating a single test embedding.
|
|
517
|
+
let dimension = this.getKnownDimension(embeddingModelId);
|
|
518
|
+
await em.initialize({
|
|
519
|
+
embeddingModels: [
|
|
520
|
+
{
|
|
521
|
+
modelId: embeddingModelId,
|
|
522
|
+
providerId: embeddingProviderId,
|
|
523
|
+
dimension: dimension || 1536, // initial guess; corrected below if needed
|
|
524
|
+
isDefault: true,
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
defaultModelId: embeddingModelId,
|
|
528
|
+
defaultBatchSize: 50,
|
|
529
|
+
}, pm);
|
|
530
|
+
this.embeddingManager = em;
|
|
531
|
+
// If dimension was unknown, generate a probe embedding to discover it
|
|
532
|
+
if (!dimension) {
|
|
533
|
+
const probe = await em.generateEmbeddings({ texts: ['dimension probe'] });
|
|
534
|
+
if (probe.embeddings.length > 0 && probe.embeddings[0].length > 0) {
|
|
535
|
+
dimension = probe.embeddings[0].length;
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
dimension = 1536; // safe fallback for OpenAI models
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
this.embeddingDimension = dimension;
|
|
542
|
+
// --- 3. Initialise the vector store manager (in-memory) ---
|
|
543
|
+
const vsm = new VectorStoreManagerClass();
|
|
544
|
+
const collectionName = this.corpusDataSourceId;
|
|
545
|
+
await vsm.initialize({
|
|
546
|
+
managerId: 'query-router-vsm',
|
|
547
|
+
providers: [{ id: 'mem', type: 'in_memory' }],
|
|
548
|
+
defaultProviderId: 'mem',
|
|
549
|
+
}, [
|
|
550
|
+
{
|
|
551
|
+
dataSourceId: collectionName,
|
|
552
|
+
displayName: 'QueryRouter Corpus',
|
|
553
|
+
vectorStoreProviderId: 'mem',
|
|
554
|
+
actualNameInProvider: collectionName,
|
|
555
|
+
embeddingDimension: dimension,
|
|
556
|
+
},
|
|
557
|
+
]);
|
|
558
|
+
this.vectorStoreManager = vsm;
|
|
559
|
+
// --- 4. Create the collection ---
|
|
560
|
+
const { store, collectionName: resolvedName } = await vsm.getStoreForDataSource(collectionName);
|
|
561
|
+
if (typeof store.createCollection === 'function') {
|
|
562
|
+
await store.createCollection(resolvedName, dimension);
|
|
563
|
+
}
|
|
564
|
+
// --- 5. Embed corpus chunks in batches of 50 ---
|
|
565
|
+
const BATCH_SIZE = 50;
|
|
566
|
+
const allDocuments = [];
|
|
567
|
+
for (let i = 0; i < this.corpus.length; i += BATCH_SIZE) {
|
|
568
|
+
const batch = this.corpus.slice(i, i + BATCH_SIZE);
|
|
569
|
+
const texts = batch.map((c) => c.content);
|
|
570
|
+
const result = await em.generateEmbeddings({ texts });
|
|
571
|
+
for (let j = 0; j < batch.length; j++) {
|
|
572
|
+
const embedding = result.embeddings[j];
|
|
573
|
+
if (!embedding || embedding.length === 0) {
|
|
574
|
+
continue; // skip chunks that failed to embed
|
|
575
|
+
}
|
|
576
|
+
// Cache embedding on the CorpusChunk for potential later reuse
|
|
577
|
+
batch[j].embedding = embedding;
|
|
578
|
+
allDocuments.push({
|
|
579
|
+
id: batch[j].id,
|
|
580
|
+
embedding,
|
|
581
|
+
textContent: batch[j].content,
|
|
582
|
+
metadata: {
|
|
583
|
+
heading: batch[j].heading,
|
|
584
|
+
sourcePath: batch[j].sourcePath,
|
|
585
|
+
},
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// --- 6. Upsert into vector store ---
|
|
590
|
+
if (allDocuments.length > 0) {
|
|
591
|
+
await store.upsert(resolvedName, allDocuments);
|
|
592
|
+
}
|
|
593
|
+
console.log(`[QueryRouter] Embedded ${allDocuments.length} chunks into vector store (dim=${dimension})`);
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
// Non-fatal: warn and continue — keyword fallback still works
|
|
597
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
598
|
+
console.warn(`[QueryRouter] Embedding initialisation failed, falling back to keyword search: ${message}`);
|
|
599
|
+
// Clean up any partial state
|
|
600
|
+
this.embeddingManager = null;
|
|
601
|
+
this.vectorStoreManager = null;
|
|
602
|
+
this.providerManager = null;
|
|
603
|
+
this.embeddingDimension = 0;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Return a known embedding dimension for common models.
|
|
608
|
+
*
|
|
609
|
+
* This avoids an extra API call when the dimension can be statically
|
|
610
|
+
* determined from the model identifier.
|
|
611
|
+
*
|
|
612
|
+
* @param modelId - The embedding model identifier.
|
|
613
|
+
* @returns The known dimension, or 0 if unknown.
|
|
614
|
+
*/
|
|
615
|
+
getKnownDimension(modelId) {
|
|
616
|
+
const KNOWN_DIMENSIONS = {
|
|
617
|
+
'text-embedding-3-small': 1536,
|
|
618
|
+
'text-embedding-3-large': 3072,
|
|
619
|
+
'text-embedding-ada-002': 1536,
|
|
620
|
+
};
|
|
621
|
+
return KNOWN_DIMENSIONS[modelId] ?? 0;
|
|
622
|
+
}
|
|
623
|
+
// ==========================================================================
|
|
624
|
+
// PRIVATE — Retrieval callbacks (injected into QueryDispatcher)
|
|
625
|
+
// ==========================================================================
|
|
626
|
+
/**
|
|
627
|
+
* Vector search callback for the dispatcher.
|
|
628
|
+
*
|
|
629
|
+
* When the EmbeddingManager and VectorStoreManager are available, this method
|
|
630
|
+
* embeds the query, queries the vector store, and maps the results to
|
|
631
|
+
* RetrievedChunk objects. If the RAG modules are not available (e.g., embedding
|
|
632
|
+
* init failed), it falls back to the KeywordFallback engine and emits a
|
|
633
|
+
* retrieve:fallback event.
|
|
634
|
+
*
|
|
635
|
+
* @param query - The user's query string.
|
|
636
|
+
* @param topK - Maximum number of chunks to return.
|
|
637
|
+
* @returns Promise resolving to an array of matched chunks.
|
|
638
|
+
*/
|
|
639
|
+
async vectorSearch(query, topK) {
|
|
640
|
+
// --- Real vector search when RAG modules are available ---
|
|
641
|
+
if (this.embeddingManager && this.vectorStoreManager) {
|
|
642
|
+
try {
|
|
643
|
+
// Embed the query
|
|
644
|
+
const queryResult = await this.embeddingManager.generateEmbeddings({
|
|
645
|
+
texts: [query],
|
|
646
|
+
});
|
|
647
|
+
const queryEmbedding = queryResult.embeddings[0];
|
|
648
|
+
if (!queryEmbedding || queryEmbedding.length === 0) {
|
|
649
|
+
// Embedding failed for the query — fall through to keyword fallback
|
|
650
|
+
throw new Error('Query embedding returned empty vector');
|
|
651
|
+
}
|
|
652
|
+
// Query the vector store
|
|
653
|
+
const { store, collectionName } = await this.vectorStoreManager.getStoreForDataSource(this.corpusDataSourceId);
|
|
654
|
+
const searchResults = await store.query(collectionName, queryEmbedding, {
|
|
655
|
+
topK,
|
|
656
|
+
includeTextContent: true,
|
|
657
|
+
includeMetadata: true,
|
|
658
|
+
});
|
|
659
|
+
// Map retrieved vector documents to RetrievedChunk[]
|
|
660
|
+
return searchResults.documents.map((doc) => ({
|
|
661
|
+
id: doc.id,
|
|
662
|
+
content: doc.textContent ?? '',
|
|
663
|
+
heading: doc.metadata?.heading ?? '',
|
|
664
|
+
sourcePath: doc.metadata?.sourcePath ?? '',
|
|
665
|
+
relevanceScore: doc.similarityScore,
|
|
666
|
+
matchType: 'vector',
|
|
667
|
+
}));
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
// On any error during vector search, fall back to keyword search
|
|
671
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
672
|
+
console.warn(`[QueryRouter] Vector search failed, falling back to keyword search: ${message}`);
|
|
673
|
+
this.emit({
|
|
674
|
+
type: 'retrieve:fallback',
|
|
675
|
+
strategy: 'keyword-fallback',
|
|
676
|
+
reason: `Vector search error: ${message}`,
|
|
677
|
+
timestamp: Date.now(),
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
// RAG modules not available — emit a fallback event
|
|
683
|
+
this.emit({
|
|
684
|
+
type: 'retrieve:fallback',
|
|
685
|
+
strategy: 'keyword-fallback',
|
|
686
|
+
reason: 'Embeddings unavailable; using keyword search',
|
|
687
|
+
timestamp: Date.now(),
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
// --- Keyword fallback ---
|
|
691
|
+
if (!this.keywordFallback) {
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
return this.keywordFallback.search(query, topK);
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Graph expansion callback for the dispatcher.
|
|
698
|
+
*
|
|
699
|
+
* Placeholder — returns empty array.
|
|
700
|
+
* // Follow-up: wire GraphRAGEngine
|
|
701
|
+
*
|
|
702
|
+
* @param _seeds - Seed chunks to expand from (unused for now).
|
|
703
|
+
* @returns Promise resolving to an empty array.
|
|
704
|
+
*/
|
|
705
|
+
async graphExpand(_seeds) {
|
|
706
|
+
// Follow-up: wire GraphRAGEngine
|
|
707
|
+
return [];
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Reranking callback for the dispatcher.
|
|
711
|
+
*
|
|
712
|
+
* Placeholder — returns the first topN chunks without actual reranking.
|
|
713
|
+
* // Follow-up: wire RerankerService
|
|
714
|
+
*
|
|
715
|
+
* @param _query - The user's query (unused for now).
|
|
716
|
+
* @param chunks - Candidate chunks to rerank.
|
|
717
|
+
* @param topN - Maximum number of chunks to keep.
|
|
718
|
+
* @returns Promise resolving to the first topN chunks.
|
|
719
|
+
*/
|
|
720
|
+
async rerank(_query, chunks, topN) {
|
|
721
|
+
// Follow-up: wire RerankerService
|
|
722
|
+
return chunks.slice(0, topN);
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Deep research callback for the dispatcher.
|
|
726
|
+
*
|
|
727
|
+
* Placeholder — returns empty synthesis and empty sources.
|
|
728
|
+
* // Follow-up: wire DeepResearchEngine
|
|
729
|
+
*
|
|
730
|
+
* @param _query - The user's query (unused for now).
|
|
731
|
+
* @param _sources - Source identifiers to consult (unused for now).
|
|
732
|
+
* @returns Promise resolving to empty synthesis and sources.
|
|
733
|
+
*/
|
|
734
|
+
async deepResearch(_query, _sources) {
|
|
735
|
+
// Follow-up: wire DeepResearchEngine
|
|
736
|
+
return { synthesis: '', sources: [] };
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Format available tools for the classifier prompt.
|
|
740
|
+
*/
|
|
741
|
+
formatToolList(availableTools) {
|
|
742
|
+
return availableTools.length > 0 ? availableTools.join(', ') : '(none available)';
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Derive fallback strategy names from classification + retrieval events.
|
|
746
|
+
*/
|
|
747
|
+
collectFallbacks(classification, events) {
|
|
748
|
+
const fallbacks = new Set();
|
|
749
|
+
if (classification.confidence < this.config.confidenceThreshold) {
|
|
750
|
+
fallbacks.add('low-confidence-classification');
|
|
751
|
+
}
|
|
752
|
+
for (const event of events) {
|
|
753
|
+
if (event.type === 'retrieve:fallback') {
|
|
754
|
+
fallbacks.add(event.strategy);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return Array.from(fallbacks);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Approximate the tiers actually exercised when fallback strategies fired.
|
|
761
|
+
*/
|
|
762
|
+
collectTiersUsed(classification, fallbacksUsed) {
|
|
763
|
+
const tiers = new Set([classification.tier]);
|
|
764
|
+
for (const fallback of fallbacksUsed) {
|
|
765
|
+
if (fallback === 'research-skip') {
|
|
766
|
+
tiers.add(2);
|
|
767
|
+
}
|
|
768
|
+
if (fallback === 'graph-skip' || fallback === 'keyword-fallback' || fallback === 'rerank-skip') {
|
|
769
|
+
tiers.add(1);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return Array.from(tiers).sort((a, b) => a - b);
|
|
773
|
+
}
|
|
774
|
+
// ==========================================================================
|
|
775
|
+
// PRIVATE — Event emission
|
|
776
|
+
// ==========================================================================
|
|
777
|
+
/**
|
|
778
|
+
* Store a lifecycle event and emit a structured console log.
|
|
779
|
+
*
|
|
780
|
+
* Events are accumulated in the `events` array for later inspection
|
|
781
|
+
* and also logged to the console with a `[QueryRouter]` prefix for
|
|
782
|
+
* real-time observability.
|
|
783
|
+
*
|
|
784
|
+
* @param event - The typed lifecycle event to emit.
|
|
785
|
+
*/
|
|
786
|
+
emit(event) {
|
|
787
|
+
this.events.push(event);
|
|
788
|
+
}
|
|
789
|
+
// ==========================================================================
|
|
790
|
+
// PRIVATE — Guards
|
|
791
|
+
// ==========================================================================
|
|
792
|
+
/**
|
|
793
|
+
* Assert that the router has been initialised via {@link init}.
|
|
794
|
+
*
|
|
795
|
+
* @throws Error if `init()` has not been called.
|
|
796
|
+
*/
|
|
797
|
+
ensureInitialized() {
|
|
798
|
+
if (!this.initialized) {
|
|
799
|
+
throw new Error('QueryRouter has not been initialised. Call init() before classify/retrieve/route.');
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
//# sourceMappingURL=QueryRouter.js.map
|