forked from microsoft/TypeChat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypechat.ts
118 lines (113 loc) · 5.68 KB
/
typechat.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
import { Result, error } from "./result";
import { TypeChatLanguageModel } from "./model";
import { TypeChatJsonValidator, createJsonValidator } from "./validate";
/**
* Represents an object that can translate natural language requests in JSON objects of the given type.
*/
export interface TypeChatJsonTranslator<T extends object> {
/**
* The associated `TypeChatLanguageModel`.
*/
model: TypeChatLanguageModel;
/**
* The associated `TypeChatJsonValidator<T>`.
*/
validator: TypeChatJsonValidator<T>;
/**
* A boolean indicating whether to attempt repairing JSON objects that fail to validate. The default is `true`,
* but an application can set the property to `false` to disable repair attempts.
*/
attemptRepair: boolean;
/**
* A boolean indicating whether to delete properties with null values from parsed JSON objects. Some language
* models (e.g. gpt-3.5-turbo) have a tendency to assign null values to optional properties instead of omitting
* them. The default for this property is `false`, but an application can set the property to `true` for schemas
* that don't permit null values.
*/
stripNulls: boolean;
/**
* Creates an AI language model prompt from the given request. This function is called by `completeAndValidate`
* to obtain the prompt. An application can assign a new function to provide a different prompt.
* @param request The natural language request.
* @returns A prompt that combines the request with the schema and type name of the underlying validator.
*/
createRequestPrompt(request: string): string;
/**
* Creates a repair prompt to append to an original prompt/response in order to repair a JSON object that
* failed to validate. This function is called by `completeAndValidate` when `attemptRepair` is true and the
* JSON object produced by the original prompt failed to validate. An application can assign a new function
* to provide a different repair prompt.
* @param validationError The error message returned by the validator.
* @returns A repair prompt constructed from the error message.
*/
createRepairPrompt(validationError: string): string;
/**
* Translates a natural language request into an object of type `T`. If the JSON object returned by
* the language model fails to validate and the `attemptRepair` property is `true`, a second
* attempt to translate the request will be made. The prompt for the second attempt will include the
* diagnostics produced for the first attempt. This often helps produce a valid instance.
* @param request The natural language request.
* @returns A promise for the resulting object.
*/
translate(request: string): Promise<Result<T>>;
}
/**
* Creates an object that can translate natural language requests into JSON objects of the given type.
* The specified type argument `T` must be the same type as `typeName` in the given `schema`. The function
* creates a `TypeChatJsonValidator<T>` and stores it in the `validator` property of the returned instance.
* @param model The language model to use for translating requests into JSON.
* @param schema A string containing the TypeScript source code for the JSON schema.
* @param typeName The name of the JSON target type in the schema.
* @returns A `TypeChatJsonTranslator<T>` instance.
*/
export function createJsonTranslator<T extends object>(model: TypeChatLanguageModel, schema: string, typeName: string): TypeChatJsonTranslator<T> {
const validator = createJsonValidator<T>(schema, typeName);
const typeChat: TypeChatJsonTranslator<T> = {
model,
validator,
attemptRepair: true,
stripNulls: false,
createRequestPrompt,
createRepairPrompt,
translate
};
return typeChat;
function createRequestPrompt(request: string) {
return `You are a service that translates user requests into JSON objects of type "${validator.typeName}" according to the following TypeScript definitions:\n` +
`\`\`\`\n${validator.schema}\`\`\`\n` +
`The following is a user request:\n` +
`"""\n${request}\n"""\n` +
`The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\n`;
}
function createRepairPrompt(validationError: string) {
return `The JSON object is invalid for the following reason:\n` +
`"""\n${validationError}\n"""\n` +
`The following is a revised JSON object:\n`;
}
async function translate(request: string) {
let prompt = typeChat.createRequestPrompt(request);
let attemptRepair = typeChat.attemptRepair;
while (true) {
const response = await model.complete(prompt);
if (!response.success) {
return response;
}
const responseText = response.data;
const startIndex = responseText.indexOf("{");
const endIndex = responseText.lastIndexOf("}");
if (!(startIndex >= 0 && endIndex > startIndex)) {
return error(`Response is not JSON:\n${responseText}`);
}
const jsonText = responseText.slice(startIndex, endIndex + 1);
const validation = validator.validate(jsonText);
if (validation.success) {
return validation;
}
if (!attemptRepair) {
return error(`JSON validation failed: ${validation.message}\n${jsonText}`);
}
prompt += `${responseText}\n${typeChat.createRepairPrompt(validation.message)}`;
attemptRepair = false;
}
}
}