"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NaiveJsonOutputParser = void 0;
exports.isModelWithResponseFormat = isModelWithResponseFormat;
exports.isModelInThinkingMode = isModelInThinkingMode;
exports.isModelWithFormat = isModelWithFormat;
exports.getOutputParserForLLM = getOutputParserForLLM;
exports.executeChain = executeChain;
const output_parsers_1 = require("@langchain/core/output_parsers");
const ai_utilities_1 = require("@n8n/ai-utilities");
const tracing_1 = require("../../../../utils/tracing");
const promptUtils_1 = require("./promptUtils");
class NaiveJsonOutputParser extends output_parsers_1.JsonOutputParser {
    async parse(text) {
        try {
            const directParsed = JSON.parse(text);
            return directParsed;
        }
        catch (e) {
            return await super.parse(text);
        }
    }
}
exports.NaiveJsonOutputParser = NaiveJsonOutputParser;
function isModelWithResponseFormat(llm) {
    return ('modelKwargs' in llm &&
        !!llm.modelKwargs &&
        typeof llm.modelKwargs === 'object' &&
        'response_format' in llm.modelKwargs);
}
function isModelInThinkingMode(llm) {
    return ('lc_kwargs' in llm &&
        'invocationKwargs' in llm.lc_kwargs &&
        typeof llm.lc_kwargs.invocationKwargs === 'object' &&
        'thinking' in llm.lc_kwargs.invocationKwargs &&
        llm.lc_kwargs.invocationKwargs.thinking.type === 'enabled');
}
function isModelWithFormat(llm) {
    return 'format' in llm && typeof llm.format !== 'undefined';
}
function getOutputParserForLLM(llm) {
    if (isModelWithResponseFormat(llm) && llm.modelKwargs?.response_format?.type === 'json_object') {
        return new NaiveJsonOutputParser();
    }
    if (isModelWithFormat(llm) && llm.format === 'json') {
        return new NaiveJsonOutputParser();
    }
    if (isModelInThinkingMode(llm)) {
        return new NaiveJsonOutputParser();
    }
    if (llm.metadata?.output_format === 'json') {
        return new NaiveJsonOutputParser();
    }
    return new output_parsers_1.StringOutputParser();
}
async function executeSimpleChain({ context, llm, query, prompt, }) {
    const outputParser = getOutputParserForLLM(llm);
    const chain = prompt.pipe(llm).pipe(outputParser).withConfig((0, tracing_1.getTracingConfig)(context));
    const response = await chain.invoke({ query }, { signal: context.getExecutionCancelSignal() });
    return [response];
}
function withBuiltInTools(llm) {
    const modelTools = llm.metadata?.tools ?? [];
    if (modelTools.length && (0, ai_utilities_1.isChatInstance)(llm) && llm.bindTools) {
        return llm.bindTools(modelTools);
    }
    return llm;
}
function prepareLlm(llm, fallbackLlm) {
    const mainLlm = withBuiltInTools(llm);
    if (fallbackLlm) {
        return mainLlm.withFallbacks([withBuiltInTools(fallbackLlm)]);
    }
    return mainLlm;
}
async function executeChain({ context, itemIndex, query, llm, outputParser, messages, fallbackLlm, }) {
    const version = context.getNode().typeVersion;
    const model = prepareLlm(llm, fallbackLlm);
    if (!outputParser) {
        const promptTemplate = await (0, promptUtils_1.createPromptTemplate)({
            context,
            itemIndex,
            llm,
            messages,
            query,
        });
        return await executeSimpleChain({
            context,
            llm: model,
            query,
            prompt: promptTemplate,
        });
    }
    const formatInstructions = outputParser.getFormatInstructions();
    const promptWithInstructions = await (0, promptUtils_1.createPromptTemplate)({
        context,
        itemIndex,
        llm,
        messages,
        formatInstructions,
        query,
    });
    let chain;
    if (version >= 1.9) {
        chain = promptWithInstructions
            .pipe(model)
            .pipe((0, promptUtils_1.getAgentStepsParser)(outputParser))
            .withConfig((0, tracing_1.getTracingConfig)(context));
    }
    else {
        chain = promptWithInstructions
            .pipe(model)
            .pipe(outputParser)
            .withConfig((0, tracing_1.getTracingConfig)(context));
    }
    const response = await chain.invoke({ query }, { signal: context.getExecutionCancelSignal() });
    return Array.isArray(response) ? response : [response];
}
//# sourceMappingURL=chainExecutor.js.map