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
1 change: 1 addition & 0 deletions core/changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- fix: allow setting authorization header through extra headers and in allow list and deny list
- feat: added image generation support for bedrock
- feat: added support for gemini google search tool
- fix: function response part handling in gemini
- fix: call enrich error in vertex to return raw request and response in bifrost errors
77 changes: 75 additions & 2 deletions core/providers/bedrock/bedrock.go
Original file line number Diff line number Diff line change
Expand Up @@ -1536,9 +1536,82 @@ func (provider *BedrockProvider) TranscriptionStream(ctx *schemas.BifrostContext
return nil, providerUtils.NewUnsupportedOperationError(schemas.TranscriptionStreamRequest, schemas.Bedrock)
}

// ImageGeneration is not supported by the Bedrock provider.
// ImageGeneration generates images using Amazon Bedrock.
// Supports Titan Image Generator v1, Nova Canvas v1, and Titan Image Generator v2.
// Returns a BifrostImageGenerationResponse containing the generated images and any error that occurred.
func (provider *BedrockProvider) ImageGeneration(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostImageGenerationRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) {
return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageGenerationRequest, schemas.Bedrock)
if err := providerUtils.CheckOperationAllowed(schemas.Bedrock, provider.customProviderConfig, schemas.ImageGenerationRequest); err != nil {
return nil, err
}

providerName := provider.GetProviderKey()
if key.BedrockKeyConfig == nil {
return nil, providerUtils.NewConfigurationError("bedrock key config is not provided", providerName)
}

modelType := DetermineImageGenModelType(request.Model)
var rawResponse []byte
var jsonData []byte
var bifrostError *schemas.BifrostError
var latency time.Duration
Comment thread
Radheshg04 marked this conversation as resolved.
var path string
var deployment string
switch modelType {

case "titan-image-generator-v1", "nova-canvas-v1:0", "titan-image-generator-v2:0":
jsonData, bifrostError = providerUtils.CheckContextAndGetRequestBody(
ctx,
request,
func() (any, error) { return ToBedrockImageGenerationRequest(request) },
provider.GetProviderKey())
if bifrostError != nil {
return nil, bifrostError
}
path, deployment = provider.getModelPath("invoke", request.Model, key)
rawResponse, latency, bifrostError = provider.completeRequest(ctx, jsonData, path, key)
default:
return nil, providerUtils.NewConfigurationError("unsupported image generation model type", providerName)
}
Comment thread
Radheshg04 marked this conversation as resolved.
if bifrostError != nil {
return nil, providerUtils.EnrichError(ctx, bifrostError, jsonData, nil, provider.sendBackRawRequest, provider.sendBackRawResponse)
}

// Parse response based on model type
var bifrostResponse *schemas.BifrostImageGenerationResponse
switch modelType {
case "titan-image-generator-v1", "nova-canvas-v1:0", "titan-image-generator-v2:0":
var imageResp BedrockImageGenerationResponse
if err := sonic.Unmarshal(rawResponse, &imageResp); err != nil {
return nil, providerUtils.EnrichError(ctx, providerUtils.NewBifrostOperationError("error parsing image generation response", err, providerName), jsonData, rawResponse, provider.sendBackRawRequest, provider.sendBackRawResponse)
}

if imageResp.Error != "" {
return nil, providerUtils.EnrichError(ctx, providerUtils.NewBifrostOperationError(imageResp.Error, nil, providerName), jsonData, rawResponse, provider.sendBackRawRequest, provider.sendBackRawResponse)
}

bifrostResponse = ToBifrostImageGenerationResponse(&imageResp)
bifrostResponse.Model = request.Model
bifrostResponse.ExtraFields.RequestType = schemas.ImageGenerationRequest
bifrostResponse.ExtraFields.Provider = providerName
bifrostResponse.ExtraFields.ModelRequested = request.Model
bifrostResponse.ExtraFields.ModelDeployment = deployment
bifrostResponse.ExtraFields.Latency = latency.Milliseconds()

// Set raw request if enabled
if providerUtils.ShouldSendBackRawRequest(ctx, provider.sendBackRawRequest) {
providerUtils.ParseAndSetRawRequest(&bifrostResponse.ExtraFields, jsonData)
}

if providerUtils.ShouldSendBackRawResponse(ctx, provider.sendBackRawResponse) {
var rawResponseData interface{}
if err := sonic.Unmarshal(rawResponse, &rawResponseData); err == nil {
bifrostResponse.ExtraFields.RawResponse = rawResponseData
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return bifrostResponse, nil
}
return nil, providerUtils.NewConfigurationError("unsupported image generation model type", providerName)
}

// ImageGenerationStream is not supported by the Bedrock provider.
Expand Down
104 changes: 104 additions & 0 deletions core/providers/bedrock/images.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package bedrock

import (
"fmt"
"strconv"
"strings"

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

// ToBedrockImageGenerationRequest converts a Bifrost image generation request to a Bedrock image generation request
func ToBedrockImageGenerationRequest(request *schemas.BifrostImageGenerationRequest) (*BedrockImageGenerationRequest, error) {
if request == nil {
return nil, fmt.Errorf("request is nil")
}

if request.Input == nil {
return nil, fmt.Errorf("request.Input is required")
}

bedrockReq := &BedrockImageGenerationRequest{
TaskType: schemas.Ptr(TaskTypeTextImage),
TextToImageParams: &BedrockTextToImageParams{
Text: request.Input.Prompt,
},
ImageGenerationConfig: &ImageGenerationConfig{},
}

if request.Params != nil {
if request.Params.N != nil {
bedrockReq.ImageGenerationConfig.NumberOfImages = request.Params.N
}
if request.Params.NegativePrompt != nil {
bedrockReq.TextToImageParams.NegativeText = request.Params.NegativePrompt
}
if request.Params.Seed != nil {
bedrockReq.ImageGenerationConfig.Seed = request.Params.Seed
}
if request.Params.Quality != nil {
bedrockReq.ImageGenerationConfig.Quality = request.Params.Quality
}
if request.Params.Style != nil {
bedrockReq.TextToImageParams.Style = request.Params.Style
}
if request.Params.Size != nil && strings.TrimSpace(strings.ToLower(*request.Params.Size)) != "auto" {

size := strings.Split(strings.TrimSpace(strings.ToLower(*request.Params.Size)), "x")
if len(size) != 2 {
return nil, fmt.Errorf("invalid size format: expected 'WIDTHxHEIGHT', got %q", *request.Params.Size)
}

width, err := strconv.Atoi(size[0])
if err != nil {
return nil, fmt.Errorf("invalid width in size %q: %w", *request.Params.Size, err)
}

height, err := strconv.Atoi(size[1])
if err != nil {
return nil, fmt.Errorf("invalid height in size %q: %w", *request.Params.Size, err)
}

bedrockReq.ImageGenerationConfig.Width = schemas.Ptr(width)
bedrockReq.ImageGenerationConfig.Height = schemas.Ptr(height)
Comment thread
Radheshg04 marked this conversation as resolved.
}
if request.Params.ExtraParams != nil {
if cfgScale, ok := schemas.SafeExtractFloat64Pointer(request.Params.ExtraParams["cfgScale"]); ok {
bedrockReq.ImageGenerationConfig.CfgScale = cfgScale
}
}
}

return bedrockReq, nil

}

// ToBifrostImageGenerationResponse converts a Bedrock image generation response to a Bifrost image generation response
func ToBifrostImageGenerationResponse(response *BedrockImageGenerationResponse) *schemas.BifrostImageGenerationResponse {
if response == nil {
return nil
}

bifrostResponse := &schemas.BifrostImageGenerationResponse{}

for index, image := range response.Images {
bifrostResponse.Data = append(bifrostResponse.Data, schemas.ImageData{
B64JSON: image,
Index: index,
})
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return bifrostResponse
}

// DetermineImageGenModelType determines the image generation model type from the model name
func DetermineImageGenModelType(model string) string {
if strings.Contains(model, "nova-canvas-v1:0") {
return "nova-canvas-v1:0"
} else if strings.Contains(model, "titan-image-generator-v2:0") {
return "titan-image-generator-v2:0"
} else if strings.Contains(model, "titan-image-generator-v1") {
return "titan-image-generator-v1"
}
return model
}
31 changes: 31 additions & 0 deletions core/providers/bedrock/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,37 @@ type BedrockTitanEmbeddingResponse struct {
InputTextTokenCount int `json:"inputTextTokenCount"` // Number of tokens in input
}

const TaskTypeTextImage = "TEXT_IMAGE"

// BedrockImageGenerationRequest represents a Bedrock image generation request
type BedrockImageGenerationRequest struct {
TaskType *string `json:"taskType"` // Should be "TEXT_IMAGE"
TextToImageParams *BedrockTextToImageParams `json:"textToImageParams"` // Parameters for text-to-image
ImageGenerationConfig *ImageGenerationConfig `json:"imageGenerationConfig"` // Image generation config
}

type BedrockTextToImageParams struct {
Text string `json:"text"` // Prompt for image generation
NegativeText *string `json:"negativeText,omitempty"` // Negative prompt for image generation
Style *string `json:"style,omitempty"` // Style for image generation
}

type ImageGenerationConfig struct {
NumberOfImages *int `json:"numberOfImages,omitempty"`
Height *int `json:"height,omitempty"`
Width *int `json:"width,omitempty"`
CfgScale *float64 `json:"cfgScale,omitempty"`
Quality *string `json:"quality,omitempty"`
Seed *int `json:"seed,omitempty"`
}

// BedrockImageGenerationResponse represents a Bedrock image generation response
type BedrockImageGenerationResponse struct {
Images []string `json:"images"` // list of Base64 encoded images
MaskImage string `json:"maskImage"` // Base64 encoded mask image (optional)
Error string `json:"error"` // error message (if present)
}

// ==================== MODELS TYPES ====================
type BedrockModelLifecycle struct {
Status string `json:"status"`
Expand Down
92 changes: 78 additions & 14 deletions docs/providers/supported-providers/bedrock.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ AWS Bedrock supports multiple model families (Claude, Nova, Mistral, Llama, Cohe

### Model Family Support

| Family | Chat | Responses | Text | Embeddings |
|--------|------|-----------|------|------------|
| **Claude (Anthropic)** | ✅ | ✅ | ✅ | ❌ |
| **Nova (Anthropic)** | ✅ | ✅ | ❌ | ❌ |
| **Mistral** | ✅ | ✅ | ✅ | ❌ |
| **Llama** | ✅ | ✅ | ❌ | ❌ |
| **Cohere** | ✅ | ✅ | ❌ | ✅ |
| **Titan** | ✅ | ✅ | ❌ | ✅ |
| Family | Chat | Responses | Text | Embeddings | Image Generation |
|--------|------|-----------|------|------------|------------|
| **Claude (Anthropic)** | ✅ | ✅ | ✅ | ❌ | ❌ |
| **Nova (Anthropic)** | ✅ | ✅ | ❌ | ❌ | ✅ |
| **Mistral** | ✅ | ✅ | ✅ | ❌ | ❌ |
| **Llama** | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Cohere** | ✅ | ✅ | ❌ | ✅ | ❌ |
| **Titan** | ✅ | ✅ | ❌ | ✅ | ✅ |
Comment thread
Radheshg04 marked this conversation as resolved.

### Supported Operations

Expand All @@ -38,7 +38,7 @@ AWS Bedrock supports multiple model families (Claude, Nova, Mistral, Llama, Cohe
| Files | ✅ | - | S3 (via SDK) |
| Batch | ✅ | - | `batch` |
| List Models | ✅ | - | `listFoundationModels` |
| Image Generation | | ❌ | - |
| Image Generation | | ❌ | `invoke` |
| Speech (TTS) | ❌ | ❌ | - |
| Transcriptions (STT) | ❌ | ❌ | - |

Expand Down Expand Up @@ -519,7 +519,71 @@ Supported embedding models: **Titan**, **Cohere**

---

# 5. Batch API
# 5. Image Generation

Supported image generation models: **Titan Image Generator v1**, **Titan Image Generator v2**, **Nova Canvas v1**

## Request Conversion

| Parameter(Bifrost) | Transformation (Bedrock) |
|---------------------|----------------|
| `prompt` | `textToImageParams.text` |
| `n` | `imageGenerationConfig.numberOfImages` |
| `negativePrompt` | `textToImageParams.negativeText` |
| `seed` | `imageGenerationConfig.seed` |
| `quality` | `imageGenerationConfig.quality` |
| `style` | `textToImageParams.style` |
| `size` | `imageGenerationConfig.width` & `imageGenerationConfig.height` |

## Response Conversion

| Parameter(Bedrock) | Transformation (Bifrost) |
|---------------------|--------------------------|
| `images` | `data.b64_json` |

### Example Request

<Tabs>
<Tab title="Gateway">

```bash
curl -X POST http://localhost:8080/v1/images/generations \
-H "Content-Type: application/json" \
-d '{
"model": "bedrock/amazon.nova-canvas-v1:0",
"prompt": "A futuristic cityscape with a flying car",
"size": "1024x1024",
"seed": 123,
"negative_prompt": "bikes",
"n": 2
}'
```

</Tab>
<Tab title="Go SDK">

```go
resp, err := client.ImageGenerationRequest(ctx, &schemas.BifrostImageGenerationRequest{
Provider: schemas.Bedrock,
Model: "amazon.nova-canvas-v1:0",
Input: &schemas.ImageGenerationInput{
Prompt: "A futuristic cityscape with a flying car",
},
Params: &schemas.ImageGenerationParameters{
N: schemas.Ptr(2),
Seed: schemas.Ptr(123),
NegativePrompt: schemas.Ptr("bikes"),
Quality: schemas.Ptr("auto"),
Style: schemas.Ptr("natural"),
Size: schemas.Ptr("1024x1024"),
},
})
```

</Tab>
</Tabs>

# 6. Batch API

**Request formats**: `requests` array (CustomID + Params) or `input_file_id`

Expand Down Expand Up @@ -548,7 +612,7 @@ Supported embedding models: **Titan**, **Cohere**

---

# 6. Files API
# 7. Files API

<Note>
S3-backed file operations. Files are stored in S3 buckets integrated with Bedrock.
Expand All @@ -574,7 +638,7 @@ S3-backed file operations. Files are stored in S3 buckets integrated with Bedroc

---

# 7. List Models
# 8. List Models

**Request**: GET `/v1/models` (no body)

Expand All @@ -594,7 +658,7 @@ S3-backed file operations. Files are stored in S3 buckets integrated with Bedroc

---

# 8. AWS Authentication & Configuration
# 9. AWS Authentication & Configuration

Bifrost automatically handles AWS Bedrock authentication via multiple methods including explicit credentials, IAM roles, and bearer tokens with automatic Signature Version 4 (SigV4) signing.

Expand Down Expand Up @@ -623,7 +687,7 @@ See **[Provider-Specific Authentication - AWS Bedrock](../../quickstart/go-sdk/p

---

# 9. Error Handling
# 10. Error Handling

**HTTP Status Mapping**:

Expand Down
2 changes: 1 addition & 1 deletion docs/providers/supported-providers/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The following table summarizes which operations are supported by each provider v
|----------|--------|------|----------------|------|---------------|-----------|--------------------|--------|-----------------|------------|-----|-------------|-----|--------------|-------|-------|--------------|
| Anthropic (`anthropic/<model>`) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
| Azure (`azure/<model>`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Bedrock (`bedrock/<model>`) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Bedrock (`bedrock/<model>`) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Cerebras (`cerebras/<model>`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Cohere (`cohere/<model>`) | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Elevenlabs (`elevenlabs/<model>`) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
Expand Down
Loading