promptfoo 0.69.1 → 0.70.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 (170) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/assertions/AssertionsResult.d.ts.map +1 -1
  3. package/dist/src/assertions/AssertionsResult.js +16 -1
  4. package/dist/src/assertions/AssertionsResult.js.map +1 -1
  5. package/dist/src/assertions.d.ts +5 -9
  6. package/dist/src/assertions.d.ts.map +1 -1
  7. package/dist/src/assertions.js +12 -9
  8. package/dist/src/assertions.js.map +1 -1
  9. package/dist/src/commands/eval.d.ts +5 -0
  10. package/dist/src/commands/eval.d.ts.map +1 -0
  11. package/dist/src/commands/eval.js +280 -0
  12. package/dist/src/commands/eval.js.map +1 -0
  13. package/dist/src/commands/generate.d.ts +20 -0
  14. package/dist/src/commands/generate.d.ts.map +1 -0
  15. package/dist/src/commands/generate.js +215 -0
  16. package/dist/src/commands/generate.js.map +1 -0
  17. package/dist/src/commands/redteam.d.ts +10 -0
  18. package/dist/src/commands/redteam.d.ts.map +1 -0
  19. package/dist/src/commands/redteam.js +191 -0
  20. package/dist/src/commands/redteam.js.map +1 -0
  21. package/dist/src/config.d.ts +17 -0
  22. package/dist/src/config.d.ts.map +1 -0
  23. package/dist/src/config.js +424 -0
  24. package/dist/src/config.js.map +1 -0
  25. package/dist/src/evaluator.d.ts.map +1 -1
  26. package/dist/src/evaluator.js +1 -3
  27. package/dist/src/evaluator.js.map +1 -1
  28. package/dist/src/main.js +13 -569
  29. package/dist/src/main.js.map +1 -1
  30. package/dist/src/redteam/constants.d.ts +5 -0
  31. package/dist/src/redteam/constants.d.ts.map +1 -1
  32. package/dist/src/redteam/constants.js +53 -1
  33. package/dist/src/redteam/constants.js.map +1 -1
  34. package/dist/src/redteam/index.d.ts +0 -2
  35. package/dist/src/redteam/index.d.ts.map +1 -1
  36. package/dist/src/redteam/index.js +25 -41
  37. package/dist/src/redteam/index.js.map +1 -1
  38. package/dist/src/redteam/iterative.d.ts +1 -1
  39. package/dist/src/redteam/iterative.js +1 -1
  40. package/dist/src/redteam/iterative.js.map +1 -1
  41. package/dist/src/redteam/iterativeImage.d.ts +1 -1
  42. package/dist/src/redteam/iterativeImage.js +1 -1
  43. package/dist/src/redteam/iterativeImage.js.map +1 -1
  44. package/dist/src/redteam/plugins/base.d.ts +35 -0
  45. package/dist/src/redteam/plugins/base.d.ts.map +1 -0
  46. package/dist/src/redteam/plugins/base.js +48 -0
  47. package/dist/src/redteam/plugins/base.js.map +1 -0
  48. package/dist/src/redteam/plugins/competitors.d.ts +10 -0
  49. package/dist/src/redteam/plugins/competitors.d.ts.map +1 -0
  50. package/dist/src/redteam/plugins/competitors.js +47 -0
  51. package/dist/src/redteam/plugins/competitors.js.map +1 -0
  52. package/dist/src/redteam/plugins/contracts.d.ts +10 -0
  53. package/dist/src/redteam/plugins/contracts.d.ts.map +1 -0
  54. package/dist/src/redteam/plugins/contracts.js +47 -0
  55. package/dist/src/redteam/plugins/contracts.js.map +1 -0
  56. package/dist/src/redteam/plugins/excessiveAgency.d.ts +10 -0
  57. package/dist/src/redteam/plugins/excessiveAgency.d.ts.map +1 -0
  58. package/dist/src/redteam/plugins/excessiveAgency.js +42 -0
  59. package/dist/src/redteam/plugins/excessiveAgency.js.map +1 -0
  60. package/dist/src/redteam/plugins/hallucination.d.ts +10 -0
  61. package/dist/src/redteam/plugins/hallucination.d.ts.map +1 -0
  62. package/dist/src/redteam/plugins/hallucination.js +43 -0
  63. package/dist/src/redteam/plugins/hallucination.js.map +1 -0
  64. package/dist/src/redteam/{getHarmfulTests.d.ts → plugins/harmful.d.ts} +9 -9
  65. package/dist/src/redteam/plugins/harmful.d.ts.map +1 -0
  66. package/dist/src/redteam/{getHarmfulTests.js → plugins/harmful.js} +2 -2
  67. package/dist/src/redteam/plugins/harmful.js.map +1 -0
  68. package/dist/src/redteam/plugins/hijacking.d.ts +10 -0
  69. package/dist/src/redteam/plugins/hijacking.d.ts.map +1 -0
  70. package/dist/src/redteam/plugins/hijacking.js +47 -0
  71. package/dist/src/redteam/plugins/hijacking.js.map +1 -0
  72. package/dist/src/redteam/plugins/overreliance.d.ts +10 -0
  73. package/dist/src/redteam/plugins/overreliance.d.ts.map +1 -0
  74. package/dist/src/redteam/plugins/overreliance.js +42 -0
  75. package/dist/src/redteam/plugins/overreliance.js.map +1 -0
  76. package/dist/src/redteam/{getPiiTests.d.ts → plugins/pii.d.ts} +2 -2
  77. package/dist/src/redteam/plugins/pii.d.ts.map +1 -0
  78. package/dist/src/redteam/{getPiiTests.js → plugins/pii.js} +2 -2
  79. package/dist/src/redteam/plugins/pii.js.map +1 -0
  80. package/dist/src/redteam/plugins/politics.d.ts +10 -0
  81. package/dist/src/redteam/plugins/politics.d.ts.map +1 -0
  82. package/dist/src/redteam/plugins/politics.js +57 -0
  83. package/dist/src/redteam/plugins/politics.js.map +1 -0
  84. package/dist/src/types.d.ts +13 -3
  85. package/dist/src/types.d.ts.map +1 -1
  86. package/dist/src/types.js +6 -1
  87. package/dist/src/types.js.map +1 -1
  88. package/dist/src/util.d.ts +0 -10
  89. package/dist/src/util.d.ts.map +1 -1
  90. package/dist/src/util.js +1 -244
  91. package/dist/src/util.js.map +1 -1
  92. package/dist/src/web/nextui/404/index.html +1 -1
  93. package/dist/src/web/nextui/404.html +1 -1
  94. package/dist/src/web/nextui/_next/static/chunks/858-5d3a3678769b7e36.js +1 -1
  95. package/dist/src/web/nextui/_next/static/chunks/954-58788165fb1e9563.js +6 -0
  96. package/dist/src/web/nextui/_next/static/chunks/app/auth/login/{page-6fcc9431205718c7.js → page-ee73165dd261f3ca.js} +1 -1
  97. package/dist/src/web/nextui/_next/static/chunks/app/auth/signup/{page-8caf49a834d34420.js → page-7375a6707eb8675e.js} +1 -1
  98. package/dist/src/web/nextui/_next/static/chunks/app/datasets/page-c11cfb1b2c58325f.js +1 -0
  99. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-50073ee4b153b82b.js +1 -0
  100. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/{page-3c5a944373865122.js → page-310e2e58179970fa.js} +1 -1
  101. package/dist/src/web/nextui/_next/static/chunks/app/eval/page-87d1e9bc26842e95.js +1 -0
  102. package/dist/src/web/nextui/_next/static/chunks/app/{layout-2038906de6c19565.js → layout-6b3048b719443145.js} +1 -1
  103. package/dist/src/web/nextui/_next/static/chunks/app/{page-e07a0ddbf3d6e21c.js → page-251d4ea0ac894cd9.js} +1 -1
  104. package/dist/src/web/nextui/_next/static/chunks/app/progress/page-15df1d043dee2f17.js +1 -0
  105. package/dist/src/web/nextui/_next/static/chunks/app/prompts/{page-50e27c24c9e255bd.js → page-6d29c01079a556f4.js} +1 -1
  106. package/dist/src/web/nextui/_next/static/chunks/app/report/{page-a0a68795eb905dcc.js → page-af906219ba2d368f.js} +1 -1
  107. package/dist/src/web/nextui/_next/static/chunks/app/setup/{page-26cb5d2478fdbd34.js → page-5a4d6156d3c83470.js} +1 -1
  108. package/dist/src/web/nextui/_next/static/chunks/{main-app-929a26b3c8cd3f7a.js → main-app-345c3eca7e5cf432.js} +1 -1
  109. package/dist/src/web/nextui/_next/static/chunks/{webpack-8a9bc9ee0defb756.js → webpack-c9f728822666f852.js} +1 -1
  110. package/dist/src/web/nextui/_next/static/css/5bd2f45de1f3ba83.css +1 -0
  111. package/dist/src/web/nextui/auth/login/index.html +1 -1
  112. package/dist/src/web/nextui/auth/login/index.txt +6 -6
  113. package/dist/src/web/nextui/auth/signup/index.html +1 -1
  114. package/dist/src/web/nextui/auth/signup/index.txt +6 -6
  115. package/dist/src/web/nextui/datasets/index.html +1 -1
  116. package/dist/src/web/nextui/datasets/index.txt +6 -6
  117. package/dist/src/web/nextui/eval/index.html +1 -1
  118. package/dist/src/web/nextui/eval/index.txt +6 -6
  119. package/dist/src/web/nextui/index.html +1 -1
  120. package/dist/src/web/nextui/index.txt +5 -5
  121. package/dist/src/web/nextui/progress/index.html +1 -1
  122. package/dist/src/web/nextui/progress/index.txt +6 -6
  123. package/dist/src/web/nextui/prompts/index.html +1 -1
  124. package/dist/src/web/nextui/prompts/index.txt +6 -6
  125. package/dist/src/web/nextui/report/index.html +1 -1
  126. package/dist/src/web/nextui/report/index.txt +6 -6
  127. package/dist/src/web/nextui/setup/index.html +2 -2
  128. package/dist/src/web/nextui/setup/index.txt +7 -7
  129. package/package.json +1 -1
  130. package/dist/src/redteam/getCompetitorTests.d.ts +0 -3
  131. package/dist/src/redteam/getCompetitorTests.d.ts.map +0 -1
  132. package/dist/src/redteam/getCompetitorTests.js +0 -60
  133. package/dist/src/redteam/getCompetitorTests.js.map +0 -1
  134. package/dist/src/redteam/getHallucinationTests.d.ts +0 -3
  135. package/dist/src/redteam/getHallucinationTests.d.ts.map +0 -1
  136. package/dist/src/redteam/getHallucinationTests.js +0 -56
  137. package/dist/src/redteam/getHallucinationTests.js.map +0 -1
  138. package/dist/src/redteam/getHarmfulTests.d.ts.map +0 -1
  139. package/dist/src/redteam/getHarmfulTests.js.map +0 -1
  140. package/dist/src/redteam/getHijackingTests.d.ts +0 -3
  141. package/dist/src/redteam/getHijackingTests.d.ts.map +0 -1
  142. package/dist/src/redteam/getHijackingTests.js +0 -60
  143. package/dist/src/redteam/getHijackingTests.js.map +0 -1
  144. package/dist/src/redteam/getOverconfidenceTests.d.ts +0 -3
  145. package/dist/src/redteam/getOverconfidenceTests.d.ts.map +0 -1
  146. package/dist/src/redteam/getOverconfidenceTests.js +0 -55
  147. package/dist/src/redteam/getOverconfidenceTests.js.map +0 -1
  148. package/dist/src/redteam/getPiiTests.d.ts.map +0 -1
  149. package/dist/src/redteam/getPiiTests.js.map +0 -1
  150. package/dist/src/redteam/getPoliticalStatementsTests.d.ts +0 -3
  151. package/dist/src/redteam/getPoliticalStatementsTests.d.ts.map +0 -1
  152. package/dist/src/redteam/getPoliticalStatementsTests.js +0 -70
  153. package/dist/src/redteam/getPoliticalStatementsTests.js.map +0 -1
  154. package/dist/src/redteam/getUnderconfidenceTests.d.ts +0 -3
  155. package/dist/src/redteam/getUnderconfidenceTests.d.ts.map +0 -1
  156. package/dist/src/redteam/getUnderconfidenceTests.js +0 -55
  157. package/dist/src/redteam/getUnderconfidenceTests.js.map +0 -1
  158. package/dist/src/redteam/getUnintendedContractTests.d.ts +0 -3
  159. package/dist/src/redteam/getUnintendedContractTests.d.ts.map +0 -1
  160. package/dist/src/redteam/getUnintendedContractTests.js +0 -60
  161. package/dist/src/redteam/getUnintendedContractTests.js.map +0 -1
  162. package/dist/src/web/nextui/_next/static/chunks/954-c35d4864ecbacd62.js +0 -6
  163. package/dist/src/web/nextui/_next/static/chunks/app/datasets/page-4f93aacd25866d60.js +0 -1
  164. package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-ce320e6d1e6d1d23.js +0 -1
  165. package/dist/src/web/nextui/_next/static/chunks/app/eval/page-73e894c39cc191f1.js +0 -1
  166. package/dist/src/web/nextui/_next/static/chunks/app/progress/page-73442c531d579c51.js +0 -1
  167. package/dist/src/web/nextui/_next/static/css/106779eb64615639.css +0 -1
  168. /package/dist/src/web/nextui/_next/static/{1r10QuQFZj3AAU-Bx1DRP → 46JfY2NdEDFuAccLbcAJl}/_buildManifest.js +0 -0
  169. /package/dist/src/web/nextui/_next/static/{1r10QuQFZj3AAU-Bx1DRP → 46JfY2NdEDFuAccLbcAJl}/_ssgManifest.js +0 -0
  170. /package/dist/src/web/nextui/_next/static/chunks/{2-671ad31c05d2c976.js → 2-57ab5e84907f795a.js} +0 -0
@@ -0,0 +1,191 @@
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.doRunRedteam = doRunRedteam;
30
+ exports.redteamCommand = redteamCommand;
31
+ const chalk_1 = __importDefault(require("chalk"));
32
+ const fs = __importStar(require("fs"));
33
+ const inquirer_1 = __importDefault(require("inquirer"));
34
+ const js_yaml_1 = __importDefault(require("js-yaml"));
35
+ const path = __importStar(require("path"));
36
+ const logger_1 = __importDefault(require("../logger"));
37
+ const constants_1 = require("../redteam/constants");
38
+ const telemetry_1 = __importDefault(require("../telemetry"));
39
+ const generate_1 = require("./generate");
40
+ async function doRunRedteam(cmdObj) { }
41
+ function redteamCommand(program) {
42
+ const redteamCommand = program.command('redteam').description('Red team LLM applications');
43
+ redteamCommand
44
+ .command('init [directory]')
45
+ .description('Initialize red teaming project')
46
+ .action(async (directory) => {
47
+ telemetry_1.default.maybeShowNotice();
48
+ telemetry_1.default.record('command_used', {
49
+ name: 'redteam init - started',
50
+ });
51
+ await telemetry_1.default.send();
52
+ let projectDir = directory;
53
+ if (!projectDir) {
54
+ const { chosenDir } = await inquirer_1.default.prompt([
55
+ {
56
+ type: 'input',
57
+ name: 'chosenDir',
58
+ message: 'Where do you want to create the project?',
59
+ default: '.',
60
+ },
61
+ ]);
62
+ projectDir = chosenDir || '.';
63
+ }
64
+ if (projectDir !== '.' && !fs.existsSync(projectDir)) {
65
+ fs.mkdirSync(projectDir, { recursive: true });
66
+ }
67
+ // Question 2: Prompt
68
+ const { promptChoice } = await inquirer_1.default.prompt([
69
+ {
70
+ type: 'list',
71
+ name: 'promptChoice',
72
+ message: 'How would you like to specify the prompt?',
73
+ choices: [
74
+ { name: 'Enter a prompt', value: 'enter' },
75
+ { name: 'Reference a prompt file', value: 'file' },
76
+ ],
77
+ },
78
+ ]);
79
+ let prompt;
80
+ if (promptChoice === 'enter') {
81
+ const { enteredPrompt } = await inquirer_1.default.prompt([
82
+ {
83
+ type: 'editor',
84
+ name: 'enteredPrompt',
85
+ message: 'Enter your prompt:',
86
+ default: 'You are a helpful concise assistant.\n\nUser query: {{query}}\n\n(NOTE: your prompt must include "{{query}}" as a placeholder for user input)',
87
+ },
88
+ ]);
89
+ prompt = enteredPrompt;
90
+ }
91
+ else {
92
+ const { promptFile } = await inquirer_1.default.prompt([
93
+ {
94
+ type: 'input',
95
+ name: 'promptFile',
96
+ message: 'Enter the path to your prompt file (text or JSON):',
97
+ },
98
+ ]);
99
+ prompt = `file://${promptFile}`;
100
+ }
101
+ // Question 3: Provider
102
+ let provider;
103
+ const { providerChoice } = await inquirer_1.default.prompt([
104
+ {
105
+ type: 'list',
106
+ name: 'providerChoice',
107
+ message: 'Choose a provider:',
108
+ choices: [
109
+ 'openai:gpt-3.5-turbo',
110
+ 'openai:gpt-4',
111
+ 'anthropic:messages:claude-3-5-sonnet-20240620',
112
+ 'anthropic:messages:claude-3-opus-20240307',
113
+ 'vertex:gemini-pro',
114
+ 'Other',
115
+ ],
116
+ },
117
+ ]);
118
+ if (providerChoice === 'Other') {
119
+ const { customProvider } = await inquirer_1.default.prompt([
120
+ {
121
+ type: 'input',
122
+ name: 'customProvider',
123
+ message: 'Enter the provider ID (see https://www.promptfoo.dev/docs/providers/ for options):',
124
+ },
125
+ ]);
126
+ provider = customProvider;
127
+ }
128
+ else {
129
+ provider = providerChoice;
130
+ }
131
+ // Question 4: Plugins
132
+ const pluginChoices = Array.from(constants_1.ALL_PLUGINS).map((plugin) => ({
133
+ name: `${plugin} - ${constants_1.subCategoryDescriptions[plugin] || 'No description available'}`,
134
+ value: plugin,
135
+ checked: constants_1.DEFAULT_PLUGINS.has(plugin),
136
+ }));
137
+ const { selectedPlugins } = await inquirer_1.default.prompt([
138
+ {
139
+ type: 'checkbox',
140
+ name: 'selectedPlugins',
141
+ message: 'Select the plugins you want to enable:',
142
+ choices: pluginChoices,
143
+ pageSize: 20,
144
+ },
145
+ ]);
146
+ const plugins = selectedPlugins;
147
+ // Create config file
148
+ const config = {
149
+ prompts: [prompt],
150
+ providers: [provider],
151
+ tests: [],
152
+ };
153
+ const configPath = path.join(projectDir, 'promptfooconfig.yaml');
154
+ fs.writeFileSync(configPath, js_yaml_1.default.dump(config), 'utf8');
155
+ logger_1.default.info('\n' + chalk_1.default.green(`Created red teaming configuration file at ${configPath}`) + '\n');
156
+ const { readyToGenerate } = await inquirer_1.default.prompt([
157
+ {
158
+ type: 'confirm',
159
+ name: 'readyToGenerate',
160
+ message: 'Are you ready to generate adversarial test cases?',
161
+ default: true,
162
+ },
163
+ ]);
164
+ telemetry_1.default.record('command_used', {
165
+ name: 'redteam init',
166
+ });
167
+ await telemetry_1.default.send();
168
+ if (readyToGenerate) {
169
+ await (0, generate_1.doGenerateRedteam)({
170
+ plugins,
171
+ cache: false,
172
+ write: true,
173
+ defaultConfig: config,
174
+ defaultConfigPath: configPath,
175
+ });
176
+ }
177
+ else {
178
+ logger_1.default.info('\n' +
179
+ chalk_1.default.blue('To generate test cases later, use the command: ' +
180
+ chalk_1.default.bold('promptfoo generate redteam')));
181
+ }
182
+ });
183
+ redteamCommand
184
+ .command('run')
185
+ .description('Run red teaming evaluation')
186
+ .option('-c, --config <path>', 'Path to configuration file')
187
+ .option('--no-cache', 'Disable cache', false)
188
+ .option('--env-file <path>', 'Path to .env file')
189
+ .action(doRunRedteam);
190
+ }
191
+ //# sourceMappingURL=redteam.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redteam.js","sourceRoot":"","sources":["../../../src/commands/redteam.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { CommandLineOptions, TestSuite, UnifiedConfig } from './types';
2
+ export declare function dereferenceConfig(rawConfig: UnifiedConfig): Promise<UnifiedConfig>;
3
+ export declare function readConfig(configPath: string): Promise<UnifiedConfig>;
4
+ export declare function maybeReadConfig(configPath: string): Promise<UnifiedConfig | undefined>;
5
+ /**
6
+ * Reads multiple configuration files and combines them into a single UnifiedConfig.
7
+ *
8
+ * @param {string[]} configPaths - An array of paths to configuration files. Supports glob patterns.
9
+ * @returns {Promise<UnifiedConfig>} A promise that resolves to a unified configuration object.
10
+ */
11
+ export declare function readConfigs(configPaths: string[]): Promise<UnifiedConfig>;
12
+ export declare function resolveConfigs(cmdObj: Partial<CommandLineOptions>, defaultConfig: Partial<UnifiedConfig>): Promise<{
13
+ testSuite: TestSuite;
14
+ config: Partial<UnifiedConfig>;
15
+ basePath: string;
16
+ }>;
17
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,kBAAkB,EAKlB,SAAS,EACT,aAAa,EACd,MAAM,SAAS,CAAC;AAGjB,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAoGxF;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAe3E;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAK5F;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAkI/E;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,EACnC,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,GACpC,OAAO,CAAC;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAsKrF"}
@@ -0,0 +1,424 @@
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.dereferenceConfig = dereferenceConfig;
30
+ exports.readConfig = readConfig;
31
+ exports.maybeReadConfig = maybeReadConfig;
32
+ exports.readConfigs = readConfigs;
33
+ exports.resolveConfigs = resolveConfigs;
34
+ const json_schema_ref_parser_1 = __importDefault(require("@apidevtools/json-schema-ref-parser"));
35
+ const chalk_1 = __importDefault(require("chalk"));
36
+ const dedent_1 = __importDefault(require("dedent"));
37
+ const fs = __importStar(require("fs"));
38
+ const glob_1 = require("glob");
39
+ const js_yaml_1 = __importDefault(require("js-yaml"));
40
+ const path = __importStar(require("path"));
41
+ const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
42
+ const assertions_1 = require("./assertions");
43
+ const validateAssertions_1 = require("./assertions/validateAssertions");
44
+ const filterTests_1 = require("./commands/eval/filterTests");
45
+ const esm_1 = require("./esm");
46
+ const logger_1 = __importDefault(require("./logger"));
47
+ const prompts_1 = require("./prompts");
48
+ const providers_1 = require("./providers");
49
+ const testCases_1 = require("./testCases");
50
+ const types_1 = require("./types");
51
+ const util_1 = require("./util");
52
+ async function dereferenceConfig(rawConfig) {
53
+ if (process.env.PROMPTFOO_DISABLE_REF_PARSER) {
54
+ return rawConfig;
55
+ }
56
+ // Track and delete tools[i].function for each tool, preserving the rest of the properties
57
+ // https://github.com/promptfoo/promptfoo/issues/364
58
+ // Remove parameters from functions and tools to prevent dereferencing
59
+ const extractFunctionParameters = (functions) => {
60
+ return functions.map((func) => {
61
+ const { parameters } = func;
62
+ delete func.parameters;
63
+ return { parameters };
64
+ });
65
+ };
66
+ const extractToolParameters = (tools) => {
67
+ return tools.map((tool) => {
68
+ const { parameters } = tool.function || {};
69
+ if (tool.function?.parameters) {
70
+ delete tool.function.parameters;
71
+ }
72
+ return { parameters };
73
+ });
74
+ };
75
+ // Restore parameters to functions and tools after dereferencing
76
+ const restoreFunctionParameters = (functions, parametersList) => {
77
+ functions.forEach((func, index) => {
78
+ if (parametersList[index]?.parameters) {
79
+ func.parameters = parametersList[index].parameters;
80
+ }
81
+ });
82
+ };
83
+ const restoreToolParameters = (tools, parametersList) => {
84
+ tools.forEach((tool, index) => {
85
+ if (parametersList[index]?.parameters) {
86
+ tool.function = tool.function || {};
87
+ tool.function.parameters = parametersList[index].parameters;
88
+ }
89
+ });
90
+ };
91
+ const functionsParametersList = [];
92
+ const toolsParametersList = [];
93
+ if (Array.isArray(rawConfig.providers)) {
94
+ rawConfig.providers.forEach((provider, providerIndex) => {
95
+ if (typeof provider === 'string')
96
+ return;
97
+ if (typeof provider === 'function')
98
+ return;
99
+ if (!provider.config) {
100
+ // Handle when provider is a map
101
+ provider = Object.values(provider)[0];
102
+ }
103
+ if (provider.config?.functions) {
104
+ functionsParametersList[providerIndex] = extractFunctionParameters(provider.config.functions);
105
+ }
106
+ if (provider.config?.tools) {
107
+ toolsParametersList[providerIndex] = extractToolParameters(provider.config.tools);
108
+ }
109
+ });
110
+ }
111
+ // Dereference JSON
112
+ const config = (await json_schema_ref_parser_1.default.dereference(rawConfig));
113
+ // Restore functions and tools parameters
114
+ if (Array.isArray(config.providers)) {
115
+ config.providers.forEach((provider, index) => {
116
+ if (typeof provider === 'string')
117
+ return;
118
+ if (typeof provider === 'function')
119
+ return;
120
+ if (!provider.config) {
121
+ // Handle when provider is a map
122
+ provider = Object.values(provider)[0];
123
+ }
124
+ if (functionsParametersList[index]) {
125
+ provider.config.functions = provider.config.functions || [];
126
+ restoreFunctionParameters(provider.config.functions, functionsParametersList[index]);
127
+ }
128
+ if (toolsParametersList[index]) {
129
+ provider.config.tools = provider.config.tools || [];
130
+ restoreToolParameters(provider.config.tools, toolsParametersList[index]);
131
+ }
132
+ });
133
+ }
134
+ return config;
135
+ }
136
+ async function readConfig(configPath) {
137
+ const ext = path.parse(configPath).ext;
138
+ switch (ext) {
139
+ case '.json':
140
+ case '.yaml':
141
+ case '.yml':
142
+ const rawConfig = js_yaml_1.default.load(fs.readFileSync(configPath, 'utf-8'));
143
+ return dereferenceConfig(rawConfig);
144
+ case '.js':
145
+ case '.cjs':
146
+ case '.mjs':
147
+ return (await (0, esm_1.importModule)(configPath));
148
+ default:
149
+ throw new Error(`Unsupported configuration file format: ${ext}`);
150
+ }
151
+ }
152
+ async function maybeReadConfig(configPath) {
153
+ if (!fs.existsSync(configPath)) {
154
+ return undefined;
155
+ }
156
+ return readConfig(configPath);
157
+ }
158
+ /**
159
+ * Reads multiple configuration files and combines them into a single UnifiedConfig.
160
+ *
161
+ * @param {string[]} configPaths - An array of paths to configuration files. Supports glob patterns.
162
+ * @returns {Promise<UnifiedConfig>} A promise that resolves to a unified configuration object.
163
+ */
164
+ async function readConfigs(configPaths) {
165
+ const configs = [];
166
+ for (const configPath of configPaths) {
167
+ const globPaths = (0, glob_1.globSync)(configPath, {
168
+ windowsPathsNoEscape: true,
169
+ });
170
+ if (globPaths.length === 0) {
171
+ throw new Error(`No configuration file found at ${configPath}`);
172
+ }
173
+ for (const globPath of globPaths) {
174
+ const config = await readConfig(globPath);
175
+ configs.push(config);
176
+ }
177
+ }
178
+ const providers = [];
179
+ const seenProviders = new Set();
180
+ configs.forEach((config) => {
181
+ (0, tiny_invariant_1.default)(typeof config.providers !== 'function', 'Providers cannot be a function for multiple configs');
182
+ if (typeof config.providers === 'string') {
183
+ if (!seenProviders.has(config.providers)) {
184
+ providers.push(config.providers);
185
+ seenProviders.add(config.providers);
186
+ }
187
+ }
188
+ else if (Array.isArray(config.providers)) {
189
+ config.providers.forEach((provider) => {
190
+ if (!seenProviders.has(JSON.stringify(provider))) {
191
+ providers.push(provider);
192
+ seenProviders.add(JSON.stringify(provider));
193
+ }
194
+ });
195
+ }
196
+ });
197
+ const tests = [];
198
+ for (const config of configs) {
199
+ if (typeof config.tests === 'string') {
200
+ const newTests = await (0, testCases_1.readTests)(config.tests, path.dirname(configPaths[0]));
201
+ tests.push(...newTests);
202
+ }
203
+ else if (Array.isArray(config.tests)) {
204
+ tests.push(...config.tests);
205
+ }
206
+ }
207
+ const configsAreStringOrArray = configs.every((config) => typeof config.prompts === 'string' || Array.isArray(config.prompts));
208
+ const configsAreObjects = configs.every((config) => typeof config.prompts === 'object');
209
+ let prompts = configsAreStringOrArray ? [] : {};
210
+ const makeAbsolute = (configPath, relativePath) => {
211
+ if (typeof relativePath === 'string') {
212
+ if (relativePath.startsWith('file://')) {
213
+ relativePath =
214
+ 'file://' + path.resolve(path.dirname(configPath), relativePath.slice('file://'.length));
215
+ }
216
+ return relativePath;
217
+ }
218
+ else if (typeof relativePath === 'object' && relativePath.id) {
219
+ if (relativePath.id.startsWith('file://')) {
220
+ relativePath.id =
221
+ 'file://' +
222
+ path.resolve(path.dirname(configPath), relativePath.id.slice('file://'.length));
223
+ }
224
+ return relativePath;
225
+ }
226
+ else {
227
+ throw new Error('Invalid prompt object');
228
+ }
229
+ };
230
+ const seenPrompts = new Set();
231
+ const addSeenPrompt = (prompt) => {
232
+ if (typeof prompt === 'string') {
233
+ seenPrompts.add(prompt);
234
+ }
235
+ else if (typeof prompt === 'object' && prompt.id) {
236
+ seenPrompts.add(prompt);
237
+ }
238
+ else {
239
+ throw new Error('Invalid prompt object');
240
+ }
241
+ };
242
+ configs.forEach((config, idx) => {
243
+ if (typeof config.prompts === 'string') {
244
+ (0, tiny_invariant_1.default)(Array.isArray(prompts), 'Cannot mix string and map-type prompts');
245
+ const absolutePrompt = makeAbsolute(configPaths[idx], config.prompts);
246
+ addSeenPrompt(absolutePrompt);
247
+ }
248
+ else if (Array.isArray(config.prompts)) {
249
+ (0, tiny_invariant_1.default)(Array.isArray(prompts), 'Cannot mix configs with map and array-type prompts');
250
+ config.prompts
251
+ .map((prompt) => makeAbsolute(configPaths[idx], prompt))
252
+ .forEach((prompt) => addSeenPrompt(prompt));
253
+ }
254
+ else {
255
+ // Object format such as { 'prompts/prompt1.txt': 'foo', 'prompts/prompt2.txt': 'bar' }
256
+ (0, tiny_invariant_1.default)(typeof prompts === 'object', 'Cannot mix configs with map and array-type prompts');
257
+ prompts = { ...prompts, ...config.prompts };
258
+ }
259
+ });
260
+ if (Array.isArray(prompts)) {
261
+ prompts.push(...Array.from(seenPrompts));
262
+ }
263
+ // Combine all configs into a single UnifiedConfig
264
+ const combinedConfig = {
265
+ description: configs.map((config) => config.description).join(', '),
266
+ providers,
267
+ prompts,
268
+ tests,
269
+ scenarios: configs.flatMap((config) => config.scenarios || []),
270
+ defaultTest: configs.reduce((prev, curr) => {
271
+ return {
272
+ ...prev,
273
+ ...curr.defaultTest,
274
+ vars: { ...prev?.vars, ...curr.defaultTest?.vars },
275
+ assert: [...(prev?.assert || []), ...(curr.defaultTest?.assert || [])],
276
+ options: { ...prev?.options, ...curr.defaultTest?.options },
277
+ };
278
+ }, {}),
279
+ nunjucksFilters: configs.reduce((prev, curr) => ({ ...prev, ...curr.nunjucksFilters }), {}),
280
+ env: configs.reduce((prev, curr) => ({ ...prev, ...curr.env }), {}),
281
+ evaluateOptions: configs.reduce((prev, curr) => ({ ...prev, ...curr.evaluateOptions }), {}),
282
+ commandLineOptions: configs.reduce((prev, curr) => ({ ...prev, ...curr.commandLineOptions }), {}),
283
+ metadata: configs.reduce((prev, curr) => ({ ...prev, ...curr.metadata }), {}),
284
+ sharing: !configs.some((config) => config.sharing === false),
285
+ };
286
+ return combinedConfig;
287
+ }
288
+ async function resolveConfigs(cmdObj, defaultConfig) {
289
+ // Config parsing
290
+ let fileConfig = {};
291
+ const configPaths = cmdObj.config;
292
+ if (configPaths) {
293
+ fileConfig = await readConfigs(configPaths);
294
+ }
295
+ // Standalone assertion mode
296
+ if (cmdObj.assertions) {
297
+ if (!cmdObj.modelOutputs) {
298
+ logger_1.default.error(chalk_1.default.red('You must provide --model-outputs when using --assertions'));
299
+ process.exit(1);
300
+ }
301
+ const modelOutputs = JSON.parse(fs.readFileSync(path.join(process.cwd(), cmdObj.modelOutputs), 'utf8'));
302
+ const assertions = await (0, assertions_1.readAssertions)(cmdObj.assertions);
303
+ fileConfig.prompts = ['{{output}}'];
304
+ fileConfig.providers = ['echo'];
305
+ fileConfig.tests = modelOutputs.map((output) => {
306
+ if (typeof output === 'string') {
307
+ return {
308
+ vars: {
309
+ output,
310
+ },
311
+ assert: assertions,
312
+ };
313
+ }
314
+ return {
315
+ vars: {
316
+ output: output.output,
317
+ ...(output.tags === undefined ? {} : { tags: output.tags.join(', ') }),
318
+ },
319
+ assert: assertions,
320
+ };
321
+ });
322
+ }
323
+ // Use basepath in cases where path was supplied in the config file
324
+ const basePath = configPaths ? path.dirname(configPaths[0]) : '';
325
+ const defaultTestRaw = fileConfig.defaultTest || defaultConfig.defaultTest;
326
+ const config = {
327
+ description: fileConfig.description || defaultConfig.description,
328
+ prompts: cmdObj.prompts || fileConfig.prompts || defaultConfig.prompts || [],
329
+ providers: cmdObj.providers || fileConfig.providers || defaultConfig.providers || [],
330
+ tests: cmdObj.tests || cmdObj.vars || fileConfig.tests || defaultConfig.tests || [],
331
+ scenarios: fileConfig.scenarios || defaultConfig.scenarios,
332
+ env: fileConfig.env || defaultConfig.env,
333
+ sharing: process.env.PROMPTFOO_DISABLE_SHARING === '1'
334
+ ? false
335
+ : fileConfig.sharing ?? defaultConfig.sharing ?? true,
336
+ defaultTest: defaultTestRaw ? await (0, testCases_1.readTest)(defaultTestRaw, basePath) : undefined,
337
+ derivedMetrics: fileConfig.derivedMetrics || defaultConfig.derivedMetrics,
338
+ outputPath: cmdObj.output || fileConfig.outputPath || defaultConfig.outputPath,
339
+ metadata: fileConfig.metadata || defaultConfig.metadata,
340
+ };
341
+ // Validation
342
+ if (!config.prompts || config.prompts.length === 0) {
343
+ logger_1.default.error(chalk_1.default.red('You must provide at least 1 prompt'));
344
+ process.exit(1);
345
+ }
346
+ if (!config.providers || config.providers.length === 0) {
347
+ logger_1.default.error(chalk_1.default.red('You must specify at least 1 provider (for example, openai:gpt-4o)'));
348
+ process.exit(1);
349
+ }
350
+ (0, tiny_invariant_1.default)(Array.isArray(config.providers), 'providers must be an array');
351
+ config.providers.forEach((provider) => {
352
+ const result = types_1.ProviderSchema.safeParse(provider);
353
+ if (!result.success) {
354
+ const errors = result.error.errors
355
+ .map((err) => {
356
+ return `- ${err.message}`;
357
+ })
358
+ .join('\n');
359
+ const providerString = typeof provider === 'string' ? provider : JSON.stringify(provider);
360
+ logger_1.default.warn(chalk_1.default.yellow((0, dedent_1.default) `
361
+ Provider: ${providerString} encountered errors during schema validation:
362
+
363
+ ${errors}
364
+
365
+ Please double check your configuration.` + '\n'));
366
+ }
367
+ });
368
+ // Parse prompts, providers, and tests
369
+ const parsedPrompts = await (0, prompts_1.readPrompts)(config.prompts, cmdObj.prompts ? undefined : basePath);
370
+ const parsedProviders = await (0, providers_1.loadApiProviders)(config.providers, {
371
+ env: config.env,
372
+ basePath,
373
+ });
374
+ const parsedTests = await (0, testCases_1.readTests)(config.tests || [], cmdObj.tests ? undefined : basePath);
375
+ // Parse testCases for each scenario
376
+ if (fileConfig.scenarios) {
377
+ for (const scenario of fileConfig.scenarios) {
378
+ const parsedScenarioTests = await (0, testCases_1.readTests)(scenario.tests, cmdObj.tests ? undefined : basePath);
379
+ scenario.tests = parsedScenarioTests;
380
+ const filteredTests = await (0, filterTests_1.filterTests)({
381
+ ...scenario,
382
+ providers: parsedProviders,
383
+ prompts: parsedPrompts,
384
+ }, {
385
+ firstN: cmdObj.filterFirstN,
386
+ pattern: cmdObj.filterPattern,
387
+ failing: cmdObj.filterFailing,
388
+ });
389
+ (0, tiny_invariant_1.default)(filteredTests, 'filteredTests are undefined');
390
+ scenario.tests = filteredTests;
391
+ }
392
+ }
393
+ const parsedProviderPromptMap = (0, prompts_1.readProviderPromptMap)(config, parsedPrompts);
394
+ if (parsedPrompts.length === 0) {
395
+ logger_1.default.error(chalk_1.default.red('No prompts found'));
396
+ process.exit(1);
397
+ }
398
+ const defaultTest = {
399
+ options: {
400
+ prefix: cmdObj.promptPrefix,
401
+ suffix: cmdObj.promptSuffix,
402
+ provider: cmdObj.grader,
403
+ // rubricPrompt
404
+ ...(config.defaultTest?.options || {}),
405
+ },
406
+ ...config.defaultTest,
407
+ };
408
+ const testSuite = {
409
+ description: config.description,
410
+ prompts: parsedPrompts,
411
+ providers: parsedProviders,
412
+ providerPromptMap: parsedProviderPromptMap,
413
+ tests: parsedTests,
414
+ scenarios: config.scenarios,
415
+ defaultTest,
416
+ derivedMetrics: config.derivedMetrics,
417
+ nunjucksFilters: await (0, util_1.readFilters)(fileConfig.nunjucksFilters || defaultConfig.nunjucksFilters || {}),
418
+ };
419
+ if (testSuite.tests) {
420
+ (0, validateAssertions_1.validateAssertions)(testSuite.tests);
421
+ }
422
+ return { config, testSuite, basePath };
423
+ }
424
+ //# sourceMappingURL=config.js.map