Files
bifrost/core/schemas/account.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

295 lines
13 KiB
Go

// Package schemas defines the core schemas and types used by the Bifrost system.
package schemas
import (
"context"
"fmt"
"slices"
"strings"
)
type KeyStatusType string
const (
KeyStatusSuccess KeyStatusType = "success"
KeyStatusListModelsFailed KeyStatusType = "list_models_failed"
)
// WhiteList is a list of values that are allowed to be used.
// Semantics:
// - "*" (alone) means all values are allowed.
// - Empty list means nothing is allowed.
// - Non-empty list (without "*") means only the listed values are allowed.
//
// This type is used generically for any field that needs whitelist behavior
// (e.g., allowed models, allowed tools).
type WhiteList []string
// Contains reports whether value is in the whitelist.
// Returns true if value is in the list.
func (wl WhiteList) Contains(value string) bool {
return slices.ContainsFunc(wl, func(s string) bool {
return strings.EqualFold(s, value)
})
}
// IsAllowed reports whether value is in the whitelist.
// Returns true if value is in the list.
func (wl WhiteList) IsAllowed(value string) bool {
return wl.IsUnrestricted() || wl.Contains(value)
}
// IsEmpty reports whether the whitelist has no entries.
func (wl WhiteList) IsEmpty() bool {
return len(wl) == 0
}
// IsUnrestricted reports whether the whitelist contains only "*",
// meaning all values are allowed.
func (wl WhiteList) IsUnrestricted() bool {
return len(wl) == 1 && wl[0] == "*"
}
// IsRestricted reports whether the whitelist contains entries other than "*",
// meaning only the listed values are allowed.
func (wl WhiteList) IsRestricted() bool {
return !wl.IsUnrestricted()
}
// Validate checks that the whitelist is well-formed.
// Returns an error if "*" is present alongside other values, or if there are duplicate entries.
func (wl WhiteList) Validate() error {
if wl.Contains("*") && len(wl) > 1 {
return fmt.Errorf("wildcard '*' cannot be used with other values in the whitelist")
}
seen := make(map[string]struct{}, len(wl))
for _, v := range wl {
normalized := strings.ToLower(v)
if _, ok := seen[normalized]; ok {
return fmt.Errorf("duplicate value '%s' in whitelist", v)
}
seen[normalized] = struct{}{}
}
return nil
}
// BlackList is a list of values that are denied.
// Semantics:
// - "*" (alone) means all values are blocked.
// - Empty list means nothing is blocked.
// - Non-empty list (without "*") means only the listed values are blocked.
type BlackList []string
func (bl BlackList) Contains(value string) bool {
return slices.ContainsFunc(bl, func(s string) bool {
return strings.EqualFold(s, value)
})
}
// IsBlocked reports whether value is blocked.
func (bl BlackList) IsBlocked(value string) bool {
return bl.IsBlockAll() || bl.Contains(value)
}
// IsEmpty reports whether the blacklist has no entries (nothing is blocked).
func (bl BlackList) IsEmpty() bool {
return len(bl) == 0
}
// IsBlockAll reports whether the blacklist contains "*", meaning all values are blocked.
func (bl BlackList) IsBlockAll() bool {
return len(bl) == 1 && bl[0] == "*"
}
// Validate checks that the blacklist is well-formed.
func (bl BlackList) Validate() error {
if bl.Contains("*") && len(bl) > 1 {
return fmt.Errorf("wildcard '*' cannot be used with other values in the blacklist")
}
seen := make(map[string]struct{}, len(bl))
for _, v := range bl {
normalized := strings.ToLower(v)
if _, ok := seen[normalized]; ok {
return fmt.Errorf("duplicate value '%s' in blacklist", v)
}
seen[normalized] = struct{}{}
}
return nil
}
// Key represents an API key and its associated configuration for a provider.
// It contains the key value, supported models, and a weight for load balancing.
type Key struct {
ID string `json:"id"` // The unique identifier for the key (used by bifrost to identify the key)
Name string `json:"name"` // The name of the key (used by users to identify the key, not used by bifrost)
Value EnvVar `json:"value"` // The actual API key value
Models WhiteList `json:"models"` // List of models this key can access
BlacklistedModels BlackList `json:"blacklisted_models"` // List of models this key cannot access
Weight float64 `json:"weight"` // Weight for load balancing between multiple keys
Aliases KeyAliases `json:"aliases,omitempty"` // Mapping of model identifiers to inference profiles
AzureKeyConfig *AzureKeyConfig `json:"azure_key_config,omitempty"` // Azure-specific key configuration
VertexKeyConfig *VertexKeyConfig `json:"vertex_key_config,omitempty"` // Vertex-specific key configuration
BedrockKeyConfig *BedrockKeyConfig `json:"bedrock_key_config,omitempty"` // AWS Bedrock-specific key configuration
VLLMKeyConfig *VLLMKeyConfig `json:"vllm_key_config,omitempty"` // vLLM-specific key configuration
ReplicateKeyConfig *ReplicateKeyConfig `json:"replicate_key_config,omitempty"` // Replicate-specific key configuration
OllamaKeyConfig *OllamaKeyConfig `json:"ollama_key_config,omitempty"` // Ollama-specific key configuration
SGLKeyConfig *SGLKeyConfig `json:"sgl_key_config,omitempty"` // SGLang-specific key configuration
Enabled *bool `json:"enabled,omitempty"` // Whether the key is active (default:true)
UseForBatchAPI *bool `json:"use_for_batch_api,omitempty"` // Whether this key can be used for batch API operations (default:false for new keys, migrated keys default to true)
ConfigHash string `json:"config_hash,omitempty"` // Hash of config.json version, used for change detection
Status KeyStatusType `json:"status,omitempty"` // Status of key
Description string `json:"description,omitempty"` // Description of key
}
type KeyAliases map[string]string
func (ka KeyAliases) Validate() error {
seen := make(map[string]struct{}, len(ka))
for from, to := range ka {
if strings.TrimSpace(from) == "" {
return fmt.Errorf("alias source cannot be empty")
}
if strings.TrimSpace(to) == "" {
return fmt.Errorf("alias target for %q cannot be empty", from)
}
if strings.TrimSpace(from) != from {
return fmt.Errorf("alias source %q cannot have leading or trailing whitespace", from)
}
if strings.TrimSpace(to) != to {
return fmt.Errorf("alias target for %q cannot have leading or trailing whitespace", from)
}
normalized := strings.ToLower(from)
if _, ok := seen[normalized]; ok {
return fmt.Errorf("duplicate alias source %q (case-insensitive)", from)
}
seen[normalized] = struct{}{}
}
return nil
}
func (ka KeyAliases) Resolve(model string) string {
if ka == nil {
return model
}
if alias, ok := ka[model]; ok {
return alias
}
// Fall back to case-insensitive lookup for consistency with WhiteList.Contains
for k, v := range ka {
if strings.EqualFold(k, model) {
return v
}
}
return model
}
type AzureAuthType string
const (
AzureAuthTypeClientSecret AzureAuthType = "client_secret"
AzureAuthTypeManagedIdentity AzureAuthType = "managed_identity"
)
// AzureKeyConfig represents the Azure-specific configuration.
// It contains Azure-specific settings required for service access and deployment management.
type AzureKeyConfig struct {
Endpoint EnvVar `json:"endpoint"` // Azure service endpoint URL
APIVersion *EnvVar `json:"api_version,omitempty"` // Azure API version to use; defaults to "2024-10-21"
ClientID *EnvVar `json:"client_id,omitempty"` // Azure client ID for authentication
ClientSecret *EnvVar `json:"client_secret,omitempty"` // Azure client secret for authentication
TenantID *EnvVar `json:"tenant_id,omitempty"` // Azure tenant ID for authentication
Scopes []string `json:"scopes,omitempty"`
}
// VertexKeyConfig represents the Vertex-specific configuration.
// It contains Vertex-specific settings required for authentication and service access.
type VertexKeyConfig struct {
ProjectID EnvVar `json:"project_id"`
ProjectNumber EnvVar `json:"project_number"`
Region EnvVar `json:"region"`
AuthCredentials EnvVar `json:"auth_credentials"`
}
// NOTE: To use Vertex IAM role authentication, set AuthCredentials to empty string.
// S3BucketConfig represents a single S3 bucket configuration for batch operations.
type S3BucketConfig struct {
BucketName string `json:"bucket_name"` // S3 bucket name
Prefix string `json:"prefix,omitempty"` // S3 key prefix for batch files
IsDefault bool `json:"is_default,omitempty"` // Whether this is the default bucket for batch operations
}
// BatchS3Config holds S3 bucket configurations for Bedrock batch operations.
// Supports multiple buckets to allow flexible batch job routing.
type BatchS3Config struct {
Buckets []S3BucketConfig `json:"buckets,omitempty"` // List of S3 bucket configurations
}
// BedrockKeyConfig represents the AWS Bedrock-specific configuration.
// It contains AWS-specific settings required for authentication and service access.
type BedrockKeyConfig struct {
AccessKey EnvVar `json:"access_key,omitempty"` // AWS access key for authentication
SecretKey EnvVar `json:"secret_key,omitempty"` // AWS secret access key for authentication
SessionToken *EnvVar `json:"session_token,omitempty"` // AWS session token for temporary credentials
Region *EnvVar `json:"region,omitempty"` // AWS region for service access
ARN *EnvVar `json:"arn,omitempty"` // Amazon Resource Name for resource identification
// IAM role for STS AssumeRole
RoleARN *EnvVar `json:"role_arn,omitempty"`
ExternalID *EnvVar `json:"external_id,omitempty"`
RoleSessionName *EnvVar `json:"session_name,omitempty"`
BatchS3Config *BatchS3Config `json:"batch_s3_config,omitempty"` // S3 bucket configuration for batch operations
}
// NOTE: To use Bedrock IAM role authentication, set both AccessKey and SecretKey to empty strings.
// To use Bedrock API Key authentication, set Value in Key struct instead.
// VLLMKeyConfig represents the vLLM-specific key configuration.
// It allows each key to target a different vLLM server URL and model name,
// enabling per-key routing and round-robin load balancing across multiple vLLM instances.
type VLLMKeyConfig struct {
URL EnvVar `json:"url"` // VLLM server base URL (required, supports env. prefix)
ModelName string `json:"model_name"` // Exact model name served on this VLLM instance (used for key selection)
}
// ReplicateKeyConfig represents the Replicate-specific key configuration.
// It contains Replicate-specific settings required for authentication and service access.
type ReplicateKeyConfig struct {
UseDeploymentsEndpoint bool `json:"use_deployments_endpoint"` // Whether to use the deployments endpoint instead of the models endpoint
}
// OllamaKeyConfig represents the Ollama-specific key configuration.
// It allows each key to target a different Ollama server URL,
// enabling per-key routing and round-robin load balancing across multiple Ollama instances.
type OllamaKeyConfig struct {
URL EnvVar `json:"url"` // Ollama server base URL (required, supports env. prefix)
}
// SGLKeyConfig represents the SGLang-specific key configuration.
// It allows each key to target a different SGLang server URL,
// enabling per-key routing and round-robin load balancing across multiple SGLang instances.
type SGLKeyConfig struct {
URL EnvVar `json:"url"` // SGLang server base URL (required, supports env. prefix)
}
// Account defines the interface for managing provider accounts and their configurations.
// It provides methods to access provider-specific settings, API keys, and configurations.
type Account interface {
// GetConfiguredProviders returns a list of providers that are configured
// in the account. This is used to determine which providers are available for use.
GetConfiguredProviders() ([]ModelProvider, error)
// GetKeysForProvider returns the API keys configured for a specific provider.
// The keys include their values, supported models, and weights for load balancing.
// The context can carry data from any source that sets values before the Bifrost request,
// including but not limited to plugin pre-hooks, application logic, or any in app middleware sharing the context.
// This enables dynamic key selection based on any context values present during the request.
GetKeysForProvider(ctx context.Context, providerKey ModelProvider) ([]Key, error)
// GetConfigForProvider returns the configuration for a specific provider.
// This includes network settings, authentication details, and other provider-specific
// configurations.
GetConfigForProvider(providerKey ModelProvider) (*ProviderConfig, error)
}