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.
- package/dist/package.json +1 -1
- package/dist/src/assertions/AssertionsResult.d.ts.map +1 -1
- package/dist/src/assertions/AssertionsResult.js +16 -1
- package/dist/src/assertions/AssertionsResult.js.map +1 -1
- package/dist/src/assertions.d.ts +5 -9
- package/dist/src/assertions.d.ts.map +1 -1
- package/dist/src/assertions.js +12 -9
- package/dist/src/assertions.js.map +1 -1
- package/dist/src/commands/eval.d.ts +5 -0
- package/dist/src/commands/eval.d.ts.map +1 -0
- package/dist/src/commands/eval.js +280 -0
- package/dist/src/commands/eval.js.map +1 -0
- package/dist/src/commands/generate.d.ts +20 -0
- package/dist/src/commands/generate.d.ts.map +1 -0
- package/dist/src/commands/generate.js +215 -0
- package/dist/src/commands/generate.js.map +1 -0
- package/dist/src/commands/redteam.d.ts +10 -0
- package/dist/src/commands/redteam.d.ts.map +1 -0
- package/dist/src/commands/redteam.js +191 -0
- package/dist/src/commands/redteam.js.map +1 -0
- package/dist/src/config.d.ts +17 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +424 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/evaluator.d.ts.map +1 -1
- package/dist/src/evaluator.js +1 -3
- package/dist/src/evaluator.js.map +1 -1
- package/dist/src/main.js +13 -569
- package/dist/src/main.js.map +1 -1
- package/dist/src/redteam/constants.d.ts +5 -0
- package/dist/src/redteam/constants.d.ts.map +1 -1
- package/dist/src/redteam/constants.js +53 -1
- package/dist/src/redteam/constants.js.map +1 -1
- package/dist/src/redteam/index.d.ts +0 -2
- package/dist/src/redteam/index.d.ts.map +1 -1
- package/dist/src/redteam/index.js +25 -41
- package/dist/src/redteam/index.js.map +1 -1
- package/dist/src/redteam/iterative.d.ts +1 -1
- package/dist/src/redteam/iterative.js +1 -1
- package/dist/src/redteam/iterative.js.map +1 -1
- package/dist/src/redteam/iterativeImage.d.ts +1 -1
- package/dist/src/redteam/iterativeImage.js +1 -1
- package/dist/src/redteam/iterativeImage.js.map +1 -1
- package/dist/src/redteam/plugins/base.d.ts +35 -0
- package/dist/src/redteam/plugins/base.d.ts.map +1 -0
- package/dist/src/redteam/plugins/base.js +48 -0
- package/dist/src/redteam/plugins/base.js.map +1 -0
- package/dist/src/redteam/plugins/competitors.d.ts +10 -0
- package/dist/src/redteam/plugins/competitors.d.ts.map +1 -0
- package/dist/src/redteam/plugins/competitors.js +47 -0
- package/dist/src/redteam/plugins/competitors.js.map +1 -0
- package/dist/src/redteam/plugins/contracts.d.ts +10 -0
- package/dist/src/redteam/plugins/contracts.d.ts.map +1 -0
- package/dist/src/redteam/plugins/contracts.js +47 -0
- package/dist/src/redteam/plugins/contracts.js.map +1 -0
- package/dist/src/redteam/plugins/excessiveAgency.d.ts +10 -0
- package/dist/src/redteam/plugins/excessiveAgency.d.ts.map +1 -0
- package/dist/src/redteam/plugins/excessiveAgency.js +42 -0
- package/dist/src/redteam/plugins/excessiveAgency.js.map +1 -0
- package/dist/src/redteam/plugins/hallucination.d.ts +10 -0
- package/dist/src/redteam/plugins/hallucination.d.ts.map +1 -0
- package/dist/src/redteam/plugins/hallucination.js +43 -0
- package/dist/src/redteam/plugins/hallucination.js.map +1 -0
- package/dist/src/redteam/{getHarmfulTests.d.ts → plugins/harmful.d.ts} +9 -9
- package/dist/src/redteam/plugins/harmful.d.ts.map +1 -0
- package/dist/src/redteam/{getHarmfulTests.js → plugins/harmful.js} +2 -2
- package/dist/src/redteam/plugins/harmful.js.map +1 -0
- package/dist/src/redteam/plugins/hijacking.d.ts +10 -0
- package/dist/src/redteam/plugins/hijacking.d.ts.map +1 -0
- package/dist/src/redteam/plugins/hijacking.js +47 -0
- package/dist/src/redteam/plugins/hijacking.js.map +1 -0
- package/dist/src/redteam/plugins/overreliance.d.ts +10 -0
- package/dist/src/redteam/plugins/overreliance.d.ts.map +1 -0
- package/dist/src/redteam/plugins/overreliance.js +42 -0
- package/dist/src/redteam/plugins/overreliance.js.map +1 -0
- package/dist/src/redteam/{getPiiTests.d.ts → plugins/pii.d.ts} +2 -2
- package/dist/src/redteam/plugins/pii.d.ts.map +1 -0
- package/dist/src/redteam/{getPiiTests.js → plugins/pii.js} +2 -2
- package/dist/src/redteam/plugins/pii.js.map +1 -0
- package/dist/src/redteam/plugins/politics.d.ts +10 -0
- package/dist/src/redteam/plugins/politics.d.ts.map +1 -0
- package/dist/src/redteam/plugins/politics.js +57 -0
- package/dist/src/redteam/plugins/politics.js.map +1 -0
- package/dist/src/types.d.ts +13 -3
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +6 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/util.d.ts +0 -10
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +1 -244
- package/dist/src/util.js.map +1 -1
- package/dist/src/web/nextui/404/index.html +1 -1
- package/dist/src/web/nextui/404.html +1 -1
- package/dist/src/web/nextui/_next/static/chunks/858-5d3a3678769b7e36.js +1 -1
- package/dist/src/web/nextui/_next/static/chunks/954-58788165fb1e9563.js +6 -0
- package/dist/src/web/nextui/_next/static/chunks/app/auth/login/{page-6fcc9431205718c7.js → page-ee73165dd261f3ca.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/auth/signup/{page-8caf49a834d34420.js → page-7375a6707eb8675e.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/datasets/page-c11cfb1b2c58325f.js +1 -0
- package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-50073ee4b153b82b.js +1 -0
- package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/{page-3c5a944373865122.js → page-310e2e58179970fa.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/eval/page-87d1e9bc26842e95.js +1 -0
- package/dist/src/web/nextui/_next/static/chunks/app/{layout-2038906de6c19565.js → layout-6b3048b719443145.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/{page-e07a0ddbf3d6e21c.js → page-251d4ea0ac894cd9.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/progress/page-15df1d043dee2f17.js +1 -0
- package/dist/src/web/nextui/_next/static/chunks/app/prompts/{page-50e27c24c9e255bd.js → page-6d29c01079a556f4.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/report/{page-a0a68795eb905dcc.js → page-af906219ba2d368f.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/app/setup/{page-26cb5d2478fdbd34.js → page-5a4d6156d3c83470.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/{main-app-929a26b3c8cd3f7a.js → main-app-345c3eca7e5cf432.js} +1 -1
- package/dist/src/web/nextui/_next/static/chunks/{webpack-8a9bc9ee0defb756.js → webpack-c9f728822666f852.js} +1 -1
- package/dist/src/web/nextui/_next/static/css/5bd2f45de1f3ba83.css +1 -0
- package/dist/src/web/nextui/auth/login/index.html +1 -1
- package/dist/src/web/nextui/auth/login/index.txt +6 -6
- package/dist/src/web/nextui/auth/signup/index.html +1 -1
- package/dist/src/web/nextui/auth/signup/index.txt +6 -6
- package/dist/src/web/nextui/datasets/index.html +1 -1
- package/dist/src/web/nextui/datasets/index.txt +6 -6
- package/dist/src/web/nextui/eval/index.html +1 -1
- package/dist/src/web/nextui/eval/index.txt +6 -6
- package/dist/src/web/nextui/index.html +1 -1
- package/dist/src/web/nextui/index.txt +5 -5
- package/dist/src/web/nextui/progress/index.html +1 -1
- package/dist/src/web/nextui/progress/index.txt +6 -6
- package/dist/src/web/nextui/prompts/index.html +1 -1
- package/dist/src/web/nextui/prompts/index.txt +6 -6
- package/dist/src/web/nextui/report/index.html +1 -1
- package/dist/src/web/nextui/report/index.txt +6 -6
- package/dist/src/web/nextui/setup/index.html +2 -2
- package/dist/src/web/nextui/setup/index.txt +7 -7
- package/package.json +1 -1
- package/dist/src/redteam/getCompetitorTests.d.ts +0 -3
- package/dist/src/redteam/getCompetitorTests.d.ts.map +0 -1
- package/dist/src/redteam/getCompetitorTests.js +0 -60
- package/dist/src/redteam/getCompetitorTests.js.map +0 -1
- package/dist/src/redteam/getHallucinationTests.d.ts +0 -3
- package/dist/src/redteam/getHallucinationTests.d.ts.map +0 -1
- package/dist/src/redteam/getHallucinationTests.js +0 -56
- package/dist/src/redteam/getHallucinationTests.js.map +0 -1
- package/dist/src/redteam/getHarmfulTests.d.ts.map +0 -1
- package/dist/src/redteam/getHarmfulTests.js.map +0 -1
- package/dist/src/redteam/getHijackingTests.d.ts +0 -3
- package/dist/src/redteam/getHijackingTests.d.ts.map +0 -1
- package/dist/src/redteam/getHijackingTests.js +0 -60
- package/dist/src/redteam/getHijackingTests.js.map +0 -1
- package/dist/src/redteam/getOverconfidenceTests.d.ts +0 -3
- package/dist/src/redteam/getOverconfidenceTests.d.ts.map +0 -1
- package/dist/src/redteam/getOverconfidenceTests.js +0 -55
- package/dist/src/redteam/getOverconfidenceTests.js.map +0 -1
- package/dist/src/redteam/getPiiTests.d.ts.map +0 -1
- package/dist/src/redteam/getPiiTests.js.map +0 -1
- package/dist/src/redteam/getPoliticalStatementsTests.d.ts +0 -3
- package/dist/src/redteam/getPoliticalStatementsTests.d.ts.map +0 -1
- package/dist/src/redteam/getPoliticalStatementsTests.js +0 -70
- package/dist/src/redteam/getPoliticalStatementsTests.js.map +0 -1
- package/dist/src/redteam/getUnderconfidenceTests.d.ts +0 -3
- package/dist/src/redteam/getUnderconfidenceTests.d.ts.map +0 -1
- package/dist/src/redteam/getUnderconfidenceTests.js +0 -55
- package/dist/src/redteam/getUnderconfidenceTests.js.map +0 -1
- package/dist/src/redteam/getUnintendedContractTests.d.ts +0 -3
- package/dist/src/redteam/getUnintendedContractTests.d.ts.map +0 -1
- package/dist/src/redteam/getUnintendedContractTests.js +0 -60
- package/dist/src/redteam/getUnintendedContractTests.js.map +0 -1
- package/dist/src/web/nextui/_next/static/chunks/954-c35d4864ecbacd62.js +0 -6
- package/dist/src/web/nextui/_next/static/chunks/app/datasets/page-4f93aacd25866d60.js +0 -1
- package/dist/src/web/nextui/_next/static/chunks/app/eval/[id]/not-found-ce320e6d1e6d1d23.js +0 -1
- package/dist/src/web/nextui/_next/static/chunks/app/eval/page-73e894c39cc191f1.js +0 -1
- package/dist/src/web/nextui/_next/static/chunks/app/progress/page-73442c531d579c51.js +0 -1
- package/dist/src/web/nextui/_next/static/css/106779eb64615639.css +0 -1
- /package/dist/src/web/nextui/_next/static/{1r10QuQFZj3AAU-Bx1DRP → 46JfY2NdEDFuAccLbcAJl}/_buildManifest.js +0 -0
- /package/dist/src/web/nextui/_next/static/{1r10QuQFZj3AAU-Bx1DRP → 46JfY2NdEDFuAccLbcAJl}/_ssgManifest.js +0 -0
- /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
|