chat.cjs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. "use strict";
  2. // Default generic "any" values are for backwards compatibility.
  3. // Replace with "string" when we are comfortable with a breaking change.
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. exports.ChatPromptTemplate = exports.SystemMessagePromptTemplate = exports.AIMessagePromptTemplate = exports.HumanMessagePromptTemplate = exports.ChatMessagePromptTemplate = exports.BaseChatPromptTemplate = exports.BaseMessageStringPromptTemplate = exports.MessagesPlaceholder = exports.BaseMessagePromptTemplate = void 0;
  6. const index_js_1 = require("../messages/index.cjs");
  7. const prompt_values_js_1 = require("../prompt_values.cjs");
  8. const base_js_1 = require("../runnables/base.cjs");
  9. const string_js_1 = require("./string.cjs");
  10. const base_js_2 = require("./base.cjs");
  11. const prompt_js_1 = require("./prompt.cjs");
  12. const image_js_1 = require("./image.cjs");
  13. const template_js_1 = require("./template.cjs");
  14. const index_js_2 = require("../errors/index.cjs");
  15. const dict_js_1 = require("./dict.cjs");
  16. /**
  17. * Abstract class that serves as a base for creating message prompt
  18. * templates. It defines how to format messages for different roles in a
  19. * conversation.
  20. */
  21. class BaseMessagePromptTemplate extends base_js_1.Runnable {
  22. constructor() {
  23. super(...arguments);
  24. Object.defineProperty(this, "lc_namespace", {
  25. enumerable: true,
  26. configurable: true,
  27. writable: true,
  28. value: ["langchain_core", "prompts", "chat"]
  29. });
  30. Object.defineProperty(this, "lc_serializable", {
  31. enumerable: true,
  32. configurable: true,
  33. writable: true,
  34. value: true
  35. });
  36. }
  37. /**
  38. * Calls the formatMessages method with the provided input and options.
  39. * @param input Input for the formatMessages method
  40. * @param options Optional BaseCallbackConfig
  41. * @returns Formatted output messages
  42. */
  43. async invoke(input, options) {
  44. return this._callWithConfig((input) => this.formatMessages(input), input, { ...options, runType: "prompt" });
  45. }
  46. }
  47. exports.BaseMessagePromptTemplate = BaseMessagePromptTemplate;
  48. /**
  49. * Class that represents a placeholder for messages in a chat prompt. It
  50. * extends the BaseMessagePromptTemplate.
  51. */
  52. class MessagesPlaceholder extends BaseMessagePromptTemplate {
  53. static lc_name() {
  54. return "MessagesPlaceholder";
  55. }
  56. constructor(fields) {
  57. if (typeof fields === "string") {
  58. // eslint-disable-next-line no-param-reassign
  59. fields = { variableName: fields };
  60. }
  61. super(fields);
  62. Object.defineProperty(this, "variableName", {
  63. enumerable: true,
  64. configurable: true,
  65. writable: true,
  66. value: void 0
  67. });
  68. Object.defineProperty(this, "optional", {
  69. enumerable: true,
  70. configurable: true,
  71. writable: true,
  72. value: void 0
  73. });
  74. this.variableName = fields.variableName;
  75. this.optional = fields.optional ?? false;
  76. }
  77. get inputVariables() {
  78. return [this.variableName];
  79. }
  80. async formatMessages(values) {
  81. const input = values[this.variableName];
  82. if (this.optional && !input) {
  83. return [];
  84. }
  85. else if (!input) {
  86. const error = new Error(`Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages as an input value. Received: undefined`);
  87. error.name = "InputFormatError";
  88. throw error;
  89. }
  90. let formattedMessages;
  91. try {
  92. if (Array.isArray(input)) {
  93. formattedMessages = input.map(index_js_1.coerceMessageLikeToMessage);
  94. }
  95. else {
  96. formattedMessages = [(0, index_js_1.coerceMessageLikeToMessage)(input)];
  97. }
  98. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  99. }
  100. catch (e) {
  101. const readableInput = typeof input === "string" ? input : JSON.stringify(input, null, 2);
  102. const error = new Error([
  103. `Field "${this.variableName}" in prompt uses a MessagesPlaceholder, which expects an array of BaseMessages or coerceable values as input.`,
  104. `Received value: ${readableInput}`,
  105. `Additional message: ${e.message}`,
  106. ].join("\n\n"));
  107. error.name = "InputFormatError";
  108. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  109. error.lc_error_code = e.lc_error_code;
  110. throw error;
  111. }
  112. return formattedMessages;
  113. }
  114. }
  115. exports.MessagesPlaceholder = MessagesPlaceholder;
  116. /**
  117. * Abstract class that serves as a base for creating message string prompt
  118. * templates. It extends the BaseMessagePromptTemplate.
  119. */
  120. class BaseMessageStringPromptTemplate extends BaseMessagePromptTemplate {
  121. constructor(fields) {
  122. if (!("prompt" in fields)) {
  123. // eslint-disable-next-line no-param-reassign
  124. fields = { prompt: fields };
  125. }
  126. super(fields);
  127. Object.defineProperty(this, "prompt", {
  128. enumerable: true,
  129. configurable: true,
  130. writable: true,
  131. value: void 0
  132. });
  133. this.prompt = fields.prompt;
  134. }
  135. get inputVariables() {
  136. return this.prompt.inputVariables;
  137. }
  138. async formatMessages(values) {
  139. return [await this.format(values)];
  140. }
  141. }
  142. exports.BaseMessageStringPromptTemplate = BaseMessageStringPromptTemplate;
  143. /**
  144. * Abstract class that serves as a base for creating chat prompt
  145. * templates. It extends the BasePromptTemplate.
  146. */
  147. class BaseChatPromptTemplate extends base_js_2.BasePromptTemplate {
  148. constructor(input) {
  149. super(input);
  150. }
  151. async format(values) {
  152. return (await this.formatPromptValue(values)).toString();
  153. }
  154. async formatPromptValue(values) {
  155. const resultMessages = await this.formatMessages(values);
  156. return new prompt_values_js_1.ChatPromptValue(resultMessages);
  157. }
  158. }
  159. exports.BaseChatPromptTemplate = BaseChatPromptTemplate;
  160. /**
  161. * Class that represents a chat message prompt template. It extends the
  162. * BaseMessageStringPromptTemplate.
  163. */
  164. class ChatMessagePromptTemplate extends BaseMessageStringPromptTemplate {
  165. static lc_name() {
  166. return "ChatMessagePromptTemplate";
  167. }
  168. constructor(fields, role) {
  169. if (!("prompt" in fields)) {
  170. // eslint-disable-next-line no-param-reassign, @typescript-eslint/no-non-null-assertion
  171. fields = { prompt: fields, role: role };
  172. }
  173. super(fields);
  174. Object.defineProperty(this, "role", {
  175. enumerable: true,
  176. configurable: true,
  177. writable: true,
  178. value: void 0
  179. });
  180. this.role = fields.role;
  181. }
  182. async format(values) {
  183. return new index_js_1.ChatMessage(await this.prompt.format(values), this.role);
  184. }
  185. static fromTemplate(template, role, options) {
  186. return new this(prompt_js_1.PromptTemplate.fromTemplate(template, {
  187. templateFormat: options?.templateFormat,
  188. }), role);
  189. }
  190. }
  191. exports.ChatMessagePromptTemplate = ChatMessagePromptTemplate;
  192. function isTextTemplateParam(param) {
  193. if (param === null || typeof param !== "object" || Array.isArray(param)) {
  194. return false;
  195. }
  196. return (Object.keys(param).length === 1 &&
  197. "text" in param &&
  198. typeof param.text === "string");
  199. }
  200. function isImageTemplateParam(param) {
  201. if (param === null || typeof param !== "object" || Array.isArray(param)) {
  202. return false;
  203. }
  204. return ("image_url" in param &&
  205. (typeof param.image_url === "string" ||
  206. (typeof param.image_url === "object" &&
  207. param.image_url !== null &&
  208. "url" in param.image_url &&
  209. typeof param.image_url.url === "string")));
  210. }
  211. class _StringImageMessagePromptTemplate extends BaseMessagePromptTemplate {
  212. static _messageClass() {
  213. throw new Error("Can not invoke _messageClass from inside _StringImageMessagePromptTemplate");
  214. }
  215. constructor(
  216. /** @TODO When we come up with a better way to type prompt templates, fix this */
  217. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  218. fields, additionalOptions) {
  219. if (!("prompt" in fields)) {
  220. // eslint-disable-next-line no-param-reassign
  221. fields = { prompt: fields };
  222. }
  223. super(fields);
  224. Object.defineProperty(this, "lc_namespace", {
  225. enumerable: true,
  226. configurable: true,
  227. writable: true,
  228. value: ["langchain_core", "prompts", "chat"]
  229. });
  230. Object.defineProperty(this, "lc_serializable", {
  231. enumerable: true,
  232. configurable: true,
  233. writable: true,
  234. value: true
  235. });
  236. Object.defineProperty(this, "inputVariables", {
  237. enumerable: true,
  238. configurable: true,
  239. writable: true,
  240. value: []
  241. });
  242. Object.defineProperty(this, "additionalOptions", {
  243. enumerable: true,
  244. configurable: true,
  245. writable: true,
  246. value: {}
  247. });
  248. Object.defineProperty(this, "prompt", {
  249. enumerable: true,
  250. configurable: true,
  251. writable: true,
  252. value: void 0
  253. });
  254. Object.defineProperty(this, "messageClass", {
  255. enumerable: true,
  256. configurable: true,
  257. writable: true,
  258. value: void 0
  259. });
  260. // ChatMessage contains role field, others don't.
  261. // Because of this, we have a separate class property for ChatMessage.
  262. Object.defineProperty(this, "chatMessageClass", {
  263. enumerable: true,
  264. configurable: true,
  265. writable: true,
  266. value: void 0
  267. });
  268. this.prompt = fields.prompt;
  269. if (Array.isArray(this.prompt)) {
  270. let inputVariables = [];
  271. this.prompt.forEach((prompt) => {
  272. if ("inputVariables" in prompt) {
  273. inputVariables = inputVariables.concat(prompt.inputVariables);
  274. }
  275. });
  276. this.inputVariables = inputVariables;
  277. }
  278. else {
  279. this.inputVariables = this.prompt.inputVariables;
  280. }
  281. this.additionalOptions = additionalOptions ?? this.additionalOptions;
  282. }
  283. createMessage(content) {
  284. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  285. const constructor = this.constructor;
  286. if (constructor._messageClass()) {
  287. const MsgClass = constructor._messageClass();
  288. return new MsgClass({ content });
  289. }
  290. else if (constructor.chatMessageClass) {
  291. const MsgClass = constructor.chatMessageClass();
  292. // Assuming ChatMessage constructor also takes a content argument
  293. return new MsgClass({
  294. content,
  295. role: this.getRoleFromMessageClass(MsgClass.lc_name()),
  296. });
  297. }
  298. else {
  299. throw new Error("No message class defined");
  300. }
  301. }
  302. getRoleFromMessageClass(name) {
  303. switch (name) {
  304. case "HumanMessage":
  305. return "human";
  306. case "AIMessage":
  307. return "ai";
  308. case "SystemMessage":
  309. return "system";
  310. case "ChatMessage":
  311. return "chat";
  312. default:
  313. throw new Error("Invalid message class name");
  314. }
  315. }
  316. static fromTemplate(template, additionalOptions) {
  317. if (typeof template === "string") {
  318. return new this(prompt_js_1.PromptTemplate.fromTemplate(template, additionalOptions));
  319. }
  320. const prompt = [];
  321. for (const item of template) {
  322. // handle string cases
  323. if (typeof item === "string") {
  324. prompt.push(prompt_js_1.PromptTemplate.fromTemplate(item, additionalOptions));
  325. }
  326. else if (item === null) {
  327. // pass
  328. }
  329. else if (isTextTemplateParam(item)) {
  330. let text = "";
  331. if (typeof item.text === "string") {
  332. text = item.text ?? "";
  333. }
  334. const options = {
  335. ...additionalOptions,
  336. additionalContentFields: item,
  337. };
  338. prompt.push(prompt_js_1.PromptTemplate.fromTemplate(text, options));
  339. }
  340. else if (isImageTemplateParam(item)) {
  341. let imgTemplate = item.image_url ?? "";
  342. let imgTemplateObject;
  343. let inputVariables = [];
  344. if (typeof imgTemplate === "string") {
  345. let parsedTemplate;
  346. if (additionalOptions?.templateFormat === "mustache") {
  347. parsedTemplate = (0, template_js_1.parseMustache)(imgTemplate);
  348. }
  349. else {
  350. parsedTemplate = (0, template_js_1.parseFString)(imgTemplate);
  351. }
  352. const variables = parsedTemplate.flatMap((item) => item.type === "variable" ? [item.name] : []);
  353. if ((variables?.length ?? 0) > 0) {
  354. if (variables.length > 1) {
  355. throw new Error(`Only one format variable allowed per image template.\nGot: ${variables}\nFrom: ${imgTemplate}`);
  356. }
  357. inputVariables = [variables[0]];
  358. }
  359. else {
  360. inputVariables = [];
  361. }
  362. imgTemplate = { url: imgTemplate };
  363. imgTemplateObject = new image_js_1.ImagePromptTemplate({
  364. template: imgTemplate,
  365. inputVariables,
  366. templateFormat: additionalOptions?.templateFormat,
  367. additionalContentFields: item,
  368. });
  369. }
  370. else if (typeof imgTemplate === "object") {
  371. if ("url" in imgTemplate) {
  372. let parsedTemplate;
  373. if (additionalOptions?.templateFormat === "mustache") {
  374. parsedTemplate = (0, template_js_1.parseMustache)(imgTemplate.url);
  375. }
  376. else {
  377. parsedTemplate = (0, template_js_1.parseFString)(imgTemplate.url);
  378. }
  379. inputVariables = parsedTemplate.flatMap((item) => item.type === "variable" ? [item.name] : []);
  380. }
  381. else {
  382. inputVariables = [];
  383. }
  384. imgTemplateObject = new image_js_1.ImagePromptTemplate({
  385. template: imgTemplate,
  386. inputVariables,
  387. templateFormat: additionalOptions?.templateFormat,
  388. additionalContentFields: item,
  389. });
  390. }
  391. else {
  392. throw new Error("Invalid image template");
  393. }
  394. prompt.push(imgTemplateObject);
  395. }
  396. else if (typeof item === "object") {
  397. prompt.push(new dict_js_1.DictPromptTemplate({
  398. template: item,
  399. templateFormat: additionalOptions?.templateFormat,
  400. }));
  401. }
  402. }
  403. return new this({ prompt, additionalOptions });
  404. }
  405. async format(input) {
  406. // eslint-disable-next-line no-instanceof/no-instanceof
  407. if (this.prompt instanceof string_js_1.BaseStringPromptTemplate) {
  408. const text = await this.prompt.format(input);
  409. return this.createMessage(text);
  410. }
  411. else {
  412. const content = [];
  413. for (const prompt of this.prompt) {
  414. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  415. let inputs = {};
  416. if (!("inputVariables" in prompt)) {
  417. throw new Error(`Prompt ${prompt} does not have inputVariables defined.`);
  418. }
  419. for (const item of prompt.inputVariables) {
  420. if (!inputs) {
  421. inputs = { [item]: input[item] };
  422. }
  423. inputs = { ...inputs, [item]: input[item] };
  424. }
  425. // eslint-disable-next-line no-instanceof/no-instanceof
  426. if (prompt instanceof string_js_1.BaseStringPromptTemplate) {
  427. const formatted = await prompt.format(inputs);
  428. let additionalContentFields;
  429. if ("additionalContentFields" in prompt) {
  430. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  431. additionalContentFields = prompt.additionalContentFields;
  432. }
  433. content.push({
  434. ...additionalContentFields,
  435. type: "text",
  436. text: formatted,
  437. });
  438. /** @TODO replace this */
  439. // eslint-disable-next-line no-instanceof/no-instanceof
  440. }
  441. else if (prompt instanceof image_js_1.ImagePromptTemplate) {
  442. const formatted = await prompt.format(inputs);
  443. let additionalContentFields;
  444. if ("additionalContentFields" in prompt) {
  445. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  446. additionalContentFields = prompt.additionalContentFields;
  447. }
  448. content.push({
  449. ...additionalContentFields,
  450. type: "image_url",
  451. image_url: formatted,
  452. });
  453. // eslint-disable-next-line no-instanceof/no-instanceof
  454. }
  455. else if (prompt instanceof dict_js_1.DictPromptTemplate) {
  456. const formatted = await prompt.format(inputs);
  457. let additionalContentFields;
  458. if ("additionalContentFields" in prompt) {
  459. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  460. additionalContentFields = prompt.additionalContentFields;
  461. }
  462. content.push({
  463. ...additionalContentFields,
  464. ...formatted,
  465. });
  466. }
  467. }
  468. return this.createMessage(content);
  469. }
  470. }
  471. async formatMessages(values) {
  472. return [await this.format(values)];
  473. }
  474. }
  475. /**
  476. * Class that represents a human message prompt template. It extends the
  477. * BaseMessageStringPromptTemplate.
  478. * @example
  479. * ```typescript
  480. * const message = HumanMessagePromptTemplate.fromTemplate("{text}");
  481. * const formatted = await message.format({ text: "Hello world!" });
  482. *
  483. * const chatPrompt = ChatPromptTemplate.fromMessages([message]);
  484. * const formattedChatPrompt = await chatPrompt.invoke({
  485. * text: "Hello world!",
  486. * });
  487. * ```
  488. */
  489. class HumanMessagePromptTemplate extends _StringImageMessagePromptTemplate {
  490. static _messageClass() {
  491. return index_js_1.HumanMessage;
  492. }
  493. static lc_name() {
  494. return "HumanMessagePromptTemplate";
  495. }
  496. }
  497. exports.HumanMessagePromptTemplate = HumanMessagePromptTemplate;
  498. /**
  499. * Class that represents an AI message prompt template. It extends the
  500. * BaseMessageStringPromptTemplate.
  501. */
  502. class AIMessagePromptTemplate extends _StringImageMessagePromptTemplate {
  503. static _messageClass() {
  504. return index_js_1.AIMessage;
  505. }
  506. static lc_name() {
  507. return "AIMessagePromptTemplate";
  508. }
  509. }
  510. exports.AIMessagePromptTemplate = AIMessagePromptTemplate;
  511. /**
  512. * Class that represents a system message prompt template. It extends the
  513. * BaseMessageStringPromptTemplate.
  514. * @example
  515. * ```typescript
  516. * const message = SystemMessagePromptTemplate.fromTemplate("{text}");
  517. * const formatted = await message.format({ text: "Hello world!" });
  518. *
  519. * const chatPrompt = ChatPromptTemplate.fromMessages([message]);
  520. * const formattedChatPrompt = await chatPrompt.invoke({
  521. * text: "Hello world!",
  522. * });
  523. * ```
  524. */
  525. class SystemMessagePromptTemplate extends _StringImageMessagePromptTemplate {
  526. static _messageClass() {
  527. return index_js_1.SystemMessage;
  528. }
  529. static lc_name() {
  530. return "SystemMessagePromptTemplate";
  531. }
  532. }
  533. exports.SystemMessagePromptTemplate = SystemMessagePromptTemplate;
  534. function _isBaseMessagePromptTemplate(baseMessagePromptTemplateLike) {
  535. return (typeof baseMessagePromptTemplateLike
  536. .formatMessages === "function");
  537. }
  538. function _coerceMessagePromptTemplateLike(messagePromptTemplateLike, extra) {
  539. if (_isBaseMessagePromptTemplate(messagePromptTemplateLike) ||
  540. (0, index_js_1.isBaseMessage)(messagePromptTemplateLike)) {
  541. return messagePromptTemplateLike;
  542. }
  543. if (Array.isArray(messagePromptTemplateLike) &&
  544. messagePromptTemplateLike[0] === "placeholder") {
  545. const messageContent = messagePromptTemplateLike[1];
  546. if (extra?.templateFormat === "mustache" &&
  547. typeof messageContent === "string" &&
  548. messageContent.slice(0, 2) === "{{" &&
  549. messageContent.slice(-2) === "}}") {
  550. const variableName = messageContent.slice(2, -2);
  551. return new MessagesPlaceholder({ variableName, optional: true });
  552. }
  553. else if (typeof messageContent === "string" &&
  554. messageContent[0] === "{" &&
  555. messageContent[messageContent.length - 1] === "}") {
  556. const variableName = messageContent.slice(1, -1);
  557. return new MessagesPlaceholder({ variableName, optional: true });
  558. }
  559. throw new Error(`Invalid placeholder template for format ${extra?.templateFormat ?? `"f-string"`}: "${messagePromptTemplateLike[1]}". Expected a variable name surrounded by ${extra?.templateFormat === "mustache" ? "double" : "single"} curly braces.`);
  560. }
  561. const message = (0, index_js_1.coerceMessageLikeToMessage)(messagePromptTemplateLike);
  562. let templateData;
  563. if (typeof message.content === "string") {
  564. templateData = message.content;
  565. }
  566. else {
  567. // Assuming message.content is an array of complex objects, transform it.
  568. templateData = message.content.map((item) => {
  569. if ("text" in item) {
  570. return { ...item, text: item.text };
  571. }
  572. else if ("image_url" in item) {
  573. return { ...item, image_url: item.image_url };
  574. }
  575. else {
  576. return item;
  577. }
  578. });
  579. }
  580. if (message._getType() === "human") {
  581. return HumanMessagePromptTemplate.fromTemplate(templateData, extra);
  582. }
  583. else if (message._getType() === "ai") {
  584. return AIMessagePromptTemplate.fromTemplate(templateData, extra);
  585. }
  586. else if (message._getType() === "system") {
  587. return SystemMessagePromptTemplate.fromTemplate(templateData, extra);
  588. }
  589. else if (index_js_1.ChatMessage.isInstance(message)) {
  590. return ChatMessagePromptTemplate.fromTemplate(message.content, message.role, extra);
  591. }
  592. else {
  593. throw new Error(`Could not coerce message prompt template from input. Received message type: "${message._getType()}".`);
  594. }
  595. }
  596. function isMessagesPlaceholder(x) {
  597. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  598. return x.constructor.lc_name() === "MessagesPlaceholder";
  599. }
  600. /**
  601. * Class that represents a chat prompt. It extends the
  602. * BaseChatPromptTemplate and uses an array of BaseMessagePromptTemplate
  603. * instances to format a series of messages for a conversation.
  604. * @example
  605. * ```typescript
  606. * const message = SystemMessagePromptTemplate.fromTemplate("{text}");
  607. * const chatPrompt = ChatPromptTemplate.fromMessages([
  608. * ["ai", "You are a helpful assistant."],
  609. * message,
  610. * ]);
  611. * const formattedChatPrompt = await chatPrompt.invoke({
  612. * text: "Hello world!",
  613. * });
  614. * ```
  615. */
  616. class ChatPromptTemplate extends BaseChatPromptTemplate {
  617. static lc_name() {
  618. return "ChatPromptTemplate";
  619. }
  620. get lc_aliases() {
  621. return {
  622. promptMessages: "messages",
  623. };
  624. }
  625. constructor(input) {
  626. super(input);
  627. Object.defineProperty(this, "promptMessages", {
  628. enumerable: true,
  629. configurable: true,
  630. writable: true,
  631. value: void 0
  632. });
  633. Object.defineProperty(this, "validateTemplate", {
  634. enumerable: true,
  635. configurable: true,
  636. writable: true,
  637. value: true
  638. });
  639. Object.defineProperty(this, "templateFormat", {
  640. enumerable: true,
  641. configurable: true,
  642. writable: true,
  643. value: "f-string"
  644. });
  645. // If input is mustache and validateTemplate is not defined, set it to false
  646. if (input.templateFormat === "mustache" &&
  647. input.validateTemplate === undefined) {
  648. this.validateTemplate = false;
  649. }
  650. Object.assign(this, input);
  651. if (this.validateTemplate) {
  652. const inputVariablesMessages = new Set();
  653. for (const promptMessage of this.promptMessages) {
  654. // eslint-disable-next-line no-instanceof/no-instanceof
  655. if (promptMessage instanceof index_js_1.BaseMessage)
  656. continue;
  657. for (const inputVariable of promptMessage.inputVariables) {
  658. inputVariablesMessages.add(inputVariable);
  659. }
  660. }
  661. const totalInputVariables = this.inputVariables;
  662. const inputVariablesInstance = new Set(this.partialVariables
  663. ? totalInputVariables.concat(Object.keys(this.partialVariables))
  664. : totalInputVariables);
  665. const difference = new Set([...inputVariablesInstance].filter((x) => !inputVariablesMessages.has(x)));
  666. if (difference.size > 0) {
  667. throw new Error(`Input variables \`${[
  668. ...difference,
  669. ]}\` are not used in any of the prompt messages.`);
  670. }
  671. const otherDifference = new Set([...inputVariablesMessages].filter((x) => !inputVariablesInstance.has(x)));
  672. if (otherDifference.size > 0) {
  673. throw new Error(`Input variables \`${[
  674. ...otherDifference,
  675. ]}\` are used in prompt messages but not in the prompt template.`);
  676. }
  677. }
  678. }
  679. _getPromptType() {
  680. return "chat";
  681. }
  682. async _parseImagePrompts(message, inputValues) {
  683. if (typeof message.content === "string") {
  684. return message;
  685. }
  686. const formattedMessageContent = await Promise.all(message.content.map(async (item) => {
  687. if (item.type !== "image_url") {
  688. return item;
  689. }
  690. let imageUrl = "";
  691. if (typeof item.image_url === "string") {
  692. imageUrl = item.image_url;
  693. }
  694. else {
  695. imageUrl = item.image_url.url;
  696. }
  697. const promptTemplatePlaceholder = prompt_js_1.PromptTemplate.fromTemplate(imageUrl, {
  698. templateFormat: this.templateFormat,
  699. });
  700. const formattedUrl = await promptTemplatePlaceholder.format(inputValues);
  701. if (typeof item.image_url !== "string" && "url" in item.image_url) {
  702. // eslint-disable-next-line no-param-reassign
  703. item.image_url.url = formattedUrl;
  704. }
  705. else {
  706. // eslint-disable-next-line no-param-reassign
  707. item.image_url = formattedUrl;
  708. }
  709. return item;
  710. }));
  711. // eslint-disable-next-line no-param-reassign
  712. message.content = formattedMessageContent;
  713. return message;
  714. }
  715. async formatMessages(values) {
  716. const allValues = await this.mergePartialAndUserVariables(values);
  717. let resultMessages = [];
  718. for (const promptMessage of this.promptMessages) {
  719. // eslint-disable-next-line no-instanceof/no-instanceof
  720. if (promptMessage instanceof index_js_1.BaseMessage) {
  721. resultMessages.push(await this._parseImagePrompts(promptMessage, allValues));
  722. }
  723. else {
  724. const inputValues = promptMessage.inputVariables.reduce((acc, inputVariable) => {
  725. if (!(inputVariable in allValues) &&
  726. !(isMessagesPlaceholder(promptMessage) && promptMessage.optional)) {
  727. const error = (0, index_js_2.addLangChainErrorFields)(new Error(`Missing value for input variable \`${inputVariable.toString()}\``), "INVALID_PROMPT_INPUT");
  728. throw error;
  729. }
  730. acc[inputVariable] = allValues[inputVariable];
  731. return acc;
  732. }, {});
  733. const message = await promptMessage.formatMessages(inputValues);
  734. resultMessages = resultMessages.concat(message);
  735. }
  736. }
  737. return resultMessages;
  738. }
  739. async partial(values) {
  740. // This is implemented in a way it doesn't require making
  741. // BaseMessagePromptTemplate aware of .partial()
  742. const newInputVariables = this.inputVariables.filter((iv) => !(iv in values));
  743. const newPartialVariables = {
  744. ...(this.partialVariables ?? {}),
  745. ...values,
  746. };
  747. const promptDict = {
  748. ...this,
  749. inputVariables: newInputVariables,
  750. partialVariables: newPartialVariables,
  751. };
  752. return new ChatPromptTemplate(promptDict);
  753. }
  754. static fromTemplate(template, options) {
  755. const prompt = prompt_js_1.PromptTemplate.fromTemplate(template, options);
  756. const humanTemplate = new HumanMessagePromptTemplate({ prompt });
  757. return this.fromMessages([humanTemplate]);
  758. }
  759. /**
  760. * Create a chat model-specific prompt from individual chat messages
  761. * or message-like tuples.
  762. * @param promptMessages Messages to be passed to the chat model
  763. * @returns A new ChatPromptTemplate
  764. */
  765. static fromMessages(promptMessages, extra) {
  766. const flattenedMessages = promptMessages.reduce((acc, promptMessage) => acc.concat(
  767. // eslint-disable-next-line no-instanceof/no-instanceof
  768. promptMessage instanceof ChatPromptTemplate
  769. ? promptMessage.promptMessages
  770. : [
  771. _coerceMessagePromptTemplateLike(promptMessage, extra),
  772. ]), []);
  773. const flattenedPartialVariables = promptMessages.reduce((acc, promptMessage) =>
  774. // eslint-disable-next-line no-instanceof/no-instanceof
  775. promptMessage instanceof ChatPromptTemplate
  776. ? Object.assign(acc, promptMessage.partialVariables)
  777. : acc, Object.create(null));
  778. const inputVariables = new Set();
  779. for (const promptMessage of flattenedMessages) {
  780. // eslint-disable-next-line no-instanceof/no-instanceof
  781. if (promptMessage instanceof index_js_1.BaseMessage)
  782. continue;
  783. for (const inputVariable of promptMessage.inputVariables) {
  784. if (inputVariable in flattenedPartialVariables) {
  785. continue;
  786. }
  787. inputVariables.add(inputVariable);
  788. }
  789. }
  790. return new this({
  791. ...extra,
  792. inputVariables: [...inputVariables],
  793. promptMessages: flattenedMessages,
  794. partialVariables: flattenedPartialVariables,
  795. templateFormat: extra?.templateFormat,
  796. });
  797. }
  798. /** @deprecated Renamed to .fromMessages */
  799. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  800. static fromPromptMessages(promptMessages) {
  801. return this.fromMessages(promptMessages);
  802. }
  803. }
  804. exports.ChatPromptTemplate = ChatPromptTemplate;