chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# config-ts (TypeScript Configuration Example)
|
||||
|
||||
You can run this example with:
|
||||
|
||||
```bash
|
||||
npx promptfoo@latest init --example config-ts
|
||||
cd config-ts
|
||||
```
|
||||
|
||||
This example demonstrates TypeScript configuration for promptfoo, including:
|
||||
|
||||
- Type-safe configuration with IDE autocompletion
|
||||
- Dynamic schema generation using Zod
|
||||
- Fun translation examples with creative language styles
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js ^20.20.0 or >=22.22.0 (Node.js 20 support ends July 30, 2026; Node.js 24 LTS recommended)
|
||||
- TypeScript loader (`tsx` recommended)
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Running Examples
|
||||
|
||||
### Basic TypeScript Configuration
|
||||
|
||||
```bash
|
||||
NODE_OPTIONS="--import tsx" promptfoo eval -c promptfooconfig.ts
|
||||
```
|
||||
|
||||
This example translates text into French and Pirate speak.
|
||||
|
||||
### Dynamic Schema Generation
|
||||
|
||||
```bash
|
||||
NODE_OPTIONS="--import tsx" promptfoo eval -c promptfooconfig-with-schema.ts
|
||||
```
|
||||
|
||||
This example shows structured JSON outputs with fun translations into Pirate speak, Shakespeare English, and Gen Z slang.
|
||||
|
||||
View results:
|
||||
|
||||
```bash
|
||||
promptfoo view
|
||||
```
|
||||
|
||||
## Examples Overview
|
||||
|
||||
### 1. Basic Configuration (`promptfooconfig.ts`)
|
||||
|
||||
Demonstrates:
|
||||
|
||||
- Type-safe configuration using the `UnifiedConfig` type
|
||||
- Simple provider configuration with GPT-5 Mini
|
||||
- Basic translation examples
|
||||
|
||||
### 2. Dynamic Schema Generation (`promptfooconfig-with-schema.ts`)
|
||||
|
||||
Shows advanced features:
|
||||
|
||||
- Zod schema for structured translation responses
|
||||
- Automatic schema adaptation for different providers (OpenAI and Gemini)
|
||||
- Structured JSON outputs with multiple fields (translation, language, confidence, funFactor, culturalNotes)
|
||||
- JavaScript assertions for validating structured outputs
|
||||
|
||||
Both OpenAI and Gemini support strict schema enforcement to ensure outputs match your Zod schema exactly.
|
||||
|
||||
## TypeScript Support
|
||||
|
||||
Node.js currently requires external loaders to run TypeScript files directly:
|
||||
|
||||
- Supported Node.js versions support ES modules with the `--import` flag
|
||||
- The `tsx` loader provides the best developer experience
|
||||
- Future versions may include native TypeScript support
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ts-config-example",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"description": "TypeScript configuration example for promptfoo with dynamic schema generation",
|
||||
"scripts": {
|
||||
"eval": "NODE_OPTIONS=\"--import tsx\" promptfoo eval -c promptfooconfig.ts",
|
||||
"eval-schema": "NODE_OPTIONS=\"--import tsx\" promptfoo eval -c promptfooconfig-with-schema.ts",
|
||||
"view": "promptfoo view"
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^6.37.0",
|
||||
"tsx": "^4.21.0",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.1.0",
|
||||
"promptfoo": "latest"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import { zodResponseFormat } from 'openai/helpers/zod.mjs';
|
||||
import { TranslationResponseSchema } from './src/schemas/translation-response';
|
||||
import type { UnifiedConfig } from 'promptfoo';
|
||||
|
||||
// Generate the response format for OpenAI
|
||||
const responseFormat = zodResponseFormat(TranslationResponseSchema, 'translation_response');
|
||||
|
||||
// Helper to adapt schema for Gemini (removes OpenAI-specific fields)
|
||||
function cleanSchemaForGemini(schema: any): any {
|
||||
if (typeof schema !== 'object' || schema === null) {
|
||||
return schema;
|
||||
}
|
||||
|
||||
const cleaned = { ...schema };
|
||||
|
||||
// Remove properties that Gemini doesn't support
|
||||
delete cleaned.additionalProperties;
|
||||
delete cleaned.$schema;
|
||||
|
||||
// Recursively clean nested objects
|
||||
if (cleaned.properties) {
|
||||
cleaned.properties = Object.fromEntries(
|
||||
Object.entries(cleaned.properties).map(([key, value]) => [key, cleanSchemaForGemini(value)]),
|
||||
);
|
||||
}
|
||||
|
||||
if (cleaned.items) {
|
||||
cleaned.items = cleanSchemaForGemini(cleaned.items);
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
const config: UnifiedConfig = {
|
||||
description: 'Fun translation tests with structured outputs',
|
||||
|
||||
prompts: [
|
||||
`You are a creative translator who adds personality to translations.
|
||||
|
||||
Translate this to {{language}}: "{{text}}"
|
||||
|
||||
Return a JSON response with your translation, confidence level, and any fun cultural notes.`,
|
||||
],
|
||||
|
||||
providers: [
|
||||
{
|
||||
id: 'openai:chat:gpt-5.5',
|
||||
label: 'GPT-5.5 (structured)',
|
||||
config: {
|
||||
response_format: responseFormat,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'google:gemini-2.5-flash',
|
||||
label: 'Gemini 2.5 Flash (structured)',
|
||||
config: {
|
||||
generationConfig: {
|
||||
response_mime_type: 'application/json',
|
||||
response_schema: cleanSchemaForGemini(responseFormat.json_schema.schema),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
tests: [
|
||||
{
|
||||
vars: {
|
||||
language: 'Pirate speak',
|
||||
text: "I can't find my coffee",
|
||||
},
|
||||
assert: [
|
||||
{
|
||||
type: 'javascript',
|
||||
value: `
|
||||
// Handle both object and string outputs
|
||||
const parsed = typeof output === 'object' ? output :
|
||||
JSON.parse(output.replace(/^\`\`\`json\\s*|\\s*\`\`\`$/g, ''));
|
||||
// Check for valid pirate speak patterns
|
||||
const text = parsed.translation.toLowerCase();
|
||||
const hasPirateSpeak = text.includes('arr') || text.includes('matey') ||
|
||||
text.includes('ye') || text.includes("me ") ||
|
||||
text.includes("'t ") || text.match(/\bt'\b/) ||
|
||||
text.includes('brew');
|
||||
return parsed.translation &&
|
||||
parsed.language.toLowerCase().includes('pirate') &&
|
||||
hasPirateSpeak;
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
vars: {
|
||||
language: 'Shakespeare English',
|
||||
text: 'This app is broken',
|
||||
},
|
||||
assert: [
|
||||
{
|
||||
type: 'javascript',
|
||||
value: `
|
||||
const parsed = typeof output === 'object' ? output :
|
||||
JSON.parse(output.replace(/^\`\`\`json\\s*|\\s*\`\`\`$/g, ''));
|
||||
const text = parsed.translation.toLowerCase();
|
||||
return parsed.translation &&
|
||||
(text.includes('thou') || text.includes('thee') ||
|
||||
text.includes('doth') || text.includes('hath') ||
|
||||
text.includes('alas') || text.includes('lieth') ||
|
||||
text.includes('woeful') || text.includes('undone') ||
|
||||
text.includes('forsooth') || text.includes('prithee') ||
|
||||
text.includes('verily') || text.match(/eth\\b/));
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
vars: {
|
||||
language: 'Gen Z slang',
|
||||
text: "That's really impressive",
|
||||
},
|
||||
assert: [
|
||||
{
|
||||
type: 'javascript',
|
||||
value: `
|
||||
const parsed = typeof output === 'object' ? output :
|
||||
JSON.parse(output.replace(/^\`\`\`json\\s*|\\s*\`\`\`$/g, ''));
|
||||
const translation = parsed.translation.toLowerCase();
|
||||
return parsed.translation &&
|
||||
parsed.confidence > 0 &&
|
||||
(translation.includes('slay') ||
|
||||
translation.includes('fire') ||
|
||||
translation.includes('bussin') ||
|
||||
translation.includes('lit') ||
|
||||
translation.includes('goat') ||
|
||||
translation.includes('lowkey') ||
|
||||
translation.includes('low-key') ||
|
||||
translation.includes('no cap') ||
|
||||
translation.includes(' fr') ||
|
||||
translation.includes('insane'));
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { UnifiedConfig } from 'promptfoo';
|
||||
|
||||
const config: UnifiedConfig = {
|
||||
description: 'A translator built with LLM',
|
||||
prompts: [
|
||||
'Rephrase this in {{language}}: {{body}}',
|
||||
'Translate this to conversational {{language}}: {{body}}',
|
||||
],
|
||||
providers: ['openai:chat:gpt-5.5'],
|
||||
tests: [
|
||||
{
|
||||
vars: {
|
||||
language: 'French',
|
||||
body: 'Hello world',
|
||||
},
|
||||
},
|
||||
{
|
||||
vars: {
|
||||
language: 'French',
|
||||
body: "I'm hungry",
|
||||
},
|
||||
},
|
||||
{
|
||||
vars: {
|
||||
language: 'Pirate',
|
||||
body: 'Hello world',
|
||||
},
|
||||
},
|
||||
{
|
||||
vars: {
|
||||
language: 'Pirate',
|
||||
body: "I'm hungry",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
// Fun schema for creative translation responses
|
||||
export const TranslationResponseSchema = z.object({
|
||||
translation: z.string().describe('The translated text'),
|
||||
language: z.string().describe('The target language or style'),
|
||||
confidence: z.number().min(0).max(1).describe('How confident the AI is (0-1)'),
|
||||
funFactor: z.number().min(0).max(10).nullable().describe('Fun rating from 0-10'),
|
||||
culturalNotes: z.string().nullable().describe('Any amusing cultural observations'),
|
||||
});
|
||||
|
||||
export type TranslationResponse = z.infer<typeof TranslationResponseSchema>;
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user