diff --git a/langchain-core/src/prompts/template.ts b/langchain-core/src/prompts/template.ts index 6b308a1f8356..18a0761493a1 100644 --- a/langchain-core/src/prompts/template.ts +++ b/langchain-core/src/prompts/template.ts @@ -85,7 +85,9 @@ const mustacheTemplateToNodes = ( if (temp[0] === "name") { const name = temp[1].includes(".") ? temp[1].split(".")[0] : temp[1]; return { type: "variable", name }; - } else if (temp[0] === "#") { + } else if (["#", "&"].includes(temp[0])) { + // # represents a section, "&" represents an unescaped variable. + // These should both be considered variables. return { type: "variable", name: temp[1] }; } else { return { type: "literal", text: temp[1] }; diff --git a/langchain-core/src/prompts/tests/prompt.mustache.test.ts b/langchain-core/src/prompts/tests/prompt.mustache.test.ts index fad9a7c733f3..7bddf97b94e6 100644 --- a/langchain-core/src/prompts/tests/prompt.mustache.test.ts +++ b/langchain-core/src/prompts/tests/prompt.mustache.test.ts @@ -1,5 +1,6 @@ import { test, expect } from "@jest/globals"; import { PromptTemplate } from "../prompt.js"; +import { parseTemplate } from "../template.js"; test("Single input variable.", async () => { const template = "This is a {{foo}} test."; @@ -91,3 +92,24 @@ hello is a test.`); expect(promptWithRepeats.inputVariables).toEqual(["foo"]); }); + +test("Escaped variables", async () => { + const template = `test: {{{text}}}`; + const parsed = parseTemplate(template, "mustache"); + expect(parsed[0]).toStrictEqual({ + type: "literal", + text: "test: ", + }); + expect(parsed[1]).toStrictEqual({ + type: "variable", + name: "text", + }); + + const promptTemplate = PromptTemplate.fromTemplate(template, { + templateFormat: "mustache", + }); + const result = await promptTemplate.invoke({ + text: `hello i have a "quote`, + }); + expect(result.value).toBe(`test: hello i have a "quote`); +});