6.1 KiB
Plan: promptfoo eval -c <uuid> Cloud Config Support
Context
Currently, promptfoo redteam run -c <uuid> supports loading configs from Promptfoo Cloud by UUID, but promptfoo eval -c only accepts local file paths. This feature extends the same cloud config loading pattern to the eval command, allowing users to run promptfoo eval -c <cloud-uuid> to fetch and execute a config stored in Promptfoo Cloud.
The ticket (ENG-1770) has two parts:
- Open Source (this PR): Make the CLI accept a cloud UUID for
eval -c - Cloud: Show the
promptfoo eval -c <uuid>command in the Cloud run modal (separate repo)
Changes
1. Add getEvalConfigFromCloud() to src/util/cloud.ts
Create a new function modeled after the existing getConfigFromCloud() (line 88-114) but hitting a different endpoint for eval configs:
export async function getEvalConfigFromCloud(id: string): Promise<UnifiedConfig> {
// Same pattern as getConfigFromCloud but using `configs/${id}` endpoint
}
- Endpoint:
GET /api/v1/configs/${id}(eval configs, not redteam-specific) - Reuse existing
makeRequest()helper (line 25) andcloudConfig.isEnabled()check pattern - Same error handling pattern as
getConfigFromCloud
2. Add UUID detection to src/commands/eval.ts
In doEval() (line 107), add UUID detection before the existing config path processing at line 142. This mirrors the pattern in src/redteam/commands/run.ts:62-79.
// Before the existing config path processing (line 142)
const UUID_REGEX = /^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$/;
if (cmdObj.config?.length === 1 && UUID_REGEX.test(cmdObj.config[0])) {
const cloudConfigObj = await getEvalConfigFromCloud(cmdObj.config[0]);
defaultConfig = cloudConfigObj;
cmdObj.config = undefined;
}
Key behaviors:
- Only trigger when exactly one config path is provided and it's a UUID
- Fetch the config from cloud and use it as
defaultConfig - Clear
cmdObj.configsoresolveConfigsusesdefaultConfiginstead of trying to read a file - Import
getEvalConfigFromCloudfrom../../util/cloud
3. Update eval command description
Update the -c option description at line 903-906 to mention cloud UUID support:
.option(
'-c, --config <paths...>',
'Path to configuration file or cloud config UUID. Automatically loads promptfooconfig.yaml',
)
4. Add tests
Create test cases in a new test file or add to existing eval command tests, following the pattern from test/redteam/commands/run.test.ts:
- Test UUID detection triggers cloud fetch
- Test local file paths bypass UUID detection
- Test error when cloud is not enabled
- Test multiple config paths with UUID (should not trigger UUID detection)
Files to Modify
| File | Change |
|---|---|
src/util/cloud.ts |
Add getEvalConfigFromCloud() function |
src/commands/eval.ts |
Add UUID detection + cloud fetch in doEval(), update -c description |
test/commands/eval.test.ts or new test file |
Add tests for UUID cloud config |
Existing Code to Reuse
makeRequest()fromsrc/util/cloud.ts:25- authenticated HTTP helpercloudConfig.isEnabled()fromsrc/globalConfig/cloud.ts- auth check- UUID regex pattern from
src/redteam/commands/run.ts:17 resolveConfigs()fromsrc/util/config/load.ts:481- existing config resolution (no changes needed)
Verification
- Build:
npm run buildshould succeed - Lint:
npm run l && npm run f - Unit tests: Run existing + new tests with
npx vitest src/commands/evalandnpx vitest src/util/cloud - Manual test (if cloud access available):
npm run local -- eval -c <valid-uuid> --env-file .envshould fetch config from cloudnpm run local -- eval -c path/to/config.yamlshould still work as beforenpm run local -- eval -c <invalid-uuid-format>should fall through to file resolution
Decisions (Reconciled)
- Use the OSS endpoint contract:
GET /api/v1/configs/:idreturning an envelope ({ config: ... }), not a raw payload. - Support persisted config shape with
providersandtests; loading must not require additional requests. - Provider references in the config should use
promptfoo://provider/<uuid>. - Prompts should be emitted as plain strings.
testsdefaults to[]when missing.descriptionfalls back toconfig.namewhen missing.--watchis not supported when-c <uuid>is used. CLI should fail fast with a clear error.- If
-c <value>matches UUID format but cloud fetch fails (404/auth disabled), hard-fail. - If multiple
-cvalues are supplied and any value is a UUID, fail with an explicit error stating only one-cvalue is allowed for cloud UUID mode. - Add tests in both places:
test/commands/eval.test.tsfor UUID detection/CLI behaviortest/util/cloud.test.tsforgetEvalConfigFromCloud()contract/error handling
- Scope is
evalonly (notredteam eval). - No temporary UI note or minimum-version gating is required.
- In UUID mode, clear/ignore
defaultConfigPathfor the run to prevent accidental local reload/fallback behavior. - Read-time schema normalization should normalize legacy fields (
providerIds/testCases) into canonical fields (providers/tests).
CLI Error Messages (exact draft text)
- Multiple
-cvalues with UUID mode:Cloud config UUID mode supports exactly one -c value. Use: promptfoo eval -c <cloud-config-uuid>
- UUID mode with
--watch:--watch is not supported when using a cloud config UUID with -c. Use a local config file path for watch mode.
- UUID-shaped value with failed cloud fetch:
Failed to load cloud eval config "<uuid>". <reason>. Cloud UUID inputs do not fall back to local file paths. Check authentication and that the UUID exists.
Remaining Follow-ups
None.