-
Notifications
You must be signed in to change notification settings - Fork 0
/
PromptTemplate.ts
174 lines (148 loc) · 5.84 KB
/
PromptTemplate.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import { ApplicationError } from '../../../errors/ApplicationError';
/**
* Defines a set of available prompt template variables.
*/
export enum PromptTemplateVariables {
PERSONA_DESCRIPTION = '{{PERSONA_DESCRIPTION}}',
PERSONA_NAME = '{{PERSONA_NAME}}',
USER_NAME = '{{USER_NAME}}',
QUESTIONNAIRE = '{{QUESTIONNAIRE}}',
LAST_CHAT_MESSAGE = '{{LAST_CHAT_MESSAGE}}',
SUMMARIZED_MESSAGES = '{{SUMMARIZED_MESSAGES}}',
CONVERSATION_MESSAGES = '{{CONVERSATION_MESSAGES}}',
INSTRUCTION = '{{INSTRUCTION}}',
OUTPUT_FORMAT = '{{OUTPUT_FORMAT}}',
CONVERSATION_EXAMPLE = '{{CONVERSATION_EXAMPLE}}',
}
function fromStringToPromptTemplateVariableEnum(variable: string) {
switch (variable) {
case '{{PERSONA_DESCRIPTION}}': return PromptTemplateVariables.PERSONA_DESCRIPTION;
case '{{PERSONA_NAME}}': return PromptTemplateVariables.PERSONA_NAME;
case '{{USER_NAME}}': return PromptTemplateVariables.USER_NAME;
case '{{QUESTIONNAIRE}}': return PromptTemplateVariables.QUESTIONNAIRE;
case '{{LAST_CHAT_MESSAGE}}': return PromptTemplateVariables.LAST_CHAT_MESSAGE;
case '{{SUMMARIZED_MESSAGES}}': return PromptTemplateVariables.SUMMARIZED_MESSAGES;
case '{{CONVERSATION_MESSAGES}}': return PromptTemplateVariables.CONVERSATION_MESSAGES;
case '{{INSTRUCTION}}': return PromptTemplateVariables.INSTRUCTION;
case '{{OUTPUT_FORMAT}}': return PromptTemplateVariables.OUTPUT_FORMAT;
case '{{CONVERSATION_EXAMPLE}}': return PromptTemplateVariables.CONVERSATION_EXAMPLE;
default: throw new ApplicationError(`Provided variable '${variable}' cannot be converted to enum`)
}
}
/**
* Serves as a sentinel for secure prompt template modifications and variable populations.
* Implements Builder Design Pattern.
* </br>
* @example
* ```typescript
* const promptTemplate = PromptTemplate(myTemplate);
*
* const populatedPrompt = promptTemplate
* .set(PromptTemplateVariables.PERSONA, "Persona definition here")
* .set(PromptTemplateVariables.INSTRUCTION, "Instruction")
* .build();
* ```
*/
export class PromptTemplate {
private static readonly variableRegex = /(\{\{\w*}})/g;
private readonly template: string;
private readonly variableAssignments: Map<PromptTemplateVariables, string> = new Map();
/**
* Creates an instance of `PromptTemplate`.
* Requires `template` to have only variables present in `PromptTemplateVariables`.
*
* @param template template which will be populated via `set` commands.
*/
constructor(template: string) {
PromptTemplate.validateTemplate(template);
this.template = template;
}
/**
* Asserts that the variable is present in the stored template and associates this variable
* with the provided value.
* </br>
* Subsequent calls will apply the <b>value of the last call</b>.
*
* @param variable variable to set
* @param value value to set
*/
set(variable: PromptTemplateVariables, value: string): PromptTemplate {
if (!this.has(variable)) {
throw new ApplicationError(`Variable '${variable}' is not present in the prompt template`)
}
this.variableAssignments.set(variable, value);
return this
}
/**
* Checks whether the provided variable is present in the stored prompt template.
*
* @param variable variable the entry of which to check
*/
has(variable: PromptTemplateVariables): boolean {
return this.template.includes(variable as string)
}
/**
* Builds a prompt populated with the values associated with variables previously provided by `set` method.
* <br/>
* Requires that all variables present in the prompt to have an associated value.
*
* @return populated prompt
*/
build(): string {
let builtPrompt = this.template;
const variables = PromptTemplate.collectPromptTemplateVariables(this.template);
for (const variable of variables) {
const enumVariable = fromStringToPromptTemplateVariableEnum(variable);
if (!this.variableAssignments.has(enumVariable)) {
throw new ApplicationError(`Variable '${variable}' is not set but present in the template`);
}
const value = this.variableAssignments.get(enumVariable)!;
// replace multiple occurrences of variable
const variableRegex = new RegExp(variable, 'g');
builtPrompt = builtPrompt.replace(variableRegex, value);
}
return builtPrompt;
}
/**
* Checks that template has only variables registered in enum `PromptTemplateVariables`.
*
* @param template template variables of which to check
* @private
*/
private static validateTemplate(template: string) {
const variables = PromptTemplate.collectPromptTemplateVariables(template)
variables.forEach(usedVariable => {
let found = false;
for (const registeredVariable in PromptTemplateVariables) {
// transforms the enum entry name into its value
// e.g., PERSONA_DESCRIPTION -> {{PERSONA_DESCRIPTION}}
const enumVariableValue = PromptTemplateVariables[registeredVariable as keyof typeof PromptTemplateVariables];
if (usedVariable == enumVariableValue) {
found = true;
break;
}
}
if (!found) {
throw new ApplicationError(`Variable '${usedVariable}' not found among the registered variables`);
}
});
}
/**
* Collects all variables present in the provided `template`.
* The return array contains only <b>unique variables</b>, i.e. duplicates are ignored.
*
* @param template template from which to collect unique variables
* @private
*/
private static collectPromptTemplateVariables(template: string): string[] {
const matches = template.matchAll(PromptTemplate.variableRegex);
const variables: string[] = [];
for (const match of matches) {
const variable = match[1];
if (variable && !variables.includes(variable)) {
variables.push(variable);
}
}
return variables
}
}