Quick Start

Minimal Configuration

The simplest way to use the Mocker plugin is with no configuration - it will create a default catch-all rule:
package main

import (
    "context"
    bifrost "github.com/maximhq/bifrost/core"
    "github.com/maximhq/bifrost/core/schemas"
    mocker "github.com/maximhq/bifrost/plugins/mocker"
)

func main() {
    // Create plugin with minimal config
    plugin, err := mocker.NewMockerPlugin(mocker.MockerConfig{
        Enabled: true, // Default rule will be created automatically
    })
    if err != nil {
        panic(err)
    }

    // Initialize Bifrost with the plugin
    client, initErr := bifrost.Init(schemas.BifrostConfig{
        Account: &yourAccount,
        Plugins: []schemas.Plugin{plugin},
    })
    if err != nil {
        panic(err)
    }
    defer client.Cleanup()

    // All requests will now return: "This is a mock response from the Mocker plugin"
    response, _ := client.ChatCompletionRequest(context.Background(), &schemas.BifrostRequest{
        Provider: schemas.OpenAI,
        Model:    "gpt-4",
        Input: schemas.RequestInput{
            ChatCompletionInput: &[]schemas.BifrostMessage{
                {
                    Role: schemas.ModelChatMessageRoleUser,
                    Content: schemas.MessageContent{
                        ContentStr: bifrost.Ptr("Hello!"),
                    },
                },
            },
        },
    })
}

Custom Response

plugin, err := mocker.NewMockerPlugin(mocker.MockerConfig{
    Enabled: true,
    Rules: []mocker.MockRule{
        {
            Name:        "openai-mock",
            Enabled:     true,
            Probability: 1.0, // Always trigger
            Conditions: mocker.Conditions{
                Providers: []string{"openai"},
            },
            Responses: []mocker.Response{
                {
                    Type: mocker.ResponseTypeSuccess,
                    Content: &mocker.SuccessResponse{
                        Message: "Hello! This is a custom mock response for OpenAI.",
                        Usage: &mocker.Usage{
                            PromptTokens:     15,
                            CompletionTokens: 25,
                            TotalTokens:      40,
                        },
                    },
                },
            },
        },
    },
})

Installation

Add the plugin to your project:
go get github.com/maximhq/bifrost/plugins/mocker
Import in your code:
import mocker "github.com/maximhq/bifrost/plugins/mocker"

Basic Usage

Creating the Plugin

config := mocker.MockerConfig{
    Enabled: true,
    DefaultBehavior: mocker.DefaultBehaviorPassthrough, // "passthrough", "success", "error"
    Rules: []mocker.MockRule{
        // Your rules here
    },
}

plugin, err := mocker.NewMockerPlugin(config)
if err != nil {
    log.Fatal(err)
}

Adding to Bifrost

client, initErr := bifrost.Init(schemas.BifrostConfig{
    Account: &yourAccount,
    Plugins: []schemas.Plugin{plugin},
    Logger: bifrost.NewDefaultLogger(schemas.LogLevelInfo),
})

Disabling the Plugin

config := mocker.MockerConfig{
    Enabled: false, // All requests pass through to real providers
}

Key Features

Template Variables

Create dynamic responses using templates:
Response{
    Type: mocker.ResponseTypeSuccess,
    Content: &mocker.SuccessResponse{
        MessageTemplate: stringPtr("Hello from {{provider}} using model {{model}}!"),
    },
}
Available Variables:
  • {{provider}} - Provider name (e.g., “openai”, “anthropic”)
  • {{model}} - Model name (e.g., “gpt-4”, “claude-3”)
  • {{faker.*}} - Fake data generation (see Configuration Reference)

Weighted Response Selection

Configure multiple responses with different probabilities:
Responses: []mocker.Response{
    {
        Type:   mocker.ResponseTypeSuccess,
        Weight: 0.8, // 80% chance
        Content: &mocker.SuccessResponse{
            Message: "Success response",
        },
    },
    {
        Type:   mocker.ResponseTypeError,
        Weight: 0.2, // 20% chance
        Error: &mocker.ErrorResponse{
            Message: "Rate limit exceeded",
            Type:    stringPtr("rate_limit"),
            Code:    stringPtr("429"),
        },
    },
}

