llm-fns 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createLlmClient.d.ts +79 -0
- package/{src/createLlmClient.ts → dist/createLlmClient.js} +72 -171
- package/dist/createLlmClient.spec.d.ts +1 -0
- package/dist/createLlmClient.spec.js +40 -0
- package/dist/createLlmRetryClient.d.ts +47 -0
- package/{src/createLlmRetryClient.ts → dist/createLlmRetryClient.js} +67 -146
- package/dist/createZodLlmClient.d.ts +45 -0
- package/{src/createZodLlmClient.ts → dist/createZodLlmClient.js} +85 -202
- package/dist/createZodLlmClient.spec.d.ts +1 -0
- package/dist/createZodLlmClient.spec.js +64 -0
- package/dist/index.js +21 -0
- package/dist/llmFactory.d.ts +43 -0
- package/dist/llmFactory.js +21 -0
- package/dist/retryUtils.d.ts +23 -0
- package/{src/retryUtils.ts → dist/retryUtils.js} +9 -32
- package/package.json +6 -2
- package/scripts/release.sh +0 -32
- package/src/createLlmClient.spec.ts +0 -42
- package/src/createZodLlmClient.spec.ts +0 -76
- package/src/llmFactory.ts +0 -26
- package/tests/basic.test.ts +0 -47
- package/tests/env.ts +0 -16
- package/tests/setup.ts +0 -24
- package/tests/zod.test.ts +0 -178
- package/tsconfig.json +0 -22
- /package/{src/index.ts → dist/index.d.ts} +0 -0
|
@@ -1,98 +1,83 @@
|
|
|
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
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeZodArgs = normalizeZodArgs;
|
|
37
|
+
exports.createZodLlmClient = createZodLlmClient;
|
|
38
|
+
const z = __importStar(require("zod"));
|
|
39
|
+
const createLlmRetryClient_js_1 = require("./createLlmRetryClient.js");
|
|
40
|
+
const zod_1 = require("zod");
|
|
41
|
+
function isZodSchema(obj) {
|
|
42
|
+
return (typeof obj === 'object' &&
|
|
34
43
|
obj !== null &&
|
|
35
44
|
'parse' in obj &&
|
|
36
|
-
'_def' in obj
|
|
37
|
-
);
|
|
45
|
+
'_def' in obj);
|
|
38
46
|
}
|
|
39
|
-
|
|
40
|
-
export interface NormalizedZodArgs<T extends ZodTypeAny> {
|
|
41
|
-
mainInstruction: string;
|
|
42
|
-
userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[];
|
|
43
|
-
dataExtractionSchema: T;
|
|
44
|
-
options?: ZodLlmClientOptions;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function normalizeZodArgs<T extends ZodTypeAny>(
|
|
48
|
-
arg1: string | T,
|
|
49
|
-
arg2?: string | OpenAI.Chat.Completions.ChatCompletionContentPart[] | T | ZodLlmClientOptions,
|
|
50
|
-
arg3?: T | ZodLlmClientOptions,
|
|
51
|
-
arg4?: ZodLlmClientOptions
|
|
52
|
-
): NormalizedZodArgs<T> {
|
|
47
|
+
function normalizeZodArgs(arg1, arg2, arg3, arg4) {
|
|
53
48
|
if (isZodSchema(arg1)) {
|
|
54
49
|
// Case 1: promptZod(schema, options?)
|
|
55
50
|
return {
|
|
56
51
|
mainInstruction: "Generate a valid JSON object based on the schema.",
|
|
57
52
|
userMessagePayload: "Generate the data.",
|
|
58
53
|
dataExtractionSchema: arg1,
|
|
59
|
-
options: arg2
|
|
54
|
+
options: arg2
|
|
60
55
|
};
|
|
61
56
|
}
|
|
62
|
-
|
|
63
57
|
if (typeof arg1 === 'string') {
|
|
64
58
|
if (isZodSchema(arg2)) {
|
|
65
59
|
// Case 2: promptZod(prompt, schema, options?)
|
|
66
60
|
return {
|
|
67
61
|
mainInstruction: "You are a helpful assistant that outputs JSON matching the provided schema.",
|
|
68
62
|
userMessagePayload: arg1,
|
|
69
|
-
dataExtractionSchema: arg2
|
|
70
|
-
options: arg3
|
|
63
|
+
dataExtractionSchema: arg2,
|
|
64
|
+
options: arg3
|
|
71
65
|
};
|
|
72
66
|
}
|
|
73
|
-
|
|
74
67
|
// Case 3: promptZod(system, user, schema, options?)
|
|
75
68
|
return {
|
|
76
69
|
mainInstruction: arg1,
|
|
77
|
-
userMessagePayload: arg2
|
|
78
|
-
dataExtractionSchema: arg3
|
|
70
|
+
userMessagePayload: arg2,
|
|
71
|
+
dataExtractionSchema: arg3,
|
|
79
72
|
options: arg4
|
|
80
73
|
};
|
|
81
74
|
}
|
|
82
|
-
|
|
83
75
|
throw new Error("Invalid arguments passed to promptZod");
|
|
84
76
|
}
|
|
85
|
-
|
|
86
|
-
export function createZodLlmClient(params: CreateZodLlmClientParams) {
|
|
77
|
+
function createZodLlmClient(params) {
|
|
87
78
|
const { prompt, isPromptCached, fallbackPrompt, disableJsonFixer = false } = params;
|
|
88
|
-
const llmRetryClient = createLlmRetryClient({ prompt, fallbackPrompt });
|
|
89
|
-
|
|
90
|
-
async function _tryToFixJson(
|
|
91
|
-
brokenResponse: string,
|
|
92
|
-
schemaJsonString: string,
|
|
93
|
-
errorDetails: string,
|
|
94
|
-
options?: ZodLlmClientOptions
|
|
95
|
-
): Promise<string | null> {
|
|
79
|
+
const llmRetryClient = (0, createLlmRetryClient_js_1.createLlmRetryClient)({ prompt, fallbackPrompt });
|
|
80
|
+
async function _tryToFixJson(brokenResponse, schemaJsonString, errorDetails, options) {
|
|
96
81
|
const fixupPrompt = `
|
|
97
82
|
An attempt to generate a JSON object resulted in the following output, which is either not valid JSON or does not conform to the required schema.
|
|
98
83
|
|
|
@@ -111,97 +96,73 @@ ${errorDetails}
|
|
|
111
96
|
BROKEN RESPONSE:
|
|
112
97
|
${brokenResponse}
|
|
113
98
|
`;
|
|
114
|
-
|
|
115
|
-
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
|
|
99
|
+
const messages = [
|
|
116
100
|
{ role: 'system', content: 'You are an expert at fixing malformed JSON data to match a specific schema.' },
|
|
117
101
|
{ role: 'user', content: fixupPrompt }
|
|
118
102
|
];
|
|
119
|
-
|
|
120
103
|
const useResponseFormat = options?.useResponseFormat ?? true;
|
|
121
|
-
const response_format
|
|
104
|
+
const response_format = useResponseFormat
|
|
122
105
|
? { type: 'json_object' }
|
|
123
106
|
: undefined;
|
|
124
|
-
|
|
125
107
|
const { maxRetries, useResponseFormat: _useResponseFormat, ...restOptions } = options || {};
|
|
126
|
-
|
|
127
108
|
const completion = await prompt({
|
|
128
109
|
messages,
|
|
129
110
|
response_format,
|
|
130
111
|
...restOptions
|
|
131
112
|
});
|
|
132
|
-
|
|
133
113
|
const fixedResponse = completion.choices[0]?.message?.content;
|
|
134
|
-
|
|
135
114
|
if (fixedResponse && fixedResponse.trim() === 'CANNOT_FIX') {
|
|
136
115
|
return null;
|
|
137
116
|
}
|
|
138
|
-
|
|
139
117
|
return fixedResponse || null;
|
|
140
118
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
async function _parseOrFixJson(
|
|
144
|
-
llmResponseString: string,
|
|
145
|
-
schemaJsonString: string,
|
|
146
|
-
options: ZodLlmClientOptions | undefined
|
|
147
|
-
): Promise<any> {
|
|
148
|
-
let jsonDataToParse: string = llmResponseString.trim();
|
|
149
|
-
|
|
119
|
+
async function _parseOrFixJson(llmResponseString, schemaJsonString, options) {
|
|
120
|
+
let jsonDataToParse = llmResponseString.trim();
|
|
150
121
|
// Robust handling for responses wrapped in markdown code blocks
|
|
151
122
|
const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)\s*```/;
|
|
152
123
|
const match = codeBlockRegex.exec(jsonDataToParse);
|
|
153
124
|
if (match && match[1]) {
|
|
154
125
|
jsonDataToParse = match[1].trim();
|
|
155
126
|
}
|
|
156
|
-
|
|
157
127
|
if (jsonDataToParse === "") {
|
|
158
128
|
throw new Error("LLM returned an empty string.");
|
|
159
129
|
}
|
|
160
|
-
|
|
161
130
|
try {
|
|
162
131
|
return JSON.parse(jsonDataToParse);
|
|
163
|
-
}
|
|
132
|
+
}
|
|
133
|
+
catch (parseError) {
|
|
164
134
|
if (disableJsonFixer) {
|
|
165
135
|
throw parseError; // re-throw original error
|
|
166
136
|
}
|
|
167
|
-
|
|
168
137
|
// Attempt a one-time fix before failing.
|
|
169
138
|
const errorDetails = `JSON Parse Error: ${parseError.message}`;
|
|
170
139
|
const fixedResponse = await _tryToFixJson(jsonDataToParse, schemaJsonString, errorDetails, options);
|
|
171
|
-
|
|
172
140
|
if (fixedResponse) {
|
|
173
141
|
try {
|
|
174
142
|
return JSON.parse(fixedResponse);
|
|
175
|
-
}
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
176
145
|
// Fix-up failed, throw original error.
|
|
177
146
|
throw parseError;
|
|
178
147
|
}
|
|
179
148
|
}
|
|
180
|
-
|
|
181
149
|
throw parseError; // if no fixed response
|
|
182
150
|
}
|
|
183
151
|
}
|
|
184
|
-
|
|
185
|
-
async function _validateOrFixSchema<SchemaType extends ZodTypeAny>(
|
|
186
|
-
jsonData: any,
|
|
187
|
-
dataExtractionSchema: SchemaType,
|
|
188
|
-
schemaJsonString: string,
|
|
189
|
-
options: ZodLlmClientOptions | undefined
|
|
190
|
-
): Promise<z.infer<SchemaType>> {
|
|
152
|
+
async function _validateOrFixSchema(jsonData, dataExtractionSchema, schemaJsonString, options) {
|
|
191
153
|
try {
|
|
192
154
|
if (options?.beforeValidation) {
|
|
193
155
|
jsonData = options.beforeValidation(jsonData);
|
|
194
156
|
}
|
|
195
157
|
return dataExtractionSchema.parse(jsonData);
|
|
196
|
-
}
|
|
197
|
-
|
|
158
|
+
}
|
|
159
|
+
catch (validationError) {
|
|
160
|
+
if (!(validationError instanceof zod_1.ZodError) || disableJsonFixer) {
|
|
198
161
|
throw validationError;
|
|
199
162
|
}
|
|
200
|
-
|
|
201
163
|
// Attempt a one-time fix for schema validation errors.
|
|
202
164
|
const errorDetails = `Schema Validation Error: ${JSON.stringify(validationError.format(), null, 2)}`;
|
|
203
165
|
const fixedResponse = await _tryToFixJson(JSON.stringify(jsonData, null, 2), schemaJsonString, errorDetails, options);
|
|
204
|
-
|
|
205
166
|
if (fixedResponse) {
|
|
206
167
|
try {
|
|
207
168
|
let fixedJsonData = JSON.parse(fixedResponse);
|
|
@@ -209,170 +170,92 @@ ${brokenResponse}
|
|
|
209
170
|
fixedJsonData = options.beforeValidation(fixedJsonData);
|
|
210
171
|
}
|
|
211
172
|
return dataExtractionSchema.parse(fixedJsonData);
|
|
212
|
-
}
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
213
175
|
// Fix-up failed, throw original validation error
|
|
214
176
|
throw validationError;
|
|
215
177
|
}
|
|
216
178
|
}
|
|
217
|
-
|
|
218
179
|
throw validationError; // if no fixed response
|
|
219
180
|
}
|
|
220
181
|
}
|
|
221
|
-
|
|
222
|
-
function _getZodPromptConfig<T extends ZodTypeAny>(
|
|
223
|
-
mainInstruction: string,
|
|
224
|
-
dataExtractionSchema: T,
|
|
225
|
-
options?: ZodLlmClientOptions
|
|
226
|
-
) {
|
|
182
|
+
function _getZodPromptConfig(mainInstruction, dataExtractionSchema, options) {
|
|
227
183
|
const schema = z.toJSONSchema(dataExtractionSchema, {
|
|
228
184
|
unrepresentable: 'any'
|
|
229
|
-
})
|
|
185
|
+
});
|
|
230
186
|
const schemaJsonString = JSON.stringify(schema);
|
|
231
|
-
|
|
232
187
|
const commonPromptFooter = `
|
|
233
188
|
Your response MUST be a single JSON entity (object or array) that strictly adheres to the following JSON schema.
|
|
234
189
|
Do NOT include any other text, explanations, or markdown formatting (like \`\`\`json) before or after the JSON entity.
|
|
235
190
|
|
|
236
191
|
JSON schema:
|
|
237
192
|
${schemaJsonString}`;
|
|
238
|
-
|
|
239
193
|
const finalMainInstruction = `${mainInstruction}\n${commonPromptFooter}`;
|
|
240
|
-
|
|
241
194
|
const useResponseFormat = options?.useResponseFormat ?? true;
|
|
242
|
-
const response_format
|
|
195
|
+
const response_format = useResponseFormat
|
|
243
196
|
? { type: 'json_object' }
|
|
244
197
|
: undefined;
|
|
245
|
-
|
|
246
198
|
return { finalMainInstruction, schemaJsonString, response_format };
|
|
247
199
|
}
|
|
248
|
-
|
|
249
|
-
async function promptZod<T extends ZodTypeAny>(
|
|
250
|
-
schema: T,
|
|
251
|
-
options?: ZodLlmClientOptions
|
|
252
|
-
): Promise<z.infer<T>>;
|
|
253
|
-
async function promptZod<T extends ZodTypeAny>(
|
|
254
|
-
prompt: string,
|
|
255
|
-
schema: T,
|
|
256
|
-
options?: ZodLlmClientOptions
|
|
257
|
-
): Promise<z.infer<T>>;
|
|
258
|
-
async function promptZod<T extends ZodTypeAny>(
|
|
259
|
-
mainInstruction: string,
|
|
260
|
-
userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[],
|
|
261
|
-
dataExtractionSchema: T,
|
|
262
|
-
options?: ZodLlmClientOptions
|
|
263
|
-
): Promise<z.infer<T>>;
|
|
264
|
-
async function promptZod<T extends ZodTypeAny>(
|
|
265
|
-
arg1: string | T,
|
|
266
|
-
arg2?: string | OpenAI.Chat.Completions.ChatCompletionContentPart[] | T | ZodLlmClientOptions,
|
|
267
|
-
arg3?: T | ZodLlmClientOptions,
|
|
268
|
-
arg4?: ZodLlmClientOptions
|
|
269
|
-
): Promise<z.infer<T>> {
|
|
200
|
+
async function promptZod(arg1, arg2, arg3, arg4) {
|
|
270
201
|
const { mainInstruction, userMessagePayload, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
dataExtractionSchema,
|
|
275
|
-
options
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
const processResponse = async (llmResponseString: string): Promise<z.infer<T>> => {
|
|
279
|
-
let jsonData: any;
|
|
202
|
+
const { finalMainInstruction, schemaJsonString, response_format } = _getZodPromptConfig(mainInstruction, dataExtractionSchema, options);
|
|
203
|
+
const processResponse = async (llmResponseString) => {
|
|
204
|
+
let jsonData;
|
|
280
205
|
try {
|
|
281
206
|
jsonData = await _parseOrFixJson(llmResponseString, schemaJsonString, options);
|
|
282
|
-
}
|
|
207
|
+
}
|
|
208
|
+
catch (parseError) {
|
|
283
209
|
const errorMessage = `Your previous response resulted in an error.
|
|
284
210
|
Error Type: JSON_PARSE_ERROR
|
|
285
211
|
Error Details: ${parseError.message}
|
|
286
212
|
The response provided was not valid JSON. Please correct it.`;
|
|
287
|
-
throw new LlmRetryError(
|
|
288
|
-
errorMessage,
|
|
289
|
-
'JSON_PARSE_ERROR',
|
|
290
|
-
undefined,
|
|
291
|
-
llmResponseString
|
|
292
|
-
);
|
|
213
|
+
throw new createLlmRetryClient_js_1.LlmRetryError(errorMessage, 'JSON_PARSE_ERROR', undefined, llmResponseString);
|
|
293
214
|
}
|
|
294
|
-
|
|
295
215
|
try {
|
|
296
216
|
const validatedData = await _validateOrFixSchema(jsonData, dataExtractionSchema, schemaJsonString, options);
|
|
297
217
|
return validatedData;
|
|
298
|
-
}
|
|
299
|
-
|
|
218
|
+
}
|
|
219
|
+
catch (validationError) {
|
|
220
|
+
if (validationError instanceof zod_1.ZodError) {
|
|
300
221
|
const rawResponseForError = JSON.stringify(jsonData, null, 2);
|
|
301
222
|
const errorDetails = JSON.stringify(validationError.format(), null, 2);
|
|
302
223
|
const errorMessage = `Your previous response resulted in an error.
|
|
303
224
|
Error Type: SCHEMA_VALIDATION_ERROR
|
|
304
225
|
Error Details: ${errorDetails}
|
|
305
226
|
The response was valid JSON but did not conform to the required schema. Please review the errors and the schema to provide a corrected response.`;
|
|
306
|
-
throw new LlmRetryError(
|
|
307
|
-
errorMessage,
|
|
308
|
-
'CUSTOM_ERROR',
|
|
309
|
-
validationError.format(),
|
|
310
|
-
rawResponseForError
|
|
311
|
-
);
|
|
227
|
+
throw new createLlmRetryClient_js_1.LlmRetryError(errorMessage, 'CUSTOM_ERROR', validationError.format(), rawResponseForError);
|
|
312
228
|
}
|
|
313
229
|
// For other errors, rethrow and let LlmRetryClient handle as critical.
|
|
314
230
|
throw validationError;
|
|
315
231
|
}
|
|
316
232
|
};
|
|
317
|
-
|
|
318
|
-
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
|
|
233
|
+
const messages = [
|
|
319
234
|
{ role: "system", content: finalMainInstruction },
|
|
320
235
|
{ role: "user", content: userMessagePayload }
|
|
321
236
|
];
|
|
322
|
-
|
|
323
|
-
const retryOptions: LlmRetryOptions<z.infer<T>> = {
|
|
237
|
+
const retryOptions = {
|
|
324
238
|
...options,
|
|
325
239
|
messages,
|
|
326
240
|
response_format,
|
|
327
241
|
validate: processResponse
|
|
328
242
|
};
|
|
329
|
-
|
|
330
243
|
// Use promptTextRetry because we expect a string response to parse as JSON
|
|
331
244
|
return llmRetryClient.promptTextRetry(retryOptions);
|
|
332
245
|
}
|
|
333
|
-
|
|
334
|
-
async function isPromptZodCached<T extends ZodTypeAny>(
|
|
335
|
-
schema: T,
|
|
336
|
-
options?: ZodLlmClientOptions
|
|
337
|
-
): Promise<boolean>;
|
|
338
|
-
async function isPromptZodCached<T extends ZodTypeAny>(
|
|
339
|
-
prompt: string,
|
|
340
|
-
schema: T,
|
|
341
|
-
options?: ZodLlmClientOptions
|
|
342
|
-
): Promise<boolean>;
|
|
343
|
-
async function isPromptZodCached<T extends ZodTypeAny>(
|
|
344
|
-
mainInstruction: string,
|
|
345
|
-
userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[],
|
|
346
|
-
dataExtractionSchema: T,
|
|
347
|
-
options?: ZodLlmClientOptions
|
|
348
|
-
): Promise<boolean>;
|
|
349
|
-
async function isPromptZodCached<T extends ZodTypeAny>(
|
|
350
|
-
arg1: string | T,
|
|
351
|
-
arg2?: string | OpenAI.Chat.Completions.ChatCompletionContentPart[] | T | ZodLlmClientOptions,
|
|
352
|
-
arg3?: T | ZodLlmClientOptions,
|
|
353
|
-
arg4?: ZodLlmClientOptions
|
|
354
|
-
): Promise<boolean> {
|
|
246
|
+
async function isPromptZodCached(arg1, arg2, arg3, arg4) {
|
|
355
247
|
const { mainInstruction, userMessagePayload, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
mainInstruction,
|
|
359
|
-
dataExtractionSchema,
|
|
360
|
-
options
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
|
|
248
|
+
const { finalMainInstruction, response_format } = _getZodPromptConfig(mainInstruction, dataExtractionSchema, options);
|
|
249
|
+
const messages = [
|
|
364
250
|
{ role: "system", content: finalMainInstruction },
|
|
365
251
|
{ role: "user", content: userMessagePayload }
|
|
366
252
|
];
|
|
367
|
-
|
|
368
253
|
const { maxRetries, useResponseFormat: _u, beforeValidation, ...restOptions } = options || {};
|
|
369
|
-
|
|
370
254
|
return isPromptCached({
|
|
371
255
|
messages,
|
|
372
256
|
response_format,
|
|
373
257
|
...restOptions
|
|
374
258
|
});
|
|
375
259
|
}
|
|
376
|
-
|
|
377
260
|
return { promptZod, isPromptZodCached };
|
|
378
261
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
6
|
+
(0, vitest_1.describe)('normalizeZodArgs', () => {
|
|
7
|
+
const TestSchema = zod_1.z.object({
|
|
8
|
+
foo: zod_1.z.string()
|
|
9
|
+
});
|
|
10
|
+
(0, vitest_1.it)('should normalize Schema Only (Case 1)', () => {
|
|
11
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(TestSchema);
|
|
12
|
+
(0, vitest_1.expect)(result.mainInstruction).toContain('Generate a valid JSON');
|
|
13
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe('Generate the data.');
|
|
14
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
15
|
+
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)('should normalize Schema Only with Options (Case 1)', () => {
|
|
18
|
+
const options = { temperature: 0.5 };
|
|
19
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(TestSchema, options);
|
|
20
|
+
(0, vitest_1.expect)(result.mainInstruction).toContain('Generate a valid JSON');
|
|
21
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe('Generate the data.');
|
|
22
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
23
|
+
(0, vitest_1.expect)(result.options).toBe(options);
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)('should normalize Prompt + Schema (Case 2)', () => {
|
|
26
|
+
const prompt = "Extract data";
|
|
27
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(prompt, TestSchema);
|
|
28
|
+
(0, vitest_1.expect)(result.mainInstruction).toContain('You are a helpful assistant');
|
|
29
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe(prompt);
|
|
30
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
31
|
+
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('should normalize Prompt + Schema with Options (Case 2)', () => {
|
|
34
|
+
const prompt = "Extract data";
|
|
35
|
+
const options = { temperature: 0.5 };
|
|
36
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(prompt, TestSchema, options);
|
|
37
|
+
(0, vitest_1.expect)(result.mainInstruction).toContain('You are a helpful assistant');
|
|
38
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe(prompt);
|
|
39
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
40
|
+
(0, vitest_1.expect)(result.options).toBe(options);
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.it)('should normalize System + User + Schema (Case 3)', () => {
|
|
43
|
+
const system = "System prompt";
|
|
44
|
+
const user = "User prompt";
|
|
45
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(system, user, TestSchema);
|
|
46
|
+
(0, vitest_1.expect)(result.mainInstruction).toBe(system);
|
|
47
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe(user);
|
|
48
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
49
|
+
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.it)('should normalize System + User + Schema with Options (Case 3)', () => {
|
|
52
|
+
const system = "System prompt";
|
|
53
|
+
const user = "User prompt";
|
|
54
|
+
const options = { temperature: 0.5 };
|
|
55
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(system, user, TestSchema, options);
|
|
56
|
+
(0, vitest_1.expect)(result.mainInstruction).toBe(system);
|
|
57
|
+
(0, vitest_1.expect)(result.userMessagePayload).toBe(user);
|
|
58
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
59
|
+
(0, vitest_1.expect)(result.options).toBe(options);
|
|
60
|
+
});
|
|
61
|
+
(0, vitest_1.it)('should throw error for invalid arguments', () => {
|
|
62
|
+
(0, vitest_1.expect)(() => (0, createZodLlmClient_js_1.normalizeZodArgs)({})).toThrow('Invalid arguments');
|
|
63
|
+
});
|
|
64
|
+
});
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./createLlmClient.js"), exports);
|
|
18
|
+
__exportStar(require("./createLlmRetryClient.js"), exports);
|
|
19
|
+
__exportStar(require("./createZodLlmClient.js"), exports);
|
|
20
|
+
__exportStar(require("./llmFactory.js"), exports);
|
|
21
|
+
__exportStar(require("./retryUtils.js"), exports);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CreateLlmClientParams } from "./createLlmClient.js";
|
|
2
|
+
export interface CreateLlmFactoryParams extends CreateLlmClientParams {
|
|
3
|
+
}
|
|
4
|
+
export declare function createLlm(params: CreateLlmFactoryParams): {
|
|
5
|
+
promptZod: {
|
|
6
|
+
<T extends import("zod").ZodType>(schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
7
|
+
<T extends import("zod").ZodType>(prompt: string, schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
8
|
+
<T extends import("zod").ZodType>(mainInstruction: string, userMessagePayload: string | import("openai/resources/index.js").ChatCompletionContentPart[], dataExtractionSchema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
9
|
+
};
|
|
10
|
+
isPromptZodCached: {
|
|
11
|
+
<T extends import("zod").ZodType>(schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
12
|
+
<T extends import("zod").ZodType>(prompt: string, schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
13
|
+
<T extends import("zod").ZodType>(mainInstruction: string, userMessagePayload: string | import("openai/resources/index.js").ChatCompletionContentPart[], dataExtractionSchema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
14
|
+
};
|
|
15
|
+
promptRetry: {
|
|
16
|
+
<T = import("openai/resources/index.js").ChatCompletion>(content: string, options?: Omit<import("./createLlmRetryClient.js").LlmRetryOptions<T>, "messages">): Promise<T>;
|
|
17
|
+
<T = import("openai/resources/index.js").ChatCompletion>(options: import("./createLlmRetryClient.js").LlmRetryOptions<T>): Promise<T>;
|
|
18
|
+
};
|
|
19
|
+
promptTextRetry: {
|
|
20
|
+
<T = string>(content: string, options?: Omit<import("./createLlmRetryClient.js").LlmRetryOptions<T>, "messages">): Promise<T>;
|
|
21
|
+
<T = string>(options: import("./createLlmRetryClient.js").LlmRetryOptions<T>): Promise<T>;
|
|
22
|
+
};
|
|
23
|
+
promptImageRetry: {
|
|
24
|
+
<T = Buffer<ArrayBufferLike>>(content: string, options?: Omit<import("./createLlmRetryClient.js").LlmRetryOptions<T>, "messages">): Promise<T>;
|
|
25
|
+
<T = Buffer<ArrayBufferLike>>(options: import("./createLlmRetryClient.js").LlmRetryOptions<T>): Promise<T>;
|
|
26
|
+
};
|
|
27
|
+
prompt: {
|
|
28
|
+
(content: string, options?: Omit<import("./createLlmClient.js").LlmPromptOptions, "messages">): Promise<import("openai/resources/index.js").ChatCompletion>;
|
|
29
|
+
(options: import("./createLlmClient.js").LlmPromptOptions): Promise<import("openai/resources/index.js").ChatCompletion>;
|
|
30
|
+
};
|
|
31
|
+
isPromptCached: {
|
|
32
|
+
(content: string, options?: Omit<import("./createLlmClient.js").LlmPromptOptions, "messages">): Promise<boolean>;
|
|
33
|
+
(options: import("./createLlmClient.js").LlmPromptOptions): Promise<boolean>;
|
|
34
|
+
};
|
|
35
|
+
promptText: {
|
|
36
|
+
(content: string, options?: Omit<import("./createLlmClient.js").LlmPromptOptions, "messages">): Promise<string>;
|
|
37
|
+
(options: import("./createLlmClient.js").LlmPromptOptions): Promise<string>;
|
|
38
|
+
};
|
|
39
|
+
promptImage: {
|
|
40
|
+
(content: string, options?: Omit<import("./createLlmClient.js").LlmPromptOptions, "messages">): Promise<Buffer>;
|
|
41
|
+
(options: import("./createLlmClient.js").LlmPromptOptions): Promise<Buffer>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLlm = createLlm;
|
|
4
|
+
const createLlmClient_js_1 = require("./createLlmClient.js");
|
|
5
|
+
const createLlmRetryClient_js_1 = require("./createLlmRetryClient.js");
|
|
6
|
+
const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
7
|
+
function createLlm(params) {
|
|
8
|
+
const baseClient = (0, createLlmClient_js_1.createLlmClient)(params);
|
|
9
|
+
const retryClient = (0, createLlmRetryClient_js_1.createLlmRetryClient)({
|
|
10
|
+
prompt: baseClient.prompt
|
|
11
|
+
});
|
|
12
|
+
const zodClient = (0, createZodLlmClient_js_1.createZodLlmClient)({
|
|
13
|
+
prompt: baseClient.prompt,
|
|
14
|
+
isPromptCached: baseClient.isPromptCached
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
...baseClient,
|
|
18
|
+
...retryClient,
|
|
19
|
+
...zodClient
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes the outcome of a validation/processing step in a retry loop.
|
|
3
|
+
*/
|
|
4
|
+
export interface RetryValidationResult<ValidatedDataType, FeedbackType = any> {
|
|
5
|
+
isValid: boolean;
|
|
6
|
+
data?: ValidatedDataType;
|
|
7
|
+
feedbackForNextAttempt?: FeedbackType;
|
|
8
|
+
isCriticalFailure?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Executes an operation with a retry mechanism.
|
|
12
|
+
*
|
|
13
|
+
* @param operation - An async function representing the operation to be tried.
|
|
14
|
+
* It receives the current attempt number and feedback from the previous validation.
|
|
15
|
+
* @param validateAndProcess - An async function that processes the raw result from the operation
|
|
16
|
+
* and validates it. It returns a RetryValidationResult.
|
|
17
|
+
* @param maxRetries - The maximum number of retries after the initial attempt (e.g., 2 means 3 total attempts).
|
|
18
|
+
* @param initialFeedbackForOperation - Optional initial feedback to pass to the very first call of the operation.
|
|
19
|
+
* @param shouldRetryError - Optional function to determine if a specific error should trigger a retry. Returns true to retry, false to throw immediately.
|
|
20
|
+
* @returns A Promise that resolves with the validated data if successful.
|
|
21
|
+
* @throws An error if all attempts fail or a critical failure occurs.
|
|
22
|
+
*/
|
|
23
|
+
export declare function executeWithRetry<OperationReturnType, ValidatedDataType, FeedbackType = any>(operation: (attemptNumber: number, feedbackForOperation?: FeedbackType) => Promise<OperationReturnType>, validateAndProcess: (rawResult: OperationReturnType, attemptNumber: number) => Promise<RetryValidationResult<ValidatedDataType, FeedbackType>>, maxRetries: number, initialFeedbackForOperation?: FeedbackType, shouldRetryError?: (error: any) => boolean): Promise<ValidatedDataType>;
|