llm-fns 1.0.4 → 1.0.6
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.js
CHANGED
|
@@ -141,12 +141,17 @@ function getPromptSummary(messages) {
|
|
|
141
141
|
const fullText = concatMessageText(messages);
|
|
142
142
|
// Replace multiple whitespace chars with a single space and trim.
|
|
143
143
|
const cleanedText = fullText.replace(/\s+/g, ' ').trim();
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (cleanedText.length > maxLength) {
|
|
147
|
-
return cleanedText.substring(0, maxLength) + '...';
|
|
144
|
+
if (cleanedText.length <= 50) {
|
|
145
|
+
return cleanedText;
|
|
148
146
|
}
|
|
149
|
-
|
|
147
|
+
const partLength = 15;
|
|
148
|
+
const start = cleanedText.substring(0, partLength);
|
|
149
|
+
const end = cleanedText.substring(cleanedText.length - partLength);
|
|
150
|
+
const midIndex = Math.floor(cleanedText.length / 2);
|
|
151
|
+
const midStart = Math.max(partLength, midIndex - Math.ceil(partLength / 2));
|
|
152
|
+
const midEnd = Math.min(cleanedText.length - partLength, midStart + partLength);
|
|
153
|
+
const middle = cleanedText.substring(midStart, midEnd);
|
|
154
|
+
return `${start}...${middle}...${end}`;
|
|
150
155
|
}
|
|
151
156
|
function normalizeOptions(arg1, arg2) {
|
|
152
157
|
if (typeof arg1 === 'string') {
|
|
@@ -229,7 +234,7 @@ function createLlmClient(params) {
|
|
|
229
234
|
}
|
|
230
235
|
return true;
|
|
231
236
|
});
|
|
232
|
-
const response = (await (queue ? queue.add(task, { id: promptSummary }) : task()));
|
|
237
|
+
const response = (await (queue ? queue.add(task, { id: promptSummary, messages: finalMessages }) : task()));
|
|
233
238
|
if (cacheInstance && response && cacheKey) {
|
|
234
239
|
try {
|
|
235
240
|
await cacheInstance.set(cacheKey, JSON.stringify(response), ttl);
|
|
@@ -25,20 +25,21 @@ export interface CreateZodLlmClientParams {
|
|
|
25
25
|
disableJsonFixer?: boolean;
|
|
26
26
|
}
|
|
27
27
|
export interface NormalizedZodArgs<T extends ZodTypeAny> {
|
|
28
|
-
|
|
29
|
-
userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[];
|
|
28
|
+
messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[];
|
|
30
29
|
dataExtractionSchema: T;
|
|
31
30
|
options?: ZodLlmClientOptions;
|
|
32
31
|
}
|
|
33
|
-
export declare function normalizeZodArgs<T extends ZodTypeAny>(arg1: string | T, arg2?: string | OpenAI.Chat.Completions.ChatCompletionContentPart[] | T | ZodLlmClientOptions, arg3?: T | ZodLlmClientOptions, arg4?: ZodLlmClientOptions): NormalizedZodArgs<T>;
|
|
32
|
+
export declare function normalizeZodArgs<T extends ZodTypeAny>(arg1: string | OpenAI.Chat.Completions.ChatCompletionMessageParam[] | T, arg2?: string | OpenAI.Chat.Completions.ChatCompletionContentPart[] | T | ZodLlmClientOptions, arg3?: T | ZodLlmClientOptions, arg4?: ZodLlmClientOptions): NormalizedZodArgs<T>;
|
|
34
33
|
export declare function createZodLlmClient(params: CreateZodLlmClientParams): {
|
|
35
34
|
promptZod: {
|
|
36
35
|
<T extends ZodTypeAny>(schema: T, options?: ZodLlmClientOptions): Promise<z.infer<T>>;
|
|
36
|
+
<T extends ZodTypeAny>(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], schema: T, options?: ZodLlmClientOptions): Promise<z.infer<T>>;
|
|
37
37
|
<T extends ZodTypeAny>(prompt: string, schema: T, options?: ZodLlmClientOptions): Promise<z.infer<T>>;
|
|
38
38
|
<T extends ZodTypeAny>(mainInstruction: string, userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[], dataExtractionSchema: T, options?: ZodLlmClientOptions): Promise<z.infer<T>>;
|
|
39
39
|
};
|
|
40
40
|
isPromptZodCached: {
|
|
41
41
|
<T extends ZodTypeAny>(schema: T, options?: ZodLlmClientOptions): Promise<boolean>;
|
|
42
|
+
<T extends ZodTypeAny>(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], schema: T, options?: ZodLlmClientOptions): Promise<boolean>;
|
|
42
43
|
<T extends ZodTypeAny>(prompt: string, schema: T, options?: ZodLlmClientOptions): Promise<boolean>;
|
|
43
44
|
<T extends ZodTypeAny>(mainInstruction: string, userMessagePayload: string | OpenAI.Chat.Completions.ChatCompletionContentPart[], dataExtractionSchema: T, options?: ZodLlmClientOptions): Promise<boolean>;
|
|
44
45
|
};
|
|
@@ -45,11 +45,21 @@ function isZodSchema(obj) {
|
|
|
45
45
|
'_def' in obj);
|
|
46
46
|
}
|
|
47
47
|
function normalizeZodArgs(arg1, arg2, arg3, arg4) {
|
|
48
|
+
// Case 0: promptZod(messages[], schema, options?)
|
|
49
|
+
if (Array.isArray(arg1)) {
|
|
50
|
+
return {
|
|
51
|
+
messages: arg1,
|
|
52
|
+
dataExtractionSchema: arg2,
|
|
53
|
+
options: arg3
|
|
54
|
+
};
|
|
55
|
+
}
|
|
48
56
|
if (isZodSchema(arg1)) {
|
|
49
57
|
// Case 1: promptZod(schema, options?)
|
|
50
58
|
return {
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
messages: [
|
|
60
|
+
{ role: 'system', content: "Generate a valid JSON object based on the schema." },
|
|
61
|
+
{ role: 'user', content: "Generate the data." }
|
|
62
|
+
],
|
|
53
63
|
dataExtractionSchema: arg1,
|
|
54
64
|
options: arg2
|
|
55
65
|
};
|
|
@@ -58,16 +68,20 @@ function normalizeZodArgs(arg1, arg2, arg3, arg4) {
|
|
|
58
68
|
if (isZodSchema(arg2)) {
|
|
59
69
|
// Case 2: promptZod(prompt, schema, options?)
|
|
60
70
|
return {
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
messages: [
|
|
72
|
+
{ role: 'system', content: "You are a helpful assistant that outputs JSON matching the provided schema." },
|
|
73
|
+
{ role: 'user', content: arg1 }
|
|
74
|
+
],
|
|
63
75
|
dataExtractionSchema: arg2,
|
|
64
76
|
options: arg3
|
|
65
77
|
};
|
|
66
78
|
}
|
|
67
79
|
// Case 3: promptZod(system, user, schema, options?)
|
|
68
80
|
return {
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
messages: [
|
|
82
|
+
{ role: 'system', content: arg1 },
|
|
83
|
+
{ role: 'user', content: arg2 }
|
|
84
|
+
],
|
|
71
85
|
dataExtractionSchema: arg3,
|
|
72
86
|
options: arg4
|
|
73
87
|
};
|
|
@@ -179,7 +193,7 @@ ${brokenResponse}
|
|
|
179
193
|
throw validationError; // if no fixed response
|
|
180
194
|
}
|
|
181
195
|
}
|
|
182
|
-
function _getZodPromptConfig(
|
|
196
|
+
function _getZodPromptConfig(messages, dataExtractionSchema, options) {
|
|
183
197
|
const schema = z.toJSONSchema(dataExtractionSchema, {
|
|
184
198
|
unrepresentable: 'any'
|
|
185
199
|
});
|
|
@@ -190,16 +204,34 @@ Do NOT include any other text, explanations, or markdown formatting (like \`\`\`
|
|
|
190
204
|
|
|
191
205
|
JSON schema:
|
|
192
206
|
${schemaJsonString}`;
|
|
193
|
-
|
|
207
|
+
// Clone messages to avoid mutating the input
|
|
208
|
+
const finalMessages = [...messages];
|
|
209
|
+
// Find the first system message to append instructions to
|
|
210
|
+
const systemMessageIndex = finalMessages.findIndex(m => m.role === 'system');
|
|
211
|
+
if (systemMessageIndex !== -1) {
|
|
212
|
+
// Append to existing system message
|
|
213
|
+
const existingContent = finalMessages[systemMessageIndex].content;
|
|
214
|
+
finalMessages[systemMessageIndex] = {
|
|
215
|
+
...finalMessages[systemMessageIndex],
|
|
216
|
+
content: `${existingContent}\n${commonPromptFooter}`
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Prepend new system message
|
|
221
|
+
finalMessages.unshift({
|
|
222
|
+
role: 'system',
|
|
223
|
+
content: commonPromptFooter
|
|
224
|
+
});
|
|
225
|
+
}
|
|
194
226
|
const useResponseFormat = options?.useResponseFormat ?? true;
|
|
195
227
|
const response_format = useResponseFormat
|
|
196
228
|
? { type: 'json_object' }
|
|
197
229
|
: undefined;
|
|
198
|
-
return {
|
|
230
|
+
return { finalMessages, schemaJsonString, response_format };
|
|
199
231
|
}
|
|
200
232
|
async function promptZod(arg1, arg2, arg3, arg4) {
|
|
201
|
-
const {
|
|
202
|
-
const {
|
|
233
|
+
const { messages, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
|
|
234
|
+
const { finalMessages, schemaJsonString, response_format } = _getZodPromptConfig(messages, dataExtractionSchema, options);
|
|
203
235
|
const processResponse = async (llmResponseString) => {
|
|
204
236
|
let jsonData;
|
|
205
237
|
try {
|
|
@@ -230,13 +262,9 @@ The response was valid JSON but did not conform to the required schema. Please r
|
|
|
230
262
|
throw validationError;
|
|
231
263
|
}
|
|
232
264
|
};
|
|
233
|
-
const messages = [
|
|
234
|
-
{ role: "system", content: finalMainInstruction },
|
|
235
|
-
{ role: "user", content: userMessagePayload }
|
|
236
|
-
];
|
|
237
265
|
const retryOptions = {
|
|
238
266
|
...options,
|
|
239
|
-
messages,
|
|
267
|
+
messages: finalMessages,
|
|
240
268
|
response_format,
|
|
241
269
|
validate: processResponse
|
|
242
270
|
};
|
|
@@ -244,15 +272,11 @@ The response was valid JSON but did not conform to the required schema. Please r
|
|
|
244
272
|
return llmRetryClient.promptTextRetry(retryOptions);
|
|
245
273
|
}
|
|
246
274
|
async function isPromptZodCached(arg1, arg2, arg3, arg4) {
|
|
247
|
-
const {
|
|
248
|
-
const {
|
|
249
|
-
const messages = [
|
|
250
|
-
{ role: "system", content: finalMainInstruction },
|
|
251
|
-
{ role: "user", content: userMessagePayload }
|
|
252
|
-
];
|
|
275
|
+
const { messages, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
|
|
276
|
+
const { finalMessages, response_format } = _getZodPromptConfig(messages, dataExtractionSchema, options);
|
|
253
277
|
const { maxRetries, useResponseFormat: _u, beforeValidation, ...restOptions } = options || {};
|
|
254
278
|
return isPromptCached({
|
|
255
|
-
messages,
|
|
279
|
+
messages: finalMessages,
|
|
256
280
|
response_format,
|
|
257
281
|
...restOptions
|
|
258
282
|
});
|
|
@@ -9,24 +9,24 @@ const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
|
9
9
|
});
|
|
10
10
|
(0, vitest_1.it)('should normalize Schema Only (Case 1)', () => {
|
|
11
11
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(TestSchema);
|
|
12
|
-
(0, vitest_1.expect)(result.
|
|
13
|
-
(0, vitest_1.expect)(result.
|
|
12
|
+
(0, vitest_1.expect)(result.messages[0].content).toContain('Generate a valid JSON');
|
|
13
|
+
(0, vitest_1.expect)(result.messages[1].content).toBe('Generate the data.');
|
|
14
14
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
15
15
|
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
16
16
|
});
|
|
17
17
|
(0, vitest_1.it)('should normalize Schema Only with Options (Case 1)', () => {
|
|
18
18
|
const options = { temperature: 0.5 };
|
|
19
19
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(TestSchema, options);
|
|
20
|
-
(0, vitest_1.expect)(result.
|
|
21
|
-
(0, vitest_1.expect)(result.
|
|
20
|
+
(0, vitest_1.expect)(result.messages[0].content).toContain('Generate a valid JSON');
|
|
21
|
+
(0, vitest_1.expect)(result.messages[1].content).toBe('Generate the data.');
|
|
22
22
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
23
23
|
(0, vitest_1.expect)(result.options).toBe(options);
|
|
24
24
|
});
|
|
25
25
|
(0, vitest_1.it)('should normalize Prompt + Schema (Case 2)', () => {
|
|
26
26
|
const prompt = "Extract data";
|
|
27
27
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(prompt, TestSchema);
|
|
28
|
-
(0, vitest_1.expect)(result.
|
|
29
|
-
(0, vitest_1.expect)(result.
|
|
28
|
+
(0, vitest_1.expect)(result.messages[0].content).toContain('You are a helpful assistant');
|
|
29
|
+
(0, vitest_1.expect)(result.messages[1].content).toBe(prompt);
|
|
30
30
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
31
31
|
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
32
32
|
});
|
|
@@ -34,8 +34,8 @@ const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
|
34
34
|
const prompt = "Extract data";
|
|
35
35
|
const options = { temperature: 0.5 };
|
|
36
36
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(prompt, TestSchema, options);
|
|
37
|
-
(0, vitest_1.expect)(result.
|
|
38
|
-
(0, vitest_1.expect)(result.
|
|
37
|
+
(0, vitest_1.expect)(result.messages[0].content).toContain('You are a helpful assistant');
|
|
38
|
+
(0, vitest_1.expect)(result.messages[1].content).toBe(prompt);
|
|
39
39
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
40
40
|
(0, vitest_1.expect)(result.options).toBe(options);
|
|
41
41
|
});
|
|
@@ -43,8 +43,8 @@ const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
|
43
43
|
const system = "System prompt";
|
|
44
44
|
const user = "User prompt";
|
|
45
45
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(system, user, TestSchema);
|
|
46
|
-
(0, vitest_1.expect)(result.
|
|
47
|
-
(0, vitest_1.expect)(result.
|
|
46
|
+
(0, vitest_1.expect)(result.messages[0].content).toBe(system);
|
|
47
|
+
(0, vitest_1.expect)(result.messages[1].content).toBe(user);
|
|
48
48
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
49
49
|
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
50
50
|
});
|
|
@@ -53,8 +53,29 @@ const createZodLlmClient_js_1 = require("./createZodLlmClient.js");
|
|
|
53
53
|
const user = "User prompt";
|
|
54
54
|
const options = { temperature: 0.5 };
|
|
55
55
|
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(system, user, TestSchema, options);
|
|
56
|
-
(0, vitest_1.expect)(result.
|
|
57
|
-
(0, vitest_1.expect)(result.
|
|
56
|
+
(0, vitest_1.expect)(result.messages[0].content).toBe(system);
|
|
57
|
+
(0, vitest_1.expect)(result.messages[1].content).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 normalize Messages Array + Schema (Case 0)', () => {
|
|
62
|
+
const messages = [
|
|
63
|
+
{ role: 'system', content: 'Sys' },
|
|
64
|
+
{ role: 'user', content: 'Usr' }
|
|
65
|
+
];
|
|
66
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(messages, TestSchema);
|
|
67
|
+
(0, vitest_1.expect)(result.messages).toBe(messages);
|
|
68
|
+
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
69
|
+
(0, vitest_1.expect)(result.options).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
(0, vitest_1.it)('should normalize Messages Array + Schema with Options (Case 0)', () => {
|
|
72
|
+
const messages = [
|
|
73
|
+
{ role: 'system', content: 'Sys' },
|
|
74
|
+
{ role: 'user', content: 'Usr' }
|
|
75
|
+
];
|
|
76
|
+
const options = { temperature: 0.5 };
|
|
77
|
+
const result = (0, createZodLlmClient_js_1.normalizeZodArgs)(messages, TestSchema, options);
|
|
78
|
+
(0, vitest_1.expect)(result.messages).toBe(messages);
|
|
58
79
|
(0, vitest_1.expect)(result.dataExtractionSchema).toBe(TestSchema);
|
|
59
80
|
(0, vitest_1.expect)(result.options).toBe(options);
|
|
60
81
|
});
|
package/dist/llmFactory.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ export interface CreateLlmFactoryParams extends CreateLlmClientParams {
|
|
|
4
4
|
export declare function createLlm(params: CreateLlmFactoryParams): {
|
|
5
5
|
promptZod: {
|
|
6
6
|
<T extends import("zod").ZodType>(schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
7
|
+
<T extends import("zod").ZodType>(messages: import("openai/resources/index.js").ChatCompletionMessageParam[], schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
7
8
|
<T extends import("zod").ZodType>(prompt: string, schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<import("zod").infer<T>>;
|
|
8
9
|
<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
|
};
|
|
10
11
|
isPromptZodCached: {
|
|
11
12
|
<T extends import("zod").ZodType>(schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
13
|
+
<T extends import("zod").ZodType>(messages: import("openai/resources/index.js").ChatCompletionMessageParam[], schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
12
14
|
<T extends import("zod").ZodType>(prompt: string, schema: T, options?: import("./createZodLlmClient.js").ZodLlmClientOptions): Promise<boolean>;
|
|
13
15
|
<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
16
|
};
|