import { OutputParserException } from "@langchain/core/output_parsers";
import { renderTemplate } from "@langchain/core/prompts";
import { AgentActionOutputParser } from "../types.js";
import { AGENT_ACTION_FORMAT_INSTRUCTIONS, FORMAT_INSTRUCTIONS, } from "./prompt.js";
import { OutputFixingParser } from "../../output_parsers/fix.js";
/**
 * A class that provides a custom implementation for parsing the output of
 * a StructuredChatAgent action. It extends the `AgentActionOutputParser`
 * class and extracts the action and action input from the text output,
 * returning an `AgentAction` or `AgentFinish` object.
 */
export class StructuredChatOutputParser extends AgentActionOutputParser {
    constructor(fields) {
        super(...arguments);
        Object.defineProperty(this, "lc_namespace", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: ["langchain", "agents", "structured_chat"]
        });
        Object.defineProperty(this, "toolNames", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.toolNames = fields.toolNames;
    }
    /**
     * Parses the given text and returns an `AgentAction` or `AgentFinish`
     * object. If an `OutputFixingParser` is provided, it is used for parsing;
     * otherwise, the base parser is used.
     * @param text The text to parse.
     * @param callbacks Optional callbacks for asynchronous operations.
     * @returns A Promise that resolves to an `AgentAction` or `AgentFinish` object.
     */
    async parse(text) {
        try {
            const regex = /```(?:json)?(.*)(```)/gs;
            const actionMatch = regex.exec(text);
            if (actionMatch === null) {
                throw new OutputParserException(`Could not parse an action. The agent action must be within a markdown code block, and "action" must be a provided tool or "Final Answer"`);
            }
            const response = JSON.parse(actionMatch[1].trim());
            const { action, action_input } = response;
            if (action === "Final Answer") {
                return { returnValues: { output: action_input }, log: text };
            }
            return { tool: action, toolInput: action_input || {}, log: text };
        }
        catch (e) {
            throw new OutputParserException(`Failed to parse. Text: "${text}". Error: ${e}`);
        }
    }
    /**
     * Returns the format instructions for parsing the output of an agent
     * action in the style of the StructuredChatAgent.
     * @returns A string representing the format instructions.
     */
    getFormatInstructions() {
        return renderTemplate(AGENT_ACTION_FORMAT_INSTRUCTIONS, "f-string", {
            tool_names: this.toolNames.join(", "),
        });
    }
}
/**
 * A class that provides a wrapper around the `StructuredChatOutputParser`
 * and `OutputFixingParser` classes. It extends the
 * `AgentActionOutputParser` class and allows for retrying the output
 * parsing using the `OutputFixingParser` if it is provided.
 * @example
 * ```typescript
 * const outputParser = new StructuredChatOutputParserWithRetries.fromLLM(
 *   new ChatOpenAI({ temperature: 0 }),
 *   {
 *     toolNames: ["calculator", "random-number-generator"],
 *   },
 * );
 * const result = await outputParser.parse(
 *  "What is a random number between 5 and 10 raised to the second power?"
 * );
 * ```
 */
export class StructuredChatOutputParserWithRetries extends AgentActionOutputParser {
    constructor(fields) {
        super(fields);
        Object.defineProperty(this, "lc_namespace", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: ["langchain", "agents", "structured_chat"]
        });
        Object.defineProperty(this, "baseParser", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "outputFixingParser", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "toolNames", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        this.toolNames = fields.toolNames ?? this.toolNames;
        this.baseParser =
            fields?.baseParser ??
                new StructuredChatOutputParser({ toolNames: this.toolNames });
        this.outputFixingParser = fields?.outputFixingParser;
    }
    /**
     * Parses the given text and returns an `AgentAction` or `AgentFinish`
     * object. Throws an `OutputParserException` if the parsing fails.
     * @param text The text to parse.
     * @returns A Promise that resolves to an `AgentAction` or `AgentFinish` object.
     */
    async parse(text, callbacks) {
        if (this.outputFixingParser !== undefined) {
            return this.outputFixingParser.parse(text, callbacks);
        }
        return this.baseParser.parse(text);
    }
    /**
     * Returns the format instructions for parsing the output of an agent
     * action in the style of the StructuredChatAgent.
     * @returns A string representing the format instructions.
     */
    getFormatInstructions() {
        return renderTemplate(FORMAT_INSTRUCTIONS, "f-string", {
            tool_names: this.toolNames.join(", "),
        });
    }
    /**
     * Creates a new `StructuredChatOutputParserWithRetries` instance from a
     * `BaseLanguageModel` and options. The options can include a base parser
     * and tool names.
     * @param llm A `BaseLanguageModel` instance.
     * @param options Options for creating a `StructuredChatOutputParserWithRetries` instance.
     * @returns A new `StructuredChatOutputParserWithRetries` instance.
     */
    static fromLLM(llm, options) {
        const baseParser = options.baseParser ??
            new StructuredChatOutputParser({ toolNames: options.toolNames ?? [] });
        const outputFixingParser = OutputFixingParser.fromLLM(llm, baseParser);
        return new StructuredChatOutputParserWithRetries({
            baseParser,
            outputFixingParser,
            toolNames: options.toolNames,
        });
    }
}