@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
431 lines (430 loc) • 14.7 kB
JavaScript
/**
* Reranker Factory
*
* Factory for creating reranker instances with configuration.
* Follows the BaseFactory pattern for consistent lifecycle management.
*/
import { BaseFactory } from "../../core/infrastructure/index.js";
import { logger } from "../../utils/logger.js";
import { RAGErrorCodes, RerankerError } from "../errors/RAGError.js";
/**
* Default reranker metadata entries
*/
const DEFAULT_RERANKER_METADATA = {
llm: {
description: "LLM-powered semantic reranking with multi-factor scoring",
defaultConfig: {
topK: 3,
weights: { semantic: 0.4, vector: 0.4, position: 0.2 },
},
supportedOptions: ["model", "provider", "topK", "weights"],
useCases: [
"High-quality semantic reranking",
"Complex query understanding",
"Context-aware scoring",
],
aliases: ["semantic", "ai", "model-based"],
requiresModel: true,
requiresExternalAPI: false,
},
"cross-encoder": {
description: "Cross-encoder model for query-document relevance scoring",
defaultConfig: {
topK: 3,
model: "ms-marco-MiniLM-L-6-v2",
},
supportedOptions: ["model", "topK"],
useCases: [
"High-precision reranking",
"Search result refinement",
"Academic/research applications",
],
aliases: ["cross", "encoder", "bi-encoder"],
requiresModel: true,
requiresExternalAPI: false,
},
cohere: {
description: "Cohere Rerank API for production-grade relevance scoring",
defaultConfig: {
topK: 3,
model: "rerank-v3.5",
},
supportedOptions: ["model", "topK", "apiKey"],
useCases: [
"Production search systems",
"Enterprise applications",
"High-volume reranking",
],
aliases: ["cohere-rerank", "cohere-api"],
requiresModel: false,
requiresExternalAPI: true,
},
simple: {
description: "Position and vector score-based reranking (no LLM required)",
defaultConfig: {
topK: 3,
weights: { vector: 0.8, position: 0.2 },
},
supportedOptions: ["topK", "weights"],
useCases: [
"Fast reranking",
"Low-latency requirements",
"When LLM is unavailable",
],
aliases: ["fast", "basic", "position-based"],
requiresModel: false,
requiresExternalAPI: false,
},
batch: {
description: "Batch LLM reranking for efficient multi-document scoring",
defaultConfig: {
topK: 3,
weights: { semantic: 0.4, vector: 0.4, position: 0.2 },
},
supportedOptions: ["model", "provider", "topK", "weights"],
useCases: [
"Large result sets",
"Cost-efficient LLM usage",
"Batch processing pipelines",
],
aliases: ["batch-llm", "efficient", "bulk"],
requiresModel: true,
requiresExternalAPI: false,
},
};
/**
* Reranker Factory
*
* Creates reranker instances based on type with configuration support.
* Uses lazy loading via dynamic imports to avoid circular dependencies.
*/
export class RerankerFactory extends BaseFactory {
static instance = null;
metadataMap = new Map();
modelProvider = null;
constructor() {
super();
}
/**
* Get singleton instance
*/
static getInstance() {
if (!RerankerFactory.instance) {
RerankerFactory.instance = new RerankerFactory();
}
return RerankerFactory.instance;
}
/**
* Reset singleton (for testing)
*/
static resetInstance() {
if (RerankerFactory.instance) {
RerankerFactory.instance.clear();
RerankerFactory.instance = null;
}
}
/**
* Set the AI provider for LLM-based rerankers
*/
setModelProvider(provider) {
this.modelProvider = provider;
}
/**
* Register all default rerankers
*/
async registerAll() {
// Register LLM reranker
this.registerReranker("llm", async (config) => {
const { rerank } = await import("./reranker.js");
return this.createLLMReranker(rerank, config);
}, DEFAULT_RERANKER_METADATA.llm);
// Register cross-encoder reranker
this.registerReranker("cross-encoder", async (config) => {
const { CrossEncoderReranker } = await import("./reranker.js");
return this.createCrossEncoderReranker(CrossEncoderReranker, config);
}, DEFAULT_RERANKER_METADATA["cross-encoder"]);
// Register Cohere reranker
this.registerReranker("cohere", async (config) => {
const { CohereRelevanceScorer } = await import("./reranker.js");
return this.createCohereReranker(CohereRelevanceScorer, config);
}, DEFAULT_RERANKER_METADATA.cohere);
// Register simple reranker
this.registerReranker("simple", async (config) => {
const { simpleRerank } = await import("./reranker.js");
return this.createSimpleReranker(simpleRerank, config);
}, DEFAULT_RERANKER_METADATA.simple);
// Register batch reranker
this.registerReranker("batch", async (config) => {
const { batchRerank } = await import("./reranker.js");
return this.createBatchReranker(batchRerank, config);
}, DEFAULT_RERANKER_METADATA.batch);
logger.debug(`[RerankerFactory] Registered ${this.items.size} reranker types`);
}
/**
* Create LLM-based reranker wrapper
*/
createLLMReranker(rerankFn, config) {
const factory = this;
return {
type: "llm",
async rerank(results, query, options) {
if (!factory.modelProvider) {
throw new RerankerError("LLM reranker requires a model provider. Call setModelProvider() first.", {
rerankerType: "llm",
});
}
return rerankFn(results, query, factory.modelProvider, {
...options,
topK: config?.topK ?? options?.topK,
weights: config?.weights ?? options?.weights,
});
},
};
}
/**
* Create cross-encoder reranker wrapper
*/
createCrossEncoderReranker(CrossEncoderClass, config) {
const encoder = new CrossEncoderClass(typeof config?.model === "string" ? config.model : undefined);
return {
type: "cross-encoder",
async rerank(results, query, options) {
const documents = results.map((r) => r.text || r.metadata?.text || "");
const scores = await encoder.rerank(query, documents);
const topK = config?.topK ?? options?.topK ?? 3;
return scores
.map((s) => ({
result: results[s.index],
score: s.score,
details: {
semantic: s.score,
vector: results[s.index].score ?? 0,
position: 1 - s.index / results.length,
},
}))
.sort((a, b) => b.score - a.score)
.slice(0, topK);
},
};
}
/**
* Create Cohere reranker wrapper
*/
createCohereReranker(CohereClass, config) {
const scorer = new CohereClass(typeof config?.model === "string" ? config.model : undefined);
return {
type: "cohere",
async rerank(results, query, options) {
const documents = results.map((r) => r.text || r.metadata?.text || "");
const scores = await scorer.score(query, documents);
const topK = config?.topK ?? options?.topK ?? 3;
return scores
.map((s) => ({
result: results[s.index],
score: s.score,
details: {
semantic: s.score,
vector: results[s.index].score ?? 0,
position: 1 - s.index / results.length,
},
}))
.sort((a, b) => b.score - a.score)
.slice(0, topK);
},
};
}
/**
* Create simple reranker wrapper
*/
createSimpleReranker(simpleRerankFn, config) {
return {
type: "simple",
async rerank(results, _query, options) {
return simpleRerankFn(results, {
topK: config?.topK ?? options?.topK,
vectorWeight: config?.weights?.vector,
positionWeight: config?.weights?.position,
});
},
};
}
/**
* Create batch reranker wrapper
*/
createBatchReranker(batchRerankFn, config) {
const factory = this;
return {
type: "batch",
async rerank(results, query, options) {
if (!factory.modelProvider) {
throw new RerankerError("Batch reranker requires a model provider. Call setModelProvider() first.", {
rerankerType: "batch",
});
}
return batchRerankFn(results, query, factory.modelProvider, {
...options,
topK: config?.topK ?? options?.topK,
weights: config?.weights ?? options?.weights,
});
},
};
}
/**
* Register a reranker with metadata and aliases
*/
registerReranker(type, factory, metadata) {
// Store metadata
this.metadataMap.set(type, metadata);
// Register with aliases
this.register(type, factory, metadata.aliases, { metadata });
logger.debug(`[RerankerFactory] Registered reranker '${type}' with aliases: ${metadata.aliases.join(", ")}`);
}
/**
* Create a reranker by type or alias
*/
async createReranker(typeOrAlias, config) {
await this.ensureInitialized();
const resolvedName = this.resolveName(typeOrAlias);
if (!this.has(resolvedName)) {
const available = this.getAvailable();
throw new RerankerError(`Unknown reranker type: '${typeOrAlias}'. Available types: ${available.join(", ")}`, {
code: RAGErrorCodes.RERANKER_NOT_FOUND,
rerankerType: typeOrAlias,
details: {
requestedType: typeOrAlias,
availableTypes: available,
},
});
}
try {
const reranker = await this.create(resolvedName, config);
logger.debug(`[RerankerFactory] Created reranker '${resolvedName}' with config:`, config);
return reranker;
}
catch (error) {
// Re-throw if already a RerankerError
if (error instanceof RerankerError) {
throw error;
}
throw new RerankerError(`Failed to create reranker '${resolvedName}': ${error instanceof Error ? error.message : String(error)}`, {
rerankerType: resolvedName,
cause: error instanceof Error ? error : undefined,
details: { type: resolvedName, config },
});
}
}
/**
* Get metadata for a reranker
*/
getRerankerMetadata(typeOrAlias) {
const resolvedName = this.resolveName(typeOrAlias);
return this.metadataMap.get(resolvedName);
}
/**
* Get default configuration for a reranker
*/
getDefaultConfig(typeOrAlias) {
const metadata = this.getRerankerMetadata(typeOrAlias);
return metadata?.defaultConfig;
}
/**
* Get available reranker types (not including aliases)
*/
async getAvailableTypes() {
await this.ensureInitialized();
return this.getAvailable();
}
/**
* Get all aliases mapped to their types
*/
getTypeAliases() {
return this.getAliases();
}
/**
* Check if a type exists
*/
hasType(typeOrAlias) {
const resolved = this.resolveName(typeOrAlias);
return this.has(resolved);
}
/**
* Get rerankers suitable for a use case
*/
getRerankersForUseCase(useCase) {
const matches = [];
const useCaseLower = useCase.toLowerCase();
for (const [type, metadata] of this.metadataMap) {
const hasMatch = metadata.useCases.some((uc) => uc.toLowerCase().includes(useCaseLower));
if (hasMatch) {
matches.push(type);
}
}
return matches;
}
/**
* Get rerankers that don't require external APIs
*/
getLocalRerankers() {
const matches = [];
for (const [type, metadata] of this.metadataMap) {
if (!metadata.requiresExternalAPI) {
matches.push(type);
}
}
return matches;
}
/**
* Get rerankers that don't require AI models
*/
getModelFreeRerankers() {
const matches = [];
for (const [type, metadata] of this.metadataMap) {
if (!metadata.requiresModel) {
matches.push(type);
}
}
return matches;
}
/**
* Get all reranker metadata
*/
getAllMetadata() {
return new Map(this.metadataMap);
}
/**
* Clear factory and metadata
*/
clear() {
super.clear();
this.metadataMap.clear();
this.modelProvider = null;
}
}
/**
* Global reranker factory singleton
*/
export const rerankerFactory = RerankerFactory.getInstance();
/**
* Convenience function to create a reranker
*/
export async function createReranker(typeOrAlias, config) {
return rerankerFactory.createReranker(typeOrAlias, config);
}
/**
* Convenience function to get available reranker types
*/
export async function getAvailableRerankerTypes() {
return rerankerFactory.getAvailableTypes();
}
/**
* Convenience function to get reranker metadata
*/
export function getRerankerMetadata(typeOrAlias) {
return rerankerFactory.getRerankerMetadata(typeOrAlias);
}
/**
* Convenience function to get default config
*/
export function getRerankerDefaultConfig(typeOrAlias) {
return rerankerFactory.getDefaultConfig(typeOrAlias);
}