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.
@@ -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
- // Truncate to a reasonable length.
145
- const maxLength = 150;
146
- if (cleanedText.length > maxLength) {
147
- return cleanedText.substring(0, maxLength) + '...';
144
+ if (cleanedText.length <= 50) {
145
+ return cleanedText;
148
146
  }
149
- return cleanedText;
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
- mainInstruction: string;
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
- mainInstruction: "Generate a valid JSON object based on the schema.",
52
- userMessagePayload: "Generate the data.",
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
- mainInstruction: "You are a helpful assistant that outputs JSON matching the provided schema.",
62
- userMessagePayload: arg1,
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
- mainInstruction: arg1,
70
- userMessagePayload: arg2,
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(mainInstruction, dataExtractionSchema, options) {
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
- const finalMainInstruction = `${mainInstruction}\n${commonPromptFooter}`;
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 { finalMainInstruction, schemaJsonString, response_format };
230
+ return { finalMessages, schemaJsonString, response_format };
199
231
  }
200
232
  async function promptZod(arg1, arg2, arg3, arg4) {
201
- const { mainInstruction, userMessagePayload, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
202
- const { finalMainInstruction, schemaJsonString, response_format } = _getZodPromptConfig(mainInstruction, dataExtractionSchema, options);
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 { mainInstruction, userMessagePayload, dataExtractionSchema, options } = normalizeZodArgs(arg1, arg2, arg3, arg4);
248
- const { finalMainInstruction, response_format } = _getZodPromptConfig(mainInstruction, dataExtractionSchema, options);
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.mainInstruction).toContain('Generate a valid JSON');
13
- (0, vitest_1.expect)(result.userMessagePayload).toBe('Generate the data.');
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.mainInstruction).toContain('Generate a valid JSON');
21
- (0, vitest_1.expect)(result.userMessagePayload).toBe('Generate the data.');
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.mainInstruction).toContain('You are a helpful assistant');
29
- (0, vitest_1.expect)(result.userMessagePayload).toBe(prompt);
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.mainInstruction).toContain('You are a helpful assistant');
38
- (0, vitest_1.expect)(result.userMessagePayload).toBe(prompt);
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.mainInstruction).toBe(system);
47
- (0, vitest_1.expect)(result.userMessagePayload).toBe(user);
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.mainInstruction).toBe(system);
57
- (0, vitest_1.expect)(result.userMessagePayload).toBe(user);
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
  });
@@ -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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-fns",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",