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,18 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
@@ -0,0 +1,93 @@
|
||||
# provider-golang (Golang Provider Example)
|
||||
|
||||
You can run this example with:
|
||||
|
||||
```bash
|
||||
npx promptfoo@latest init --example provider-golang
|
||||
cd provider-golang
|
||||
```
|
||||
|
||||
This example demonstrates how to structure a Go-based provider for promptfoo. For detailed documentation, see [Go Provider](https://www.promptfoo.dev/docs/providers/go/) documentation.
|
||||
|
||||
To get started with this example:
|
||||
|
||||
```sh
|
||||
promptfoo init --example provider-golang
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
This example shows two implementations of the same provider interface:
|
||||
|
||||
```text
|
||||
provider-golang/
|
||||
├── go.mod # Root module definition
|
||||
├── main.go # Root provider implementation
|
||||
├── core/ # Supporting code
|
||||
│ └── openai.go # OpenAI client wrapper
|
||||
├── pkg1/ # Shared utilities
|
||||
│ └── utils.go # Configuration
|
||||
├── evaluation/ # Alternative implementation
|
||||
│ └── main.go # Provider with same interface
|
||||
└── promptfooconfig.yml # Config comparing both implementations
|
||||
```
|
||||
|
||||
The structure demonstrates how to:
|
||||
|
||||
1. Keep shared Go code in a single module
|
||||
2. Implement the same provider interface in different ways
|
||||
3. Compare multiple implementations in one config
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Go installed (1.16 or later)
|
||||
2. OpenAI Go client library:
|
||||
|
||||
```sh
|
||||
go get github.com/sashabaranov/go-openai@v1.37.0
|
||||
```
|
||||
|
||||
3. Set your API key:
|
||||
|
||||
```sh
|
||||
export OPENAI_API_KEY=your_key_here
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Run the comparison:
|
||||
|
||||
```sh
|
||||
npx promptfoo eval
|
||||
```
|
||||
|
||||
Then view the results with:
|
||||
|
||||
```sh
|
||||
npx promptfoo view
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The config compares both implementations:
|
||||
|
||||
```yaml
|
||||
providers:
|
||||
- id: 'file://evaluation/main.go:CallApi'
|
||||
label: 'Provider in evaluation/'
|
||||
|
||||
- id: 'file://main.go:CallApi'
|
||||
label: 'Provider in root'
|
||||
config:
|
||||
reasoning_effort: 'high'
|
||||
```
|
||||
|
||||
## Provider Implementations
|
||||
|
||||
Both `main.go` and `evaluation/main.go` implement the same interface:
|
||||
|
||||
```go
|
||||
func CallApi(prompt string, options map[string]interface{}) (string, error)
|
||||
```
|
||||
|
||||
They share the same OpenAI client code but can be configured differently through the config file.
|
||||
@@ -0,0 +1,57 @@
|
||||
// Package core provides OpenAI API integration with support for reasoning effort control.
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/promptfoo/promptfoo/examples/golang-provider/pkg1"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
)
|
||||
|
||||
// Client wraps the OpenAI API client with custom functionality for reasoning control.
|
||||
// It provides a simplified interface for making chat completion requests with
|
||||
// configurable reasoning effort levels.
|
||||
type Client struct {
|
||||
api *openai.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new OpenAI client using the API key from OPENAI_API_KEY
|
||||
// environment variable. Returns a Client configured with default settings.
|
||||
func NewClient() *Client {
|
||||
return &Client{
|
||||
api: openai.NewClient(os.Getenv("OPENAI_API_KEY")),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateCompletion generates a chat completion with reasoning effort control.
|
||||
// It takes a prompt string and a reasoningEffort level ("low", "medium", "high")
|
||||
// and returns the model's response as a string.
|
||||
//
|
||||
// The reasoning effort parameter controls how much computation the model spends
|
||||
// on analyzing and solving the problem. Higher effort may result in more thorough
|
||||
// or accurate responses at the cost of increased latency.
|
||||
//
|
||||
// Returns an error if the API call fails or if the response is invalid.
|
||||
func (c *Client) CreateCompletion(prompt string, reasoningEffort string) (string, error) {
|
||||
resp, err := c.api.CreateChatCompletion(
|
||||
context.Background(),
|
||||
openai.ChatCompletionRequest{
|
||||
Model: pkg1.GetModel(),
|
||||
Messages: []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: openai.ChatMessageRoleUser,
|
||||
Content: prompt,
|
||||
},
|
||||
},
|
||||
ReasoningEffort: reasoningEffort,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("chat completion error: %v", err)
|
||||
}
|
||||
|
||||
return resp.Choices[0].Message.Content, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Package main implements a promptfoo provider that uses OpenAI's API with reasoning effort control.
|
||||
// It provides a CallApi function that can be used by promptfoo to generate responses
|
||||
// with configurable reasoning levels.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/promptfoo/promptfoo/examples/golang-provider/core"
|
||||
"github.com/promptfoo/promptfoo/examples/golang-provider/pkg1"
|
||||
)
|
||||
|
||||
// client is the OpenAI API client instance used for all requests
|
||||
var client = core.NewClient()
|
||||
|
||||
// handlePrompt processes a prompt with configurable reasoning effort.
|
||||
// It accepts:
|
||||
// - prompt: the input text to send to the model
|
||||
// - options: configuration map containing reasoning_effort setting
|
||||
// - ctx: additional context (currently unused)
|
||||
//
|
||||
// Returns a map containing the "output" key with the model's response,
|
||||
// or an error if the API call fails.
|
||||
func handlePrompt(prompt string, options map[string]interface{}, ctx map[string]interface{}) (map[string]interface{}, error) {
|
||||
// Get reasoning_effort from config, default to pkg1's default if not specified
|
||||
reasoningEffort := pkg1.GetDefaultReasoningEffort()
|
||||
if mode, ok := options["config"].(map[string]interface{})["reasoning_effort"].(string); ok {
|
||||
reasoningEffort = mode
|
||||
}
|
||||
|
||||
output, err := client.CreateCompletion(prompt, reasoningEffort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("completion error: %v", err)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"output": output,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var CallApi func(string, map[string]interface{}, map[string]interface{}) (map[string]interface{}, error)
|
||||
|
||||
func init() {
|
||||
// Assign our implementation to the wrapper's CallApi function.
|
||||
// This makes it available to promptfoo for evaluation.
|
||||
CallApi = handlePrompt
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module github.com/promptfoo/promptfoo/examples/golang-provider
|
||||
|
||||
go 1.23.6
|
||||
|
||||
require github.com/sashabaranov/go-openai v1.37.0
|
||||
@@ -0,0 +1,2 @@
|
||||
github.com/sashabaranov/go-openai v1.37.0 h1:hQQowgYm4OXJ1Z/wTrE+XZaO20BYsL0R3uRPSpfNZkY=
|
||||
github.com/sashabaranov/go-openai v1.37.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
@@ -0,0 +1,50 @@
|
||||
// Package main implements a promptfoo provider that uses OpenAI's API.
|
||||
// It demonstrates a simple implementation of the provider interface using
|
||||
// shared code from the core and pkg1 packages.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/promptfoo/promptfoo/examples/golang-provider/core"
|
||||
"github.com/promptfoo/promptfoo/examples/golang-provider/pkg1"
|
||||
)
|
||||
|
||||
// client is the shared OpenAI client instance used for all requests.
|
||||
var client = core.NewClient()
|
||||
|
||||
// CallApi is the provider's implementation of promptfoo's API interface.
|
||||
// It processes prompts with configurable reasoning effort and returns the model's response.
|
||||
//
|
||||
// The prompt parameter is the input text to send to the model.
|
||||
// The options parameter may contain a config map with a "reasoning_effort" key
|
||||
// that accepts "low", "medium", or "high" values.
|
||||
//
|
||||
// Returns a map containing the "output" key with the model's response,
|
||||
// or an error if the API call fails.
|
||||
var CallApi func(string, map[string]interface{}, map[string]interface{}) (map[string]interface{}, error)
|
||||
|
||||
// handlePrompt processes a prompt with configurable reasoning effort.
|
||||
// It extracts the reasoning_effort from options (defaulting to pkg1's default)
|
||||
// and calls the OpenAI API through the core client.
|
||||
func handlePrompt(prompt string, options map[string]interface{}, ctx map[string]interface{}) (map[string]interface{}, error) {
|
||||
reasoningEffort := pkg1.GetDefaultReasoningEffort()
|
||||
if val, ok := options["config"].(map[string]interface{})["reasoning_effort"].(string); ok {
|
||||
reasoningEffort = val
|
||||
}
|
||||
|
||||
output, err := client.CreateCompletion(prompt, reasoningEffort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("completion error: %v", err)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"output": output,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Assign our implementation to the wrapper's CallApi function.
|
||||
// This makes it available to promptfoo for evaluation.
|
||||
CallApi = handlePrompt
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Package pkg1 provides configuration and utility functions for the OpenAI API client.
|
||||
package pkg1
|
||||
|
||||
// GetDefaultReasoningEffort returns the default reasoning effort setting for the API.
|
||||
// Valid values are "low", "medium", or "high", controlling how much effort the model
|
||||
// spends on reasoning through the problem.
|
||||
func GetDefaultReasoningEffort() string {
|
||||
return "medium"
|
||||
}
|
||||
|
||||
// GetModel returns the model identifier to use for API calls.
|
||||
// Currently uses o3-mini, which is optimized for reasoning tasks.
|
||||
func GetModel() string {
|
||||
return "o3-mini"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
|
||||
description: 'Golang provider example'
|
||||
|
||||
prompts:
|
||||
- 'Given the sequence {{sequence}}, what are the next two numbers and explain your reasoning?'
|
||||
|
||||
providers:
|
||||
- id: 'file://evaluation/main.go:CallApi'
|
||||
label: 'Provider in evaluation/'
|
||||
|
||||
- id: 'file://main.go:CallApi'
|
||||
label: 'Provider in root'
|
||||
config:
|
||||
reasoning_effort: 'high'
|
||||
|
||||
tests:
|
||||
- vars:
|
||||
sequence: '2, 6, 12, 20, 30'
|
||||
assert:
|
||||
- type: contains
|
||||
value: '42' # Next number in sequence
|
||||
- type: contains
|
||||
value: '56' # Number after that
|
||||
|
||||
- vars:
|
||||
sequence: '3, 7, 13, 21, 31'
|
||||
assert:
|
||||
- type: contains
|
||||
value: '43' # Next number
|
||||
- type: contains
|
||||
value: '57' # Number after that
|
||||
Reference in New Issue
Block a user