-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
handlebars.ts
95 lines (89 loc) · 3.05 KB
/
handlebars.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import Handlebars from "handlebars";
import { type ParsedFStringNode } from "@langchain/core/prompts";
import type { InputValues } from "@langchain/core/utils/types";
import {
CustomFormatPromptTemplate,
CustomFormatPromptTemplateInput,
} from "./custom_format.js";
export const parseHandlebars = (template: string): ParsedFStringNode[] => {
const parsed: ParsedFStringNode[] = [];
const nodes: { type: string }[] = [...Handlebars.parse(template).body];
while (nodes.length) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const node = nodes.pop()!;
if (node.type === "ContentStatement") {
// @ts-expect-error - handlebars' hbs.AST.ContentStatement isn't exported
const text = node.value;
parsed.push({ type: "literal", text });
} else if (node.type === "MustacheStatement") {
// @ts-expect-error - handlebars' hbs.AST.MustacheStatement isn't exported
const name: string = node.path.parts[0];
// @ts-expect-error - handlebars' hbs.AST.MustacheStatement isn't exported
const { original } = node.path as { original: string };
if (
!!name &&
!original.startsWith("this.") &&
!original.startsWith("@")
) {
parsed.push({ type: "variable", name });
}
} else if (node.type === "PathExpression") {
// @ts-expect-error - handlebars' hbs.AST.PathExpression isn't exported
const name: string = node.parts[0];
// @ts-expect-error - handlebars' hbs.AST.PathExpression isn't exported
const { original } = node;
if (
!!name &&
!original.startsWith("this.") &&
!original.startsWith("@")
) {
parsed.push({ type: "variable", name });
}
} else if (node.type === "BlockStatement") {
// @ts-expect-error - handlebars' hbs.AST.BlockStatement isn't exported
nodes.push(...node.params, ...node.program.body);
}
}
return parsed;
};
export const interpolateHandlebars = (
template: string,
values: InputValues
) => {
const compiled = Handlebars.compile(template, { noEscape: true });
return compiled(values);
};
export type HandlebarsPromptTemplateInput<RunInput extends InputValues> =
CustomFormatPromptTemplateInput<RunInput>;
export class HandlebarsPromptTemplate<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
RunInput extends InputValues = any
> extends CustomFormatPromptTemplate<RunInput> {
static lc_name() {
return "HandlebarsPromptTemplate";
}
/**
* Load prompt template from a template
*/
static fromTemplate<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
RunInput extends InputValues = Record<string, any>
>(
template: string,
params?: Omit<
HandlebarsPromptTemplateInput<RunInput>,
| "template"
| "inputVariables"
| "customParser"
| "templateValidator"
| "renderer"
>
) {
return super.fromTemplate<RunInput>(template, {
...params,
validateTemplate: false,
customParser: parseHandlebars,
renderer: interpolateHandlebars,
});
}
}