promptfoo 0.8.3 → 0.10.0

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.
Files changed (55) hide show
  1. package/README.md +5 -5
  2. package/dist/assertions.d.ts +3 -3
  3. package/dist/assertions.d.ts.map +1 -1
  4. package/dist/assertions.js +11 -12
  5. package/dist/assertions.js.map +1 -1
  6. package/dist/cache.d.ts.map +1 -1
  7. package/dist/cache.js +9 -9
  8. package/dist/cache.js.map +1 -1
  9. package/dist/evaluator.d.ts +1 -1
  10. package/dist/evaluator.d.ts.map +1 -1
  11. package/dist/evaluator.js +60 -34
  12. package/dist/evaluator.js.map +1 -1
  13. package/dist/index.d.ts +10 -10
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +18 -14
  16. package/dist/index.js.map +1 -1
  17. package/dist/main.js +41 -40
  18. package/dist/main.js.map +1 -1
  19. package/dist/providers/localai.js +11 -11
  20. package/dist/providers/localai.js.map +1 -1
  21. package/dist/providers/openai.d.ts.map +1 -1
  22. package/dist/providers/openai.js +30 -21
  23. package/dist/providers/openai.js.map +1 -1
  24. package/dist/providers.d.ts +3 -3
  25. package/dist/providers.d.ts.map +1 -1
  26. package/dist/providers.js +15 -15
  27. package/dist/providers.js.map +1 -1
  28. package/dist/types.d.ts +5 -2
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/util.d.ts +2 -2
  31. package/dist/util.d.ts.map +1 -1
  32. package/dist/util.js +43 -15
  33. package/dist/util.js.map +1 -1
  34. package/dist/web/client/assets/index-9a9ba400.css +1 -0
  35. package/dist/web/client/assets/{index-8751749f.js → index-b72d3ca9.js} +12 -12
  36. package/dist/web/client/index.html +2 -2
  37. package/dist/web/server.js +9 -9
  38. package/dist/web/server.js.map +1 -1
  39. package/package.json +3 -1
  40. package/src/assertions.ts +8 -9
  41. package/src/cache.ts +5 -4
  42. package/src/evaluator.ts +66 -33
  43. package/src/index.ts +13 -8
  44. package/src/main.ts +13 -18
  45. package/src/providers/localai.ts +3 -3
  46. package/src/providers/openai.ts +16 -8
  47. package/src/providers.ts +3 -3
  48. package/src/types.ts +7 -2
  49. package/src/util.ts +42 -20
  50. package/src/web/client/package-lock.json +5729 -0
  51. package/src/web/client/src/ResultsTable.css +19 -0
  52. package/src/web/client/src/ResultsTable.tsx +51 -37
  53. package/src/web/client/src/ResultsView.tsx +7 -7
  54. package/src/web/server.ts +3 -3
  55. package/dist/web/client/assets/index-207192fc.css +0 -1
package/src/util.ts CHANGED
@@ -10,19 +10,13 @@ import { parse as parsePath } from 'path';
10
10
  import { parse as parseCsv } from 'csv-parse/sync';
11
11
  import { stringify } from 'csv-stringify/sync';
12
12
 
13
- import logger from './logger.js';
14
- import { getDirectory } from './esm.js';
13
+ import logger from './logger';
14
+ import { getDirectory } from './esm';
15
15
 
16
16
  import type { RequestInfo, RequestInit, Response } from 'node-fetch';
17
17
 
18
- import type {
19
- Assertion,
20
- CsvRow,
21
- EvaluateSummary,
22
- UnifiedConfig,
23
- TestCase,
24
- } from './types.js';
25
- import { assertionFromString } from './assertions.js';
18
+ import type { Assertion, CsvRow, EvaluateSummary, UnifiedConfig, TestCase, Prompt } from './types';
19
+ import { assertionFromString } from './assertions';
26
20
 
27
21
  const PROMPT_DELIMITER = '---';
28
22
 
@@ -50,17 +44,36 @@ export function readConfig(configPath: string): UnifiedConfig {
50
44
  case '.js':
51
45
  return require(configPath) as UnifiedConfig;
52
46
  case '.yaml':
47
+ case '.yml':
53
48
  return yaml.load(fs.readFileSync(configPath, 'utf-8')) as UnifiedConfig;
54
49
  default:
55
50
  throw new Error(`Unsupported configuration file format: ${ext}`);
56
51
  }
57
52
  }
58
53
 
59
- export function readPrompts(promptPathsOrGlobs: string | string[]): string[] {
60
- promptPathsOrGlobs =
61
- typeof promptPathsOrGlobs === 'string' ? [promptPathsOrGlobs] : promptPathsOrGlobs;
62
- const promptPaths = promptPathsOrGlobs.flatMap((pathOrGlob) => globSync(pathOrGlob));
63
- let promptContents: string[] = [];
54
+ enum PromptInputType {
55
+ STRING = 1,
56
+ ARRAY = 2,
57
+ NAMED = 3,
58
+ }
59
+
60
+ export function readPrompts(
61
+ promptPathOrGlobs: string | string[] | Record<string, string>,
62
+ ): Prompt[] {
63
+ let promptPaths: string[] = [];
64
+ let promptContents: Prompt[] = [];
65
+
66
+ let inputType: PromptInputType | undefined;
67
+ if (typeof promptPathOrGlobs === 'string') {
68
+ promptPaths = [promptPathOrGlobs];
69
+ inputType = PromptInputType.STRING;
70
+ } else if (Array.isArray(promptPathOrGlobs)) {
71
+ promptPaths = promptPathOrGlobs.flatMap((pathOrGlob) => globSync(pathOrGlob));
72
+ inputType = PromptInputType.ARRAY;
73
+ } else if (typeof promptPathOrGlobs === 'object') {
74
+ promptPaths = Object.keys(promptPathOrGlobs);
75
+ inputType = PromptInputType.NAMED;
76
+ }
64
77
 
65
78
  for (const promptPath of promptPaths) {
66
79
  const stat = fs.statSync(promptPath);
@@ -69,18 +82,27 @@ export function readPrompts(promptPathsOrGlobs: string | string[]): string[] {
69
82
  const fileContents = filesInDirectory.map((fileName) =>
70
83
  fs.readFileSync(path.join(promptPath, fileName), 'utf-8'),
71
84
  );
72
- promptContents.push(...fileContents);
85
+ promptContents.push(...fileContents.map((content) => ({ raw: content, display: content })));
73
86
  } else {
74
87
  const fileContent = fs.readFileSync(promptPath, 'utf-8');
75
- promptContents.push(fileContent);
88
+ let display;
89
+ if (inputType === PromptInputType.NAMED) {
90
+ display = (promptPathOrGlobs as Record<string, string>)[promptPath];
91
+ } else {
92
+ display = fileContent.length > 200 ? promptPath : fileContent;
93
+ }
94
+ promptContents.push({ raw: fileContent, display });
76
95
  }
77
96
  }
78
97
 
79
- if (promptContents.length === 1) {
80
- promptContents = promptContents[0].split(PROMPT_DELIMITER).map((p) => p.trim());
98
+ if (promptContents.length === 1 && inputType !== PromptInputType.NAMED) {
99
+ const content = promptContents[0].raw;
100
+ promptContents = content
101
+ .split(PROMPT_DELIMITER)
102
+ .map((p) => ({ raw: p.trim(), display: p.trim() }));
81
103
  }
82
104
  if (promptContents.length === 0) {
83
- throw new Error(`There are no prompts in ${promptPathsOrGlobs.join(', ')}`);
105
+ throw new Error(`There are no prompts in ${JSON.stringify(promptPathOrGlobs)}`);
84
106
  }
85
107
  return promptContents;
86
108
  }