Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
],
"disable_content_logging": false,
"drop_excess_requests": false,
"enable_litellm_fallbacks": false,
"enable_logging": true,
"enforce_auth_on_inference": true,
"initial_pool_size": 300,
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/scripts/run-migration-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,8 @@ VALUES ('migration-test-lock', 'holder-migration-test-001', $future, $now)
ON CONFLICT DO NOTHING;

-- config_client (global client configuration)
INSERT INTO config_client (id, drop_excess_requests, prometheus_labels_json, allowed_origins_json, allowed_headers_json, header_filter_config_json, initial_pool_size, enable_logging, disable_content_logging, disable_db_pings_in_health, log_retention_days, enforce_governance_header, allow_direct_keys, max_request_body_size_mb, mcp_agent_depth, mcp_tool_execution_timeout, mcp_code_mode_binding_level, mcp_tool_sync_interval, enable_litellm_fallbacks, config_hash, created_at, updated_at)
VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, true, 100, 10, 30, 'server', 10, false, 'client-config-hash-001', $now, $now)
INSERT INTO config_client (id, drop_excess_requests, prometheus_labels_json, allowed_origins_json, allowed_headers_json, header_filter_config_json, initial_pool_size, enable_logging, disable_content_logging, disable_db_pings_in_health, log_retention_days, enforce_governance_header, allow_direct_keys, max_request_body_size_mb, mcp_agent_depth, mcp_tool_execution_timeout, mcp_code_mode_binding_level, mcp_tool_sync_interval, compat_convert_text_to_chat, compat_convert_chat_to_responses, compat_should_drop_params, compat_should_convert_params, config_hash, created_at, updated_at)
VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, 100, 10, 30, 'server', 10, false, false, false, true, 'client-config-hash-001', $now, $now)
ON CONFLICT DO NOTHING;

-- governance_config (key-value config table)
Expand Down Expand Up @@ -3509,4 +3509,4 @@ main() {
exit $exit_code
}

main "$@"
main "$@"
3 changes: 1 addition & 2 deletions .github/workflows/scripts/test-docker-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ cat > "$CONFIG_FILE" << 'CONFIGEOF'
"enable_logging": true,
"enforce_governance_header": false,
"allow_direct_keys": false,
"max_request_body_size_mb": 100,
"enable_litellm_fallbacks": false
"max_request_body_size_mb": 100
},
"encryption_key": ""
}
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/scripts/validate-helm-config-fields.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ bifrost:
enforceGovernanceHeader: true
allowDirectKeys: true
maxRequestBodySizeMb: 50
enableLitellmFallbacks: true
compat:
convertTextToChat: true
convertChatToResponses: true
shouldDropParams: true
shouldConvertParams: true
Comment thread
coderabbitai[bot] marked this conversation as resolved.
prometheusLabels:
- "team"
- "env"
Expand Down Expand Up @@ -200,7 +204,10 @@ assert_field_value 'client.log_retention_days' '.client.log_retention_days' '30'
assert_field_value 'client.enforce_governance_header' '.client.enforce_governance_header' 'true'
assert_field_value 'client.allow_direct_keys' '.client.allow_direct_keys' 'true'
assert_field_value 'client.max_request_body_size_mb' '.client.max_request_body_size_mb' '50'
assert_field_value 'client.enable_litellm_fallbacks' '.client.enable_litellm_fallbacks' 'true'
assert_field_value 'client.compat.convert_text_to_chat' '.client.compat.convert_text_to_chat' 'true'
assert_field_value 'client.compat.convert_chat_to_responses' '.client.compat.convert_chat_to_responses' 'true'
assert_field_value 'client.compat.should_drop_params' '.client.compat.should_drop_params' 'true'
assert_field_value 'client.compat.should_convert_params' '.client.compat.should_convert_params' 'true'
assert_field 'client.prometheus_labels' '.client.prometheus_labels'
assert_field 'client.header_filter_config.allowlist' '.client.header_filter_config.allowlist'
assert_field 'client.header_filter_config.denylist' '.client.header_filter_config.denylist'
Expand Down Expand Up @@ -1194,4 +1201,4 @@ if [ "$TESTS_FAILED" -gt 0 ]; then
else
echo -e "${GREEN}✅ All config.json field validations passed!${NC}"
exit 0
fi
fi
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ bifrost/
│ ├── mocker/ # Mock responses for testing
│ ├── jsonparser/ # JSON extraction utilities
│ ├── maxim/ # Maxim observability
│ └── litellmcompat/ # LiteLLM SDK compatibility (HTTP transport)
│ └── compat/ # LiteLLM SDK compatibility (HTTP transport)
├── ui/ # Next.js web interface
│ ├── app/workspace/ # Feature pages (20+ workspace sections)
Expand Down Expand Up @@ -647,4 +647,4 @@ Systematically address unresolved PR review comments. Uses GraphQL to get unreso
- **Provider types**: Prefixed with provider name in PascalCase (`AnthropicChatRequest`, `GeminiEmbeddingResponse`).
- **Converter functions**: Pure — no side effects, no logging, no HTTP.
- **Pool names**: Descriptive string passed to `pool.New()` (e.g., `"channel-message"`, `"response-stream"`).
- **Context keys**: Use `BifrostContextKey` type. Custom plugins should define their own key types to avoid collisions.
- **Context keys**: Use `BifrostContextKey` type. Custom plugins should define their own key types to avoid collisions.
53 changes: 45 additions & 8 deletions core/bifrost.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ func (bifrost *Bifrost) TextCompletionRequest(ctx *schemas.BifrostContext, req *
if err != nil {
return nil, err
}
//TODO: Release the response
// TODO: Release the response
return response.TextCompletionResponse, nil
}