Latency Simulation

Add realistic delays to responses:
// Fixed latency
Latency: &mocker.Latency{
    Type: mocker.LatencyTypeFixed,
    Min:  250 * time.Millisecond,
}

// Variable latency
Latency: &mocker.Latency{
    Type: mocker.LatencyTypeUniform,
    Min:  100 * time.Millisecond,
    Max:  500 * time.Millisecond,
}

Advanced Matching

Regex Message Matching

Conditions: mocker.Conditions{
    MessageRegex: stringPtr(`(?i).*support.*|.*help.*`),
}

Request Size Filtering

Conditions: mocker.Conditions{
    RequestSize: &mocker.SizeRange{
        Min: 100,  // bytes
        Max: 1000, // bytes
    },
}

Faker Data Generation

Create realistic test data using faker variables:
{
    Name: "user-profile-example",
    Responses: []mocker.Response{
        {
            Type: mocker.ResponseTypeSuccess,
            Content: &mocker.SuccessResponse{
                MessageTemplate: stringPtr(`User Profile:
- Name: {{faker.name}}
- Email: {{faker.email}}
- Company: {{faker.company}}
- Address: {{faker.address}}, {{faker.city}}
- Phone: {{faker.phone}}
- User ID: {{faker.uuid}}
- Join Date: {{faker.date}}
- Premium Account: {{faker.boolean}}`),
            },
        },
    },
}

Statistics and Monitoring

Get runtime statistics for monitoring:
stats := plugin.GetStatistics()
fmt.Printf("Plugin enabled: %v\n", stats.Enabled)
fmt.Printf("Total requests: %d\n", stats.TotalRequests)
fmt.Printf("Mocked requests: %d\n", stats.MockedRequests)

// Rule-specific stats
for ruleName, ruleStats := range stats.Rules {
    fmt.Printf("Rule %s: %d triggers\n", ruleName, ruleStats.Triggers)
}

Configuration Reference

MockerConfig

FieldTypeDefaultDescription
EnabledboolfalseEnable/disable the entire plugin
DefaultBehaviorstring"passthrough"Action when no rules match: "passthrough", "success", "error"
GlobalLatency*LatencynilGlobal latency applied to all rules
Rules[]MockRule[]List of mock rules evaluated in priority order

MockRule

FieldTypeDefaultDescription
Namestring-Unique rule name for identification
EnabledbooltrueEnable/disable this specific rule
Priorityint0Higher numbers = higher priority
Probabilityfloat641.0Activation probability (0.0=never, 1.0=always)
ConditionsConditions{}Matching conditions (empty = match all)
Responses[]Response-Possible responses (weighted random selection)
Latency*LatencynilRule-specific latency override

Conditions

FieldTypeDescription
Providers[]stringMatch specific providers: ["openai", "anthropic"]
Models[]stringMatch specific models: ["gpt-4", "claude-3"]
MessageRegex*stringRegex pattern to match message content
RequestSize*SizeRangeRequest size constraints in bytes

Response

FieldTypeDescription
TypestringResponse type: "success" or "error"
Weightfloat64Weight for random selection (default: 1.0)
Content*SuccessResponseRequired if Type="success"
Error*ErrorResponseRequired if Type="error"
AllowFallbacks*boolControl fallback behavior (nil=allow, false=block)

SuccessResponse

FieldTypeDescription
MessagestringStatic response message
MessageTemplate*stringTemplate with variables: {{provider}}, {{model}}, {{faker.*}}
Model*stringOverride model name in response
Usage*UsageToken usage information
FinishReason*stringCompletion reason (default: "stop")
CustomFieldsmap[string]interface{}Additional metadata fields

ErrorResponse

FieldTypeDescription
MessagestringError message to return
Type*stringError type (e.g., "rate_limit", "auth_error")
Code*stringError code (e.g., "429", "401")
StatusCode*intHTTP status code

Latency

FieldTypeDescription
TypestringLatency type: "fixed" or "uniform"
Mintime.DurationMinimum/exact latency (use time.Millisecond)
Maxtime.DurationMaximum latency (required for "uniform")
Important: Use Go’s time.Duration constants:
  • ✅ Correct: 100 * time.Millisecond
  • ❌ Wrong: 100 (nanoseconds, barely noticeable)

Faker Variables

Personal Information

  • {{faker.name}} - Full name
  • {{faker.first_name}} - First name only
  • {{faker.last_name}} - Last name only
  • {{faker.email}} - Email address
  • {{faker.phone}} - Phone number

Location

  • {{faker.address}} - Street address
  • {{faker.city}} - City name
  • {{faker.state}} - State/province
  • {{faker.zip_code}} - Postal code

Business

  • {{faker.company}} - Company name
  • {{faker.job_title}} - Job title

Text and Data

  • {{faker.lorem_ipsum}} - Lorem ipsum text
  • {{faker.lorem_ipsum:10}} - Lorem ipsum with 10 words
  • {{faker.uuid}} - UUID v4
  • {{faker.hex_color}} - Hex color code

Numbers and Dates

  • {{faker.integer}} - Random integer (1-100)
  • {{faker.integer:10,50}} - Random integer between 10-50
  • {{faker.float}} - Random float (0-100, 2 decimals)
  • {{faker.float:1,10}} - Random float between 1-10
  • {{faker.boolean}} - Random boolean
  • {{faker.date}} - Date (YYYY-MM-DD format)
  • {{faker.datetime}} - Datetime (YYYY-MM-DD HH:MM:SS format)

Best Practices

Rule Organization

// Use priority to control rule evaluation order
rules := []mocker.MockRule{
    {Name: "specific-error", Priority: 100, Conditions: /* specific */},
    {Name: "general-success", Priority: 50, Conditions: /* general */},
    {Name: "catch-all", Priority: 0, Conditions: /* empty */},
}

Development vs Production

// Development: High mock rate
config := mocker.MockerConfig{
    Enabled: true,
    Rules: []mocker.MockRule{
        {Probability: 1.0}, // Always mock
    },
}

// Production: Occasional testing
config := mocker.MockerConfig{
    Enabled: true,
    Rules: []mocker.MockRule{
        {Probability: 0.1}, // 10% mock rate
    },
}

Performance Considerations

  • Place specific conditions before general ones (higher priority)
  • Use simple string matching over complex regex when possible
  • Keep response templates reasonably sized
  • Consider disabling debug logging in production

Testing Your Configuration

func validateMockerConfig(config mocker.MockerConfig) error {
    _, err := mocker.NewMockerPlugin(config)
    return err
}

// Test before deployment
if err := validateMockerConfig(yourConfig); err != nil {
    log.Fatalf("Invalid mocker configuration: %v", err)
}

Common Issues

Plugin Not Triggering

  1. Check if plugin is enabled: Enabled: true
  2. Verify rule is enabled: rule.Enabled: true
  3. Check probability: Probability: 1.0 for testing
  4. Verify conditions match your request

Latency Not Working

Use time.Duration constants, not raw integers:
// ❌ Wrong: 100 nanoseconds (barely noticeable)
Min: 100

// ✅ Correct: 100 milliseconds
Min: 100 * time.Millisecond

Regex Not Matching

Test your regex pattern and ensure proper escaping:
// Case-insensitive matching
MessageRegex: stringPtr(`(?i).*help.*`)

// Escape special characters
MessageRegex: stringPtr(`\$\d+\.\d+`) // Match $12.34

Controlling Fallbacks

Response{
    Type: mocker.ResponseTypeError,
    AllowFallbacks: boolPtr(false), // Block fallbacks
    Error: &mocker.ErrorResponse{
        Message: "Authentication failed",
    },
}

Debug Mode

Enable debug logging to troubleshoot:
client, initErr := bifrost.Init(schemas.BifrostConfig{
    Account: &account,
    Plugins: []schemas.Plugin{plugin},
    Logger:  bifrost.NewDefaultLogger(schemas.LogLevelDebug),
})