Files
promptfoo--promptfoo/plugins/promptfoo/skills/promptfoo-provider-setup/references/provider-patterns.md
T
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

258 lines
8.5 KiB
Markdown

# Provider Setup Patterns
Use these as starting points; keep secrets in env vars.
## Live HTTP JSON endpoint
```yaml
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
description: HTTP endpoint smoke test
prompts:
- '{{message}}'
providers:
- id: https
label: live-chat-api
config:
url: '{{env.CHAT_API_URL}}'
method: POST
stateful: false
headers:
Content-Type: application/json
Authorization: 'Bearer {{env.CHAT_API_TOKEN}}'
body:
message: '{{prompt}}'
transformResponse: json.output
tests:
- description: endpoint returns text
vars:
message: Say exactly PONG.
assert:
- type: contains
value: PONG
```
Smoke with `promptfoo eval -c promptfooconfig.yaml -o output.json --no-cache
--no-share`. Use `stateful: false` for stateless targets. If the app maintains
conversation state, omit it and map `{{sessionId}}` into the request or configure
`sessionParser`.
## Live HTTP GET endpoint
Use `queryParams` instead of hand-building query strings when the target accepts GET parameters.
```yaml
providers:
- id: https
label: search-api
config:
url: '{{env.SEARCH_API_URL}}'
method: GET
stateful: false
headers:
Authorization: 'Bearer {{env.SEARCH_API_TOKEN}}'
queryParams:
q: '{{prompt}}'
user_id: '{{user_id}}'
transformResponse: json.answer
```
## OpenAI-compatible chat endpoint
Use an HTTP provider when the endpoint is OpenAI-shaped but not one of Promptfoo's native providers.
```yaml
providers:
- id: https
label: openai-compatible-chat
config:
url: '{{env.CHAT_COMPLETIONS_URL}}'
method: POST
stateful: false
headers:
Content-Type: application/json
Authorization: 'Bearer {{env.CHAT_COMPLETIONS_TOKEN}}'
body:
model: '{{env.CHAT_COMPLETIONS_MODEL}}'
messages:
- role: system
content: Return concise answers.
- role: user
content: '{{prompt}}'
transformResponse: json.choices[0].message.content
```
## Text response endpoint
Use `text` in `transformResponse` when the target returns plain text.
```yaml
providers:
- id: https
label: text-chat-api
config:
url: '{{env.TEXT_CHAT_API_URL}}'
method: POST
stateful: false
headers:
Content-Type: text/plain
body: '{{prompt}}'
transformResponse: text.replace(/^Assistant:\s*/, '')
```
## OpenAPI operation to HTTP provider
Map one operation at a time: base URL to an env var, path parameters into the URL with `urlencode`, request/header/query fields into `body`/`headers`/`queryParams`, and the first successful response schema into `transformResponse` (prefer `200`, otherwise the lowest explicit `2xx` status).
The bundled `scripts/openapi-operation-to-config.mjs` helper supports local OpenAPI `$ref`s plus `allOf` and first-variant `oneOf`/`anyOf` schemas. It lets operation parameters override path parameters, URL-encodes path/form values, skips readOnly request and writeOnly response fields even through `$ref`/composed schemas, keeps wire names intact, creates safe vars, preserves headers, and maps prompt fields (`message`, `question`, `input`, `text`, `q`, `query`) to `{{prompt}}`. With `--token-env`, it infers Bearer/OAuth2/OpenID/header/query/cookie API-key auth, uses parameter/media examples (including example-only bodies), +json media, text request bodies, form-url-encoded request bodies, structured multipart request bodies with generated file parts, typed/format schema samples from const/defaults/enums, root JSON array request bodies, schema/example-derived response transforms, health/status `message` vars, and `--auth-header X-API-Key --auth-prefix none`.
```yaml
providers:
- id: https
config:
url: '{{env.INVOICE_API_BASE_URL}}/v1/invoices/{{invoice_id}}/chat'
method: POST
headers:
Authorization: 'Bearer {{env.INVOICE_API_TOKEN}}'
body: { user_id: '{{user_id}}', message: '{{prompt}}' }
transformResponse: json.output
```
## Static-code-derived local wrappers
Use this for direct local code or custom setup. Pick JavaScript for Node apps and Python for Python app modules.
```yaml
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
description: Local agent provider smoke test
prompts:
- '{{message}}'
providers:
- id: file://provider.py:call_api # use file://provider.js for Node wrappers
config:
workers: 1
timeout: 30000
tests:
- description: local provider returns text
vars:
message: Say exactly PONG.
assert:
- type: contains
value: PONG
```
```javascript
export default class LocalAgentProvider {
constructor(options = {}) {
this.config = options.config || {};
}
id() {
return 'local-agent';
}
async callApi(prompt, context = {}) {
const vars = context.vars || {};
const result = await callAgent({
message: prompt,
userId: vars.user_id || this.config.defaultUserId || 'validate-user',
});
return typeof result?.output === 'string'
? { output: result.output }
: { error: 'Agent returned no string output' };
}
}
```
```python
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from app.invoice_agent import call_agent # noqa: E402
def call_api(prompt: str, options: dict, context: dict) -> dict:
config = options.get("config", {}) if isinstance(options, dict) else {}
vars = context.get("vars", {}) if isinstance(context, dict) else {}
user_id = vars.get("user_id") or config.get("defaultUserId") or "validate-user"
result = call_agent(message=prompt, user_id=user_id)
if not isinstance(result.get("output"), str):
return {"error": "Agent returned no string output"}
return {"output": result["output"]}
```
Python providers implement `call_api(prompt, options, context)` unless the id
uses a custom `file://provider.py:function_name` suffix. Anchor `sys.path` to
the provider directory before nearby app imports. Use `PROMPTFOO_PYTHON` or
`config.pythonExecutable` for a venv, `PROMPTFOO_PYTHON_WORKERS` or
`config.workers` for concurrency, and `config.timeout` for slow SDK calls.
`validate target` may call providers without vars, so wrappers need harmless defaults.
## Redteam target with named inputs
Use `targets` and preserve the app's real input fields. This gives redteam
plugins access to the actual authorization and injection surface.
```yaml
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
description: Multi-input redteam target
targets:
- id: https
label: invoice-agent
config:
url: '{{env.INVOICE_AGENT_URL}}'
method: POST
stateful: false
headers:
Content-Type: application/json
Authorization: 'Bearer {{env.INVOICE_AGENT_TOKEN}}'
body:
vendor_id: '{{vendor_id}}'
invoice_id: '{{invoice_id}}'
message: '{{message}}'
transformResponse: json.output
inputs:
vendor_id: Vendor identifier for the signed-in user.
invoice_id: Invoice identifier being discussed.
message: User message to the assistant.
redteam:
purpose: >-
Invoice support assistant that answers invoice questions only for the
authenticated vendor and must not reveal or modify other vendors' invoices.
numTests: 3
plugins:
- bola
- rbac
- indirect-prompt-injection
strategies:
- basic
```
Do not set `redteam.injectVar` for multi-input mode. Define `inputs` on the
target; Promptfoo automatically creates the internal combined `__prompt` value
for generation and grading.
## Hybrid discovery notes
Use this when static code and a live endpoint are both available. Record the contract before writing YAML:
- Static source: route/handler/client file and line range.
- Expected request: method, path, headers, body/query fields, and auth env var.
- Safe live probe: exact non-mutating payload and observed response field.
- Promptfoo mapping: vars to request fields and `transformResponse`.
- Open questions: mutations, session behavior, rate limits, or missing auth.
Prefer a local wrapper when the static path exposes app logic directly; prefer
`id: https` when the live endpoint contract is simple and safely probeable.
## Static discovery checklist
```bash
rg -n "app\\.(get|post|put|patch)|router\\.(get|post|put|patch)|fetch\\(|axios\\." .
rg -n "openapi|swagger|routes|controller|handler|chat|completion|agent" .
rg -n "Authorization|Bearer|apiKey|x-api-key|transformResponse|callApi" .
```