"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FunctionCallStructuredOutputParser = void 0;
exports.createStructuredOutputChain = createStructuredOutputChain;
exports.createStructuredOutputChainFromZod = createStructuredOutputChainFromZod;
const json_schema_1 = require("@langchain/core/utils/json_schema");
const openai_1 = require("@langchain/openai");
const output_parsers_1 = require("@langchain/core/output_parsers");
const types_1 = require("@langchain/core/utils/types");
const llm_chain_js_1 = require("../llm_chain.cjs");
const openai_functions_js_1 = require("../../output_parsers/openai_functions.cjs");
function isJsonSchema7Type(x) {
    return (x.jsonSchema === undefined &&
        x.zodSchema === undefined);
}
/**
 * Class that extends the BaseLLMOutputParser class. It provides
 * functionality for parsing the structured output based on a JSON schema.
 */
class FunctionCallStructuredOutputParser extends output_parsers_1.BaseLLMOutputParser {
    constructor(fieldsOrSchema) {
        let fields;
        if (isJsonSchema7Type(fieldsOrSchema)) {
            fields = { jsonSchema: fieldsOrSchema };
        }
        else {
            fields = fieldsOrSchema;
        }
        if (fields.jsonSchema === undefined && fields.zodSchema === undefined) {
            throw new Error(`Must provide at least one of "jsonSchema" or "zodSchema".`);
        }
        super(fields);
        Object.defineProperty(this, "lc_namespace", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: ["langchain", "chains", "openai_functions"]
        });
        Object.defineProperty(this, "functionOutputParser", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: new openai_functions_js_1.OutputFunctionsParser()
        });
        Object.defineProperty(this, "jsonSchemaValidator", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "zodSchema", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        if (fields.jsonSchema !== undefined) {
            this.jsonSchemaValidator = new json_schema_1.Validator(fields.jsonSchema, "7");
        }
        if (fields.zodSchema !== undefined) {
            this.zodSchema = fields.zodSchema;
        }
    }
    /**
     * Method to parse the result of chat generations. It first parses the
     * result using the functionOutputParser, then parses the result against a
     * zod schema if the zod schema is available which allows the result to undergo
     * Zod preprocessing, then it parses that result against the JSON schema.
     * If the result is valid, it returns the parsed result. Otherwise, it throws
     * an OutputParserException.
     * @param generations Array of ChatGeneration instances to be parsed.
     * @returns The parsed result if it is valid according to the JSON schema.
     */
    async parseResult(generations) {
        const initialResult = await this.functionOutputParser.parseResult(generations);
        const parsedResult = JSON.parse(initialResult, (_, value) => {
            if (value === null) {
                return undefined;
            }
            return value;
        });
        if (this.zodSchema) {
            const zodParsedResult = await (0, types_1.interopSafeParseAsync)(this.zodSchema, parsedResult);
            if (zodParsedResult.success) {
                return zodParsedResult.data;
            }
            else {
                throw new output_parsers_1.OutputParserException(`Failed to parse. Text: "${initialResult}". Error: ${JSON.stringify(zodParsedResult.error.issues)}`, initialResult);
            }
        }
        else if (this.jsonSchemaValidator !== undefined) {
            const result = this.jsonSchemaValidator.validate(parsedResult);
            if (result.valid) {
                return parsedResult;
            }
            else {
                throw new output_parsers_1.OutputParserException(`Failed to parse. Text: "${initialResult}". Error: ${JSON.stringify(result.errors)}`, initialResult);
            }
        }
        else {
            throw new Error("This parser requires an input JSON Schema or an input Zod schema.");
        }
    }
}
exports.FunctionCallStructuredOutputParser = FunctionCallStructuredOutputParser;
/**
 * @deprecated Use {@link https://api.js.langchain.com/functions/langchain.chains_openai_functions.createStructuredOutputRunnable.html | createStructuredOutputRunnable} instead
 * Create a chain that returns output matching a JSON Schema.
 * @param input Object that includes all LLMChainInput fields except "outputParser"
 * as well as an additional required "outputSchema" JSON Schema object.
 * @returns OpenAPIChain
 */
function createStructuredOutputChain(input) {
    const { outputSchema, llm = new openai_1.ChatOpenAI({ model: "gpt-3.5-turbo-0613", temperature: 0 }), outputKey = "output", llmKwargs = {}, zodSchema, ...rest } = input;
    if (outputSchema === undefined && zodSchema === undefined) {
        throw new Error(`Must provide one of "outputSchema" or "zodSchema".`);
    }
    const functionName = "output_formatter";
    return new llm_chain_js_1.LLMChain({
        llm,
        llmKwargs: {
            ...llmKwargs,
            functions: [
                {
                    name: functionName,
                    description: `Output formatter. Should always be used to format your response to the user.`,
                    parameters: outputSchema,
                },
            ],
            function_call: {
                name: functionName,
            },
        },
        outputKey,
        outputParser: new FunctionCallStructuredOutputParser({
            jsonSchema: outputSchema,
            zodSchema,
        }),
        ...rest,
    });
}
/** @deprecated Use {@link https://api.js.langchain.com/functions/langchain.chains_openai_functions.createStructuredOutputRunnable.html | createStructuredOutputRunnable} instead */
function createStructuredOutputChainFromZod(zodSchema, input) {
    return createStructuredOutputChain({
        ...input,
        outputSchema: (0, json_schema_1.toJsonSchema)(zodSchema),
        zodSchema,
    });
}
