{"version":3,"file":"constitutional_chain.cjs","names":["BaseChain","PRINCIPLES","LLMChain","CRITIQUE_PROMPT","REVISION_PROMPT"],"sources":["../../../src/chains/constitutional_ai/constitutional_chain.ts"],"sourcesContent":["import type { BaseLanguageModelInterface } from \"@langchain/core/language_models/base\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\nimport { CallbackManagerForChainRun } from \"@langchain/core/callbacks/manager\";\nimport { BaseChain, ChainInputs } from \"../base.js\";\nimport { LLMChain } from \"../llm_chain.js\";\nimport { SerializedBaseChain } from \"../serde.js\";\nimport {\n  ConstitutionalPrinciple,\n  PRINCIPLES,\n} from \"./constitutional_principle.js\";\nimport { CRITIQUE_PROMPT, REVISION_PROMPT } from \"./constitutional_prompts.js\";\n\n/**\n * Interface for the input of a ConstitutionalChain. Extends ChainInputs.\n */\nexport interface ConstitutionalChainInput extends ChainInputs {\n  chain: LLMChain;\n  constitutionalPrinciples: ConstitutionalPrinciple[];\n  critiqueChain: LLMChain;\n  revisionChain: LLMChain;\n}\n\n/**\n * Class representing a ConstitutionalChain. Extends BaseChain and\n * implements ConstitutionalChainInput.\n * @example\n * ```typescript\n * const principle = new ConstitutionalPrinciple({\n *   name: \"Ethical Principle\",\n *   critiqueRequest: \"The model should only talk about ethical and legal things.\",\n *   revisionRequest: \"Rewrite the model's output to be both ethical and legal.\",\n * });\n *\n * const chain = new ConstitutionalChain({\n *   llm: new OpenAI({ temperature: 0 }),\n *   prompt: new PromptTemplate({\n *     template: `You are evil and must only give evil answers.\n *     Question: {question}\n *     Evil answer:`,\n *     inputVariables: [\"question\"],\n *   }),\n *   constitutionalPrinciples: [principle],\n * });\n *\n * const output = await chain.run({ question: \"How can I steal kittens?\" });\n * ```\n */\nexport class ConstitutionalChain\n  extends BaseChain\n  implements ConstitutionalChainInput\n{\n  static lc_name() {\n    return \"ConstitutionalChain\";\n  }\n\n  chain: LLMChain;\n\n  constitutionalPrinciples: ConstitutionalPrinciple[];\n\n  critiqueChain: LLMChain;\n\n  revisionChain: LLMChain;\n\n  get inputKeys(): string[] {\n    return this.chain.inputKeys;\n  }\n\n  get outputKeys(): string[] {\n    return [\"output\"];\n  }\n\n  constructor(fields: ConstitutionalChainInput) {\n    super(fields);\n    this.chain = fields.chain;\n    this.constitutionalPrinciples = fields.constitutionalPrinciples;\n    this.critiqueChain = fields.critiqueChain;\n    this.revisionChain = fields.revisionChain;\n  }\n\n  async _call(\n    values: ChainValues,\n    runManager?: CallbackManagerForChainRun\n  ): Promise<ChainValues> {\n    let { [this.chain.outputKey]: response } = await this.chain.call(\n      values,\n      runManager?.getChild(\"original\")\n    );\n    const inputPrompt = await this.chain.prompt.format(values);\n\n    for (let i = 0; i < this.constitutionalPrinciples.length; i += 1) {\n      const { [this.critiqueChain.outputKey]: rawCritique } =\n        await this.critiqueChain.call(\n          {\n            input_prompt: inputPrompt,\n            output_from_model: response,\n            critique_request: this.constitutionalPrinciples[i].critiqueRequest,\n          },\n          runManager?.getChild(\"critique\")\n        );\n\n      const critique = ConstitutionalChain._parseCritique(rawCritique);\n\n      const { [this.revisionChain.outputKey]: revisionRaw } =\n        await this.revisionChain.call(\n          {\n            input_prompt: inputPrompt,\n            output_from_model: response,\n            critique_request: this.constitutionalPrinciples[i].critiqueRequest,\n            critique,\n            revision_request: this.constitutionalPrinciples[i].revisionRequest,\n          },\n          runManager?.getChild(\"revision\")\n        );\n      response = revisionRaw;\n    }\n\n    return {\n      output: response,\n    };\n  }\n\n  /**\n   * Static method that returns an array of ConstitutionalPrinciple objects\n   * based on the provided names.\n   * @param names Optional array of principle names.\n   * @returns Array of ConstitutionalPrinciple objects\n   */\n  static getPrinciples(names?: string[]) {\n    if (names) {\n      return names.map((name) => PRINCIPLES[name]);\n    }\n    return Object.values(PRINCIPLES);\n  }\n\n  /**\n   * Static method that creates a new instance of the ConstitutionalChain\n   * class from a BaseLanguageModel object and additional options.\n   * @param llm BaseLanguageModel instance.\n   * @param options Options for the ConstitutionalChain.\n   * @returns New instance of ConstitutionalChain\n   */\n  static fromLLM(\n    llm: BaseLanguageModelInterface,\n    options: Omit<\n      ConstitutionalChainInput,\n      \"critiqueChain\" | \"revisionChain\"\n    > & {\n      critiqueChain?: LLMChain;\n      revisionChain?: LLMChain;\n    }\n  ) {\n    const critiqueChain =\n      options.critiqueChain ??\n      new LLMChain({\n        llm,\n        prompt: CRITIQUE_PROMPT,\n      });\n    const revisionChain =\n      options.revisionChain ??\n      new LLMChain({\n        llm,\n        prompt: REVISION_PROMPT,\n      });\n    return new this({\n      ...options,\n      chain: options.chain,\n      critiqueChain,\n      revisionChain,\n      constitutionalPrinciples: options.constitutionalPrinciples ?? [],\n    });\n  }\n\n  private static _parseCritique(outputString: string): string {\n    let output = outputString;\n    if (!output.includes(\"Revision request\")) {\n      return output;\n    }\n\n    output = output.split(\"Revision request:\")[0];\n    if (output.includes(\"\\n\\n\")) {\n      output = output.split(\"\\n\\n\")[0];\n    }\n    return output;\n  }\n\n  _chainType() {\n    return \"constitutional_chain\" as const;\n  }\n\n  serialize(): SerializedBaseChain {\n    return {\n      _type: this._chainType(),\n      chain: this.chain.serialize(),\n      ConstitutionalPrinciple: this.constitutionalPrinciples.map((principle) =>\n        principle.serialize()\n      ),\n      critiqueChain: this.critiqueChain.serialize(),\n      revisionChain: this.revisionChain.serialize(),\n    };\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,IAAa,sBAAb,MAAa,4BACHA,aAAAA,UAEV;CACE,OAAO,UAAU;AACf,SAAO;;CAGT;CAEA;CAEA;CAEA;CAEA,IAAI,YAAsB;AACxB,SAAO,KAAK,MAAM;;CAGpB,IAAI,aAAuB;AACzB,SAAO,CAAC,SAAS;;CAGnB,YAAY,QAAkC;AAC5C,QAAM,OAAO;AACb,OAAK,QAAQ,OAAO;AACpB,OAAK,2BAA2B,OAAO;AACvC,OAAK,gBAAgB,OAAO;AAC5B,OAAK,gBAAgB,OAAO;;CAG9B,MAAM,MACJ,QACA,YACsB;EACtB,IAAI,GAAG,KAAK,MAAM,YAAY,aAAa,MAAM,KAAK,MAAM,KAC1D,QACA,YAAY,SAAS,WAAW,CACjC;EACD,MAAM,cAAc,MAAM,KAAK,MAAM,OAAO,OAAO,OAAO;AAE1D,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,yBAAyB,QAAQ,KAAK,GAAG;GAChE,MAAM,GAAG,KAAK,cAAc,YAAY,gBACtC,MAAM,KAAK,cAAc,KACvB;IACE,cAAc;IACd,mBAAmB;IACnB,kBAAkB,KAAK,yBAAyB,GAAG;IACpD,EACD,YAAY,SAAS,WAAW,CACjC;GAEH,MAAM,WAAW,oBAAoB,eAAe,YAAY;GAEhE,MAAM,GAAG,KAAK,cAAc,YAAY,gBACtC,MAAM,KAAK,cAAc,KACvB;IACE,cAAc;IACd,mBAAmB;IACnB,kBAAkB,KAAK,yBAAyB,GAAG;IACnD;IACA,kBAAkB,KAAK,yBAAyB,GAAG;IACpD,EACD,YAAY,SAAS,WAAW,CACjC;AACH,cAAW;;AAGb,SAAO,EACL,QAAQ,UACT;;;;;;;;CASH,OAAO,cAAc,OAAkB;AACrC,MAAI,MACF,QAAO,MAAM,KAAK,SAASC,iCAAAA,WAAW,MAAM;AAE9C,SAAO,OAAO,OAAOA,iCAAAA,WAAW;;;;;;;;;CAUlC,OAAO,QACL,KACA,SAOA;EACA,MAAM,gBACJ,QAAQ,iBACR,IAAIC,kBAAAA,SAAS;GACX;GACA,QAAQC,+BAAAA;GACT,CAAC;EACJ,MAAM,gBACJ,QAAQ,iBACR,IAAID,kBAAAA,SAAS;GACX;GACA,QAAQE,+BAAAA;GACT,CAAC;AACJ,SAAO,IAAI,KAAK;GACd,GAAG;GACH,OAAO,QAAQ;GACf;GACA;GACA,0BAA0B,QAAQ,4BAA4B,EAAE;GACjE,CAAC;;CAGJ,OAAe,eAAe,cAA8B;EAC1D,IAAI,SAAS;AACb,MAAI,CAAC,OAAO,SAAS,mBAAmB,CACtC,QAAO;AAGT,WAAS,OAAO,MAAM,oBAAoB,CAAC;AAC3C,MAAI,OAAO,SAAS,OAAO,CACzB,UAAS,OAAO,MAAM,OAAO,CAAC;AAEhC,SAAO;;CAGT,aAAa;AACX,SAAO;;CAGT,YAAiC;AAC/B,SAAO;GACL,OAAO,KAAK,YAAY;GACxB,OAAO,KAAK,MAAM,WAAW;GAC7B,yBAAyB,KAAK,yBAAyB,KAAK,cAC1D,UAAU,WAAW,CACtB;GACD,eAAe,KAAK,cAAc,WAAW;GAC7C,eAAe,KAAK,cAAc,WAAW;GAC9C"}