"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "RouterQueryEngine", {
    enumerable: true,
    get: function() {
        return RouterQueryEngine;
    }
});
const _Response = require("../../Response.js");
const _Settings = require("../../Settings.js");
const _index = require("../../prompts/index.js");
const _index1 = require("../../selectors/index.js");
const _index2 = require("../../synthesizers/index.js");
async function combineResponses(summarizer, responses, queryBundle, verbose = false) {
    if (verbose) {
        console.log("Combining responses from multiple query engines.");
    }
    const responseStrs = [];
    const sourceNodes = [];
    for (const response of responses){
        if (response?.sourceNodes) {
            sourceNodes.push(...response.sourceNodes);
        }
        responseStrs.push(response.response);
    }
    const summary = await summarizer.getResponse({
        query: queryBundle.queryStr,
        textChunks: responseStrs
    });
    return new _Response.Response(summary, sourceNodes);
}
class RouterQueryEngine extends _index.PromptMixin {
    selector;
    queryEngines;
    metadatas;
    summarizer;
    verbose;
    constructor(init){
        super();
        this.selector = init.selector;
        this.queryEngines = init.queryEngineTools.map((tool)=>tool.queryEngine);
        this.metadatas = init.queryEngineTools.map((tool)=>({
                description: tool.description
            }));
        this.summarizer = init.summarizer || new _index2.TreeSummarize(init.serviceContext);
        this.verbose = init.verbose ?? false;
    }
    _getPromptModules() {
        return {
            selector: this.selector,
            summarizer: this.summarizer
        };
    }
    static fromDefaults(init) {
        const serviceContext = init.serviceContext;
        return new RouterQueryEngine({
            selector: init.selector ?? new _index1.LLMSingleSelector({
                llm: (0, _Settings.llmFromSettingsOrContext)(serviceContext)
            }),
            queryEngineTools: init.queryEngineTools,
            serviceContext,
            summarizer: init.summarizer,
            verbose: init.verbose
        });
    }
    async query(params) {
        const { query, stream } = params;
        const response = await this.queryRoute({
            queryStr: query
        });
        if (stream) {
            throw new Error("Streaming is not supported yet.");
        }
        return response;
    }
    async queryRoute(queryBundle) {
        const result = await this.selector.select(this.metadatas, queryBundle);
        if (result.selections.length > 1) {
            const responses = [];
            for(let i = 0; i < result.selections.length; i++){
                const engineInd = result.selections[i];
                const logStr = `Selecting query engine ${engineInd}: ${result.selections[i]}.`;
                if (this.verbose) {
                    console.log(logStr + "\n");
                }
                const selectedQueryEngine = this.queryEngines[engineInd.index];
                responses.push(await selectedQueryEngine.query({
                    query: queryBundle.queryStr
                }));
            }
            if (responses.length > 1) {
                const finalResponse = await combineResponses(this.summarizer, responses, queryBundle, this.verbose);
                return finalResponse;
            } else {
                return responses[0];
            }
        } else {
            let selectedQueryEngine;
            try {
                selectedQueryEngine = this.queryEngines[result.selections[0].index];
                const logStr = `Selecting query engine ${result.selections[0].index}: ${result.selections[0].reason}`;
                if (this.verbose) {
                    console.log(logStr + "\n");
                }
            } catch (e) {
                throw new Error("Failed to select query engine");
            }
            if (!selectedQueryEngine) {
                throw new Error("Selected query engine is null");
            }
            const finalResponse = await selectedQueryEngine.query({
                query: queryBundle.queryStr
            });
            // add selected result
            finalResponse.metadata = finalResponse.metadata || {};
            finalResponse.metadata["selectorResult"] = result;
            return finalResponse;
        }
    }
}
