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, }); } }