(model: TypeChatLanguageModel, validator: TypeChatJsonValidator<T>)
| 95 | * @returns A `TypeChatJsonTranslator<T>` instance. |
| 96 | */ |
| 97 | export function createJsonTranslator<T extends object>(model: TypeChatLanguageModel, validator: TypeChatJsonValidator<T>): TypeChatJsonTranslator<T> { |
| 98 | const typeChat: TypeChatJsonTranslator<T> = { |
| 99 | model, |
| 100 | validator, |
| 101 | attemptRepair: true, |
| 102 | stripNulls: false, |
| 103 | createRequestPrompt, |
| 104 | createRepairPrompt, |
| 105 | validateInstance: success, |
| 106 | translate |
| 107 | }; |
| 108 | return typeChat; |
| 109 | |
| 110 | function createRequestPrompt(request: string) { |
| 111 | return `You are a service that translates user requests into JSON objects of type "${validator.getTypeName()}" according to the following TypeScript definitions:\n` + |
| 112 | `\`\`\`\n${validator.getSchemaText()}\`\`\`\n` + |
| 113 | `The following is a user request:\n` + |
| 114 | `"""\n${request}\n"""\n` + |
| 115 | `The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:\n`; |
| 116 | } |
| 117 | |
| 118 | function createRepairPrompt(validationError: string) { |
| 119 | return `The JSON object is invalid for the following reason:\n` + |
| 120 | `"""\n${validationError}\n"""\n` + |
| 121 | `The following is a revised JSON object:\n`; |
| 122 | } |
| 123 | |
| 124 | async function translate(request: string, promptPreamble?: string | PromptSection[]) { |
| 125 | const preamble: PromptSection[] = typeof promptPreamble === "string" ? [{ role: "user", content: promptPreamble }] : promptPreamble ?? []; |
| 126 | let prompt: PromptSection[] = [...preamble, { role: "user", content: typeChat.createRequestPrompt(request) }]; |
| 127 | let attemptRepair = typeChat.attemptRepair; |
| 128 | while (true) { |
| 129 | const response = await model.complete(prompt); |
| 130 | if (!response.success) { |
| 131 | return response; |
| 132 | } |
| 133 | const responseText = response.data; |
| 134 | const startIndex = responseText.indexOf("{"); |
| 135 | const endIndex = responseText.lastIndexOf("}"); |
| 136 | if (!(startIndex >= 0 && endIndex > startIndex)) { |
| 137 | return error(`Response is not JSON:\n${responseText}`); |
| 138 | } |
| 139 | const jsonText = responseText.slice(startIndex, endIndex + 1); |
| 140 | let jsonObject; |
| 141 | try { |
| 142 | jsonObject = JSON.parse(jsonText) as object; |
| 143 | } |
| 144 | catch (e) { |
| 145 | return error(e instanceof SyntaxError ? e.message : "JSON parse error"); |
| 146 | } |
| 147 | if (typeChat.stripNulls) { |
| 148 | stripNulls(jsonObject); |
| 149 | } |
| 150 | const schemaValidation = validator.validate(jsonObject); |
| 151 | const validation = schemaValidation.success ? typeChat.validateInstance(schemaValidation.data) : schemaValidation; |
| 152 | if (validation.success) { |
| 153 | return validation; |
| 154 | } |
no outgoing calls
no test coverage detected
searching dependent graphs…