Expand Down Expand Up @@ -934,7 +934,7 @@ func (bifrost *Bifrost) EmbeddingRequest(ctx *schemas.BifrostContext, req *schem
if err != nil {
return nil, err
}
//TODO: Release the response
// TODO: Release the response
return response.EmbeddingResponse, nil
}

Expand Down Expand Up @@ -1042,7 +1042,7 @@ func (bifrost *Bifrost) SpeechRequest(ctx *schemas.BifrostContext, req *schemas.
if err != nil {
return nil, err
}
//TODO: Release the response
// TODO: Release the response
return response.SpeechResponse, nil
}

Expand Down Expand Up @@ -1117,7 +1117,7 @@ func (bifrost *Bifrost) TranscriptionRequest(ctx *schemas.BifrostContext, req *s
if err != nil {
return nil, err
}
//TODO: Release the response
// TODO: Release the response
return response.TranscriptionResponse, nil
}

Expand Down Expand Up @@ -1158,7 +1158,8 @@ func (bifrost *Bifrost) TranscriptionStreamRequest(ctx *schemas.BifrostContext,

// ImageGenerationRequest sends an image generation request to the specified provider.
func (bifrost *Bifrost) ImageGenerationRequest(ctx *schemas.BifrostContext,
req *schemas.BifrostImageGenerationRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) {
req *schemas.BifrostImageGenerationRequest,
) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) {
if req == nil {
return nil, &schemas.BifrostError{
IsBifrostError: false,
Expand Down Expand Up @@ -1213,7 +1214,8 @@ func (bifrost *Bifrost) ImageGenerationRequest(ctx *schemas.BifrostContext,

// ImageGenerationStreamRequest sends an image generation stream request to the specified provider.
func (bifrost *Bifrost) ImageGenerationStreamRequest(ctx *schemas.BifrostContext,
req *schemas.BifrostImageGenerationRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) {
req *schemas.BifrostImageGenerationRequest,
) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) {
if req == nil {
return nil, &schemas.BifrostError{
IsBifrostError: false,
Expand Down Expand Up @@ -1434,7 +1436,8 @@ func (bifrost *Bifrost) ImageVariationRequest(ctx *schemas.BifrostContext, req *

// VideoGenerationRequest sends a video generation request to the specified provider.
func (bifrost *Bifrost) VideoGenerationRequest(ctx *schemas.BifrostContext,
req *schemas.BifrostVideoGenerationRequest) (*schemas.BifrostVideoGenerationResponse, *schemas.BifrostError) {
req *schemas.BifrostVideoGenerationRequest,
) (*schemas.BifrostVideoGenerationResponse, *schemas.BifrostError) {
if req == nil {
return nil, &schemas.BifrostError{
IsBifrostError: false,
Expand Down Expand Up @@ -4692,7 +4695,7 @@ func (bifrost *Bifrost) tryStreamRequest(ctx *schemas.BifrostContext, req *schem
// Send the processed message to the output stream
outputStream <- streamResponse

//TODO: Release the processed response immediately after use
// TODO: Release the processed response immediately after use
}
}()

Expand Down Expand Up @@ -5264,12 +5267,34 @@ func (bifrost *Bifrost) handleProviderRequest(provider schemas.Provider, req *Ch
}
response.ListModelsResponse = listModelsResponse
case schemas.TextCompletionRequest:
if changeType, ok := req.Context.Value(schemas.BifrostContextKeyChangeRequestType).(schemas.RequestType); ok && changeType == schemas.ChatCompletionRequest {
chatRequest := req.BifrostRequest.TextCompletionRequest.ToBifrostChatRequest()
if chatRequest != nil {
chatCompletionResponse, bifrostError := provider.ChatCompletion(req.Context, key, chatRequest)
if bifrostError != nil {
return nil, bifrostError
}
response.TextCompletionResponse = chatCompletionResponse.ToBifrostTextCompletionResponse()
break
}
}
Comment thread
sammaji marked this conversation as resolved.
textCompletionResponse, bifrostError := provider.TextCompletion(req.Context, key, req.BifrostRequest.TextCompletionRequest)
if bifrostError != nil {
return nil, bifrostError
}
response.TextCompletionResponse = textCompletionResponse
case schemas.ChatCompletionRequest:
if changeType, ok := req.Context.Value(schemas.BifrostContextKeyChangeRequestType).(schemas.RequestType); ok && changeType == schemas.ResponsesRequest {
responsesRequest := req.BifrostRequest.ChatRequest.ToResponsesRequest()
if responsesRequest != nil {
responsesResponse, bifrostError := provider.Responses(req.Context, key, responsesRequest)
if bifrostError != nil {
return nil, bifrostError
}
response.ChatResponse = responsesResponse.ToBifrostChatResponse()
break
}
}
Comment thread
sammaji marked this conversation as resolved.
chatCompletionResponse, bifrostError := provider.ChatCompletion(req.Context, key, req.BifrostRequest.ChatRequest)
if bifrostError != nil {
return nil, bifrostError
Expand Down Expand Up @@ -5519,8 +5544,20 @@ func (bifrost *Bifrost) handleProviderRequest(provider schemas.Provider, req *Ch
func (bifrost *Bifrost) handleProviderStreamRequest(provider schemas.Provider, req *ChannelMessage, key schemas.Key, postHookRunner schemas.PostHookRunner) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) {
switch req.RequestType {
case schemas.TextCompletionStreamRequest:
if changeType, ok := req.Context.Value(schemas.BifrostContextKeyChangeRequestType).(schemas.RequestType); ok && changeType == schemas.ChatCompletionRequest {
chatRequest := req.BifrostRequest.TextCompletionRequest.ToBifrostChatRequest()
if chatRequest != nil {
return provider.ChatCompletionStream(req.Context, wrapConvertedStreamPostHookRunner(postHookRunner, schemas.ChatCompletionRequest), key, chatRequest)
}
}
return provider.TextCompletionStream(req.Context, postHookRunner, key, req.BifrostRequest.TextCompletionRequest)
case schemas.ChatCompletionStreamRequest:
if changeType, ok := req.Context.Value(schemas.BifrostContextKeyChangeRequestType).(schemas.RequestType); ok && changeType == schemas.ResponsesRequest {
responsesRequest := req.BifrostRequest.ChatRequest.ToResponsesRequest()
if responsesRequest != nil {
return provider.ResponsesStream(req.Context, wrapConvertedStreamPostHookRunner(postHookRunner, schemas.ResponsesRequest), key, responsesRequest)
}
}
return provider.ChatCompletionStream(req.Context, postHookRunner, key, req.BifrostRequest.ChatRequest)
case schemas.ResponsesStreamRequest:
return provider.ResponsesStream(req.Context, postHookRunner, key, req.BifrostRequest.ResponsesRequest)
Expand Down
2 changes: 1 addition & 1 deletion core/providers/anthropic/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1316,4 +1316,4 @@ func parseAnthropicFileTimestamp(timestamp string) int64 {
// AnthropicCountTokensResponse models the payload returned by Anthropic's count tokens endpoint.
type AnthropicCountTokensResponse struct {
InputTokens int `json:"input_tokens"`
}
}
1 change: 0 additions & 1 deletion core/providers/bedrock/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ func ToBedrockImageGenerationRequest(request *schemas.BifrostImageGenerationRequ
}

return bedrockReq, nil

}

// ToStabilityAIImageGenerationResponse converts a BifrostImageGenerationResponse back to
Expand Down
3 changes: 1 addition & 2 deletions core/providers/bedrock/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ type BedrockRerankResponseDocument struct {
TextDocument *BedrockRerankTextValue `json:"textDocument,omitempty"`
}


func (response *BedrockListModelsResponse) ToBifrostListModelsResponse(providerKey schemas.ModelProvider, allowedModels schemas.WhiteList, blacklistedModels schemas.BlackList, aliases map[string]string, unfiltered bool) *schemas.BifrostListModelsResponse {
if response == nil {
return nil
Expand Down Expand Up @@ -128,4 +127,4 @@ func (response *BedrockListModelsResponse) ToBifrostListModelsResponse(providerK
pipeline.BackfillModels(included)...)

return bifrostResponse
}
}
7 changes: 5 additions & 2 deletions core/providers/cohere/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (
"github.com/maximhq/bifrost/core/schemas"
)

const MinimumReasoningMaxTokens = 1
const DefaultCompletionMaxTokens = 4096 // Only used for relative reasoning max token calculation - not passed in body by default
const (
MinimumReasoningMaxTokens = 1
DefaultCompletionMaxTokens = 4096 // Only used for relative reasoning max token calculation - not passed in body by default
)

// Limits for tokenize input api call https://docs.cohere.com/reference/tokenize#request
const (
cohereTokenizeMinTextLength = 1
Expand Down
21 changes: 10 additions & 11 deletions core/providers/gemini/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import (
"github.com/maximhq/bifrost/core/schemas"
)

const MinReasoningMaxTokens = 1 // Minimum max tokens for reasoning - used for estimation of effort level
const DefaultCompletionMaxTokens = 8192 // Default max output tokens for Gemini - used for relative reasoning max token calculation
const DefaultReasoningMinBudget = 1024 // Default minimum reasoning budget for Gemini
const DynamicReasoningBudget = -1 // Special value for dynamic reasoning budget in Gemini
const skipThoughtSignatureValidator = "skip_thought_signature_validator"
const (
MinReasoningMaxTokens = 1 // Minimum max tokens for reasoning - used for estimation of effort level
DefaultCompletionMaxTokens = 8192 // Default max output tokens for Gemini - used for relative reasoning max token calculation
DefaultReasoningMinBudget = 1024 // Default minimum reasoning budget for Gemini
DynamicReasoningBudget = -1 // Special value for dynamic reasoning budget in Gemini
skipThoughtSignatureValidator = "skip_thought_signature_validator"
)

type thinkingBudgetRange struct {
Min int
Expand Down Expand Up @@ -509,8 +511,7 @@ type GoogleMaps struct {
}

// URLContext is a tool to support URL context retrieval.
type URLContext struct {
}
type URLContext struct{}

// ToolComputerUse is a tool to support computer use.
type ToolComputerUse struct {
Expand Down Expand Up @@ -555,8 +556,7 @@ type ExternalAPIElasticSearchParams struct {
}

// ExternalAPISimpleSearchParams represents the search parameters to use for SIMPLE_SEARCH spec.
type ExternalAPISimpleSearchParams struct {
}
type ExternalAPISimpleSearchParams struct{}

// ExternalAPI retrieves from data source powered by external API for grounding. The external API
// is not owned by Google, but needs to follow the pre-defined API spec.
Expand Down Expand Up @@ -714,8 +714,7 @@ type Retrieval struct {
// ToolCodeExecution is a tool that executes code generated by the model, and automatically returns the result
// to the model. See also [ExecutableCode]and [CodeExecutionResult] which are input
// and output to this tool.
type ToolCodeExecution struct {
}
type ToolCodeExecution struct{}

// Tool details of a tool that the model may use to generate a response.
type Tool struct {
Expand Down
4 changes: 2 additions & 2 deletions core/providers/openai/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"fmt"

"github.com/bytedance/sonic"
"github.com/maximhq/bifrost/core/schemas"
providerUtils "github.com/maximhq/bifrost/core/providers/utils"
"github.com/maximhq/bifrost/core/schemas"
)

const MinMaxCompletionTokens = 16
Expand Down Expand Up @@ -82,7 +82,7 @@ type OpenAIChatRequest struct {
// PromptCacheIsolationKey is the Fireworks chat-completions field for cache isolation.
PromptCacheIsolationKey *string `json:"prompt_cache_isolation_key,omitempty"`

//NOTE: MaxCompletionTokens is a new replacement for max_tokens but some providers still use max_tokens.
// NOTE: MaxCompletionTokens is a new replacement for max_tokens but some providers still use max_tokens.
// This Field is populated only for such providers and is NOT to be used externally.
MaxTokens *int `json:"max_tokens,omitempty"`

Expand Down
Loading
Loading