@langchain/core
Version:
Core LangChain.js abstractions and schemas
161 lines (159 loc) • 5.55 kB
JavaScript
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
const require_index = require('../errors/index.cjs');
const mustache = require_rolldown_runtime.__toESM(require("mustache"));
//#region src/prompts/template.ts
function configureMustache() {
mustache.default.escape = (text) => text;
}
const parseFString = (template) => {
const chars = template.split("");
const nodes = [];
const nextBracket = (bracket, start) => {
for (let i$1 = start; i$1 < chars.length; i$1 += 1) if (bracket.includes(chars[i$1])) return i$1;
return -1;
};
let i = 0;
while (i < chars.length) if (chars[i] === "{" && i + 1 < chars.length && chars[i + 1] === "{") {
nodes.push({
type: "literal",
text: "{"
});
i += 2;
} else if (chars[i] === "}" && i + 1 < chars.length && chars[i + 1] === "}") {
nodes.push({
type: "literal",
text: "}"
});
i += 2;
} else if (chars[i] === "{") {
const j = nextBracket("}", i);
if (j < 0) throw new Error("Unclosed '{' in template.");
nodes.push({
type: "variable",
name: chars.slice(i + 1, j).join("")
});
i = j + 1;
} else if (chars[i] === "}") throw new Error("Single '}' in template.");
else {
const next = nextBracket("{}", i);
const text = (next < 0 ? chars.slice(i) : chars.slice(i, next)).join("");
nodes.push({
type: "literal",
text
});
i = next < 0 ? chars.length : next;
}
return nodes;
};
/**
* Convert the result of mustache.parse into an array of ParsedTemplateNode,
* to make it compatible with other LangChain string parsing template formats.
*
* @param {mustache.TemplateSpans} template The result of parsing a mustache template with the mustache.js library.
* @param {string[]} context Array of section variable names for nested context
* @returns {ParsedTemplateNode[]}
*/
const mustacheTemplateToNodes = (template, context = []) => {
const nodes = [];
for (const temp of template) if (temp[0] === "name") {
const name = temp[1].includes(".") ? temp[1].split(".")[0] : temp[1];
nodes.push({
type: "variable",
name
});
} else if ([
"#",
"&",
"^",
">"
].includes(temp[0])) {
nodes.push({
type: "variable",
name: temp[1]
});
if (temp[0] === "#" && temp.length > 4 && Array.isArray(temp[4])) {
const newContext = [...context, temp[1]];
const nestedNodes = mustacheTemplateToNodes(temp[4], newContext);
nodes.push(...nestedNodes);
}
} else nodes.push({
type: "literal",
text: temp[1]
});
return nodes;
};
const parseMustache = (template) => {
configureMustache();
const parsed = mustache.default.parse(template);
return mustacheTemplateToNodes(parsed);
};
const interpolateFString = (template, values) => {
return parseFString(template).reduce((res, node) => {
if (node.type === "variable") {
if (node.name in values) {
const stringValue = typeof values[node.name] === "string" ? values[node.name] : JSON.stringify(values[node.name]);
return res + stringValue;
}
throw new Error(`(f-string) Missing value for input ${node.name}`);
}
return res + node.text;
}, "");
};
const interpolateMustache = (template, values) => {
configureMustache();
return mustache.default.render(template, values);
};
const DEFAULT_FORMATTER_MAPPING = {
"f-string": interpolateFString,
mustache: interpolateMustache
};
const DEFAULT_PARSER_MAPPING = {
"f-string": parseFString,
mustache: parseMustache
};
const renderTemplate = (template, templateFormat, inputValues) => {
try {
return DEFAULT_FORMATTER_MAPPING[templateFormat](template, inputValues);
} catch (e) {
const error = require_index.addLangChainErrorFields(e, "INVALID_PROMPT_INPUT");
throw error;
}
};
const parseTemplate = (template, templateFormat) => DEFAULT_PARSER_MAPPING[templateFormat](template);
const checkValidTemplate = (template, templateFormat, inputVariables) => {
if (!(templateFormat in DEFAULT_FORMATTER_MAPPING)) {
const validFormats = Object.keys(DEFAULT_FORMATTER_MAPPING);
throw new Error(`Invalid template format. Got \`${templateFormat}\`;
should be one of ${validFormats}`);
}
try {
const dummyInputs = inputVariables.reduce((acc, v) => {
acc[v] = "foo";
return acc;
}, {});
if (Array.isArray(template)) template.forEach((message) => {
if (message.type === "text" && "text" in message && typeof message.text === "string") renderTemplate(message.text, templateFormat, dummyInputs);
else if (message.type === "image_url") {
if (typeof message.image_url === "string") renderTemplate(message.image_url, templateFormat, dummyInputs);
else if (typeof message.image_url === "object" && message.image_url !== null && "url" in message.image_url && typeof message.image_url.url === "string") {
const imageUrl = message.image_url.url;
renderTemplate(imageUrl, templateFormat, dummyInputs);
}
} else throw new Error(`Invalid message template received. ${JSON.stringify(message, null, 2)}`);
});
else renderTemplate(template, templateFormat, dummyInputs);
} catch (e) {
throw new Error(`Invalid prompt schema: ${e.message}`);
}
};
//#endregion
exports.DEFAULT_FORMATTER_MAPPING = DEFAULT_FORMATTER_MAPPING;
exports.DEFAULT_PARSER_MAPPING = DEFAULT_PARSER_MAPPING;
exports.checkValidTemplate = checkValidTemplate;
exports.interpolateFString = interpolateFString;
exports.interpolateMustache = interpolateMustache;
exports.parseFString = parseFString;
exports.parseMustache = parseMustache;
exports.parseTemplate = parseTemplate;
exports.renderTemplate = renderTemplate;
//# sourceMappingURL=template.cjs.map