Skip to main content
Bifrost uses Go’s context.Context to pass configuration and metadata through the request lifecycle. Context keys allow you to customize request behavior, pass request-specific settings, and read metadata set by Bifrost.

Request Configuration Keys

These keys can be set before making a request to customize behavior.

Extra Headers

Pass custom headers with individual requests. Headers are automatically propagated to the provider.
ctx := context.Background()

extraHeaders := map[string][]string{
    "user-id":    {"user-123"},
    "session-id": {"session-abc"},
}
ctx = context.WithValue(ctx, schemas.BifrostContextKeyExtraHeaders, extraHeaders)

response, err := client.ChatCompletionRequest(ctx, &schemas.BifrostChatRequest{
    Provider: schemas.OpenAI,
    Model:    "gpt-4o-mini",
    Input:    messages,
})
See Custom Headers Per Request for detailed information on header handling and security restrictions.

API Key Name Selection

Explicitly select a named API key from your configured keys.
ctx := context.WithValue(ctx, schemas.BifrostContextKeyAPIKeyName, "premium-key")

Direct Key

Bypass key selection and provide credentials directly. Useful for dynamic key scenarios.
directKey := schemas.Key{
    Value:  "sk-direct-api-key",
    Models: []string{"gpt-4o"},
    Weight: 1.0,
}
ctx := context.WithValue(ctx, schemas.BifrostContextKeyDirectKey, directKey)

Skip Key Selection

Skip the key selection process entirely and pass an empty key to the provider. Useful for providers that don’t require authentication or when using ambient credentials.
ctx := context.WithValue(ctx, schemas.BifrostContextKeySkipKeySelection, true)

Request ID

Set a custom request ID for tracking and correlation.
ctx := context.WithValue(ctx, schemas.BifrostContextKeyRequestID, "req-12345-abc")

Custom URL Path

Append a custom path to the provider’s base URL. Useful for accessing provider-specific endpoints.
ctx := context.WithValue(ctx, schemas.BifrostContextKeyURLPath, "/custom/endpoint")

Raw Request Body

Send a raw request body instead of Bifrost’s standardized format. The provider receives your payload as-is. You must both enable the context key AND set the RawRequestBody field on your request.
// Prepare your raw JSON payload
rawPayload := []byte(`{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello!"}],
    "custom_field": "provider-specific-value"
}`)

// Enable raw request body mode
ctx := context.WithValue(ctx, schemas.BifrostContextKeyUseRawRequestBody, true)

// Set the raw body on the request
response, err := client.ChatCompletionRequest(ctx, &schemas.BifrostChatRequest{
    Provider:       schemas.OpenAI,
    Model:          "gpt-4o",
    RawRequestBody: rawPayload,  // This will be sent directly to the provider
})
When using raw request body, Bifrost bypasses its request conversion and sends your payload directly to the provider. You’re responsible for ensuring the payload matches the provider’s expected format.

Send Back Raw Request/Response

Include the original request or response in the ExtraFields for debugging.
// Include raw request in response
ctx := context.WithValue(ctx, schemas.BifrostContextKeySendBackRawRequest, true)

// Include raw provider response
ctx := context.WithValue(ctx, schemas.BifrostContextKeySendBackRawResponse, true)
Access in response:
response, _ := client.ChatCompletionRequest(ctx, request)
if response.ChatResponse != nil {
    rawReq := response.ChatResponse.ExtraFields.RawRequest
    rawResp := response.ChatResponse.ExtraFields.RawResponse
}

Response Metadata Keys

These keys are set by Bifrost and can be read from the context after a request completes. They’re particularly useful in plugins and hooks.

Selected Key Information

After Bifrost selects an API key, it stores the selection details in the context.
// Get the selected key's ID
keyID := ctx.Value(schemas.BifrostContextKeySelectedKeyID).(string)

// Get the selected key's name
keyName := ctx.Value(schemas.BifrostContextKeySelectedKeyName).(string)

Retry and Fallback Information

Track retry attempts and fallback progression.
// Number of retries attempted (0 = first attempt)
retries := ctx.Value(schemas.BifrostContextKeyNumberOfRetries).(int)

// Fallback index (0 = primary, 1 = first fallback, etc.)
fallbackIdx := ctx.Value(schemas.BifrostContextKeyFallbackIndex).(int)

// Fallback request ID (set when using a fallback provider)
fallbackReqID := ctx.Value(schemas.BifrostContextKeyFallbackRequestID).(string)

Stream End Indicator

For streaming responses, indicates when the stream has completed.
isStreamEnd := ctx.Value(schemas.BifrostContextKeyStreamEndIndicator).(bool)
Plugin developers: When implementing custom streaming in PreHook or PostHook, make sure to mark BifrostContextKeyStreamEndIndicator as true at the end of the stream for proper cleanup.

Integration Type

Identifies which integration format is being used (useful in gateway scenarios).
integrationType := ctx.Value(schemas.BifrostContextKeyIntegrationType).(string)
// e.g., "openai", "anthropic", "bedrock"

Complete Example

Here’s a comprehensive example showing multiple context keys in use:
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/maximhq/bifrost"
    "github.com/maximhq/bifrost/core/schemas"
)

func makeRequest(client *bifrost.Bifrost) {
    // Start with background context
    ctx := context.Background()

    // Add request tracking
    ctx = context.WithValue(ctx, schemas.BifrostContextKeyRequestID, "req-001")

    // Add custom headers for the provider
    extraHeaders := map[string][]string{
        "x-correlation-id": {"corr-12345"},
        "x-tenant-id":      {"tenant-abc"},
    }
    ctx = context.WithValue(ctx, schemas.BifrostContextKeyExtraHeaders, extraHeaders)

    // Request raw response for debugging
    ctx = context.WithValue(ctx, schemas.BifrostContextKeySendBackRawResponse, true)

    // Make the request
    messages := []schemas.BifrostMessage{
        {Role: "user", Content: &schemas.BifrostMessageContent{Text: bifrost.Ptr("Hello!")}},
    }

    response, err := client.ChatCompletionRequest(ctx, &schemas.BifrostChatRequest{
        Provider: schemas.OpenAI,
        Model:    "gpt-4o-mini",
        Input:    messages,
    })

    if err != nil {
        log.Printf("Request failed: %v", err)
        return
    }

    // Access response metadata
    if response.ChatResponse != nil {
        extra := response.ChatResponse.ExtraFields
        fmt.Printf("Provider: %s\n", extra.Provider)
        fmt.Printf("Latency: %dms\n", extra.Latency)

        if extra.RawResponse != nil {
            fmt.Printf("Raw response available for debugging\n")
        }
    }
}

Context Keys Reference

KeyTypeDirectionDescription
BifrostContextKeyVirtualKeystringSetVirtual key identifier
BifrostContextKeyAPIKeyNamestringSetExplicit API key name selection
BifrostContextKeyRequestIDstringSetCustom request ID for tracking
BifrostContextKeyFallbackRequestIDstringReadRequest ID when using fallback
BifrostContextKeyDirectKeyschemas.KeySetDirect key credentials
BifrostContextKeySelectedKeyIDstringReadSelected key’s ID
BifrostContextKeySelectedKeyNamestringReadSelected key’s name
BifrostContextKeyNumberOfRetriesintReadNumber of retry attempts
BifrostContextKeyFallbackIndexintReadCurrent fallback index
BifrostContextKeyStreamEndIndicatorboolReadStream completion flag
BifrostContextKeySkipKeySelectionboolSetSkip key selection
BifrostContextKeyExtraHeadersmap[string][]stringSetCustom request headers
BifrostContextKeyURLPathstringSetCustom URL path suffix
BifrostContextKeyUseRawRequestBodyboolSetUse raw request body
BifrostContextKeySendBackRawRequestboolSetInclude raw request in response
BifrostContextKeySendBackRawResponseboolSetInclude raw response
BifrostContextKeyIntegrationTypestringReadIntegration format type
BifrostContextKeyUserAgentstringReadRequest user agent

Next Steps