diff --git a/core/bifrost.go b/core/bifrost.go
index 32959ed30a..6e42fe25e5 100644
--- a/core/bifrost.go
+++ b/core/bifrost.go
@@ -1248,8 +1248,12 @@ func (bifrost *Bifrost) ImageEditRequest(ctx *schemas.BifrostContext, req *schem
},
}
}
- // Prompt is not required when type is background_removal
- if (req.Params == nil || req.Params.Type == nil || *req.Params.Type != "background_removal") &&
+ // Prompt is not required for certain operation types that work without a text prompt
+ var imageEditParamsType *string
+ if req.Params != nil {
+ imageEditParamsType = req.Params.Type
+ }
+ if !isPromptOptionalImageEditType(imageEditParamsType) &&
(req.Input == nil || req.Input.Prompt == "") && !isLargePayloadPassthrough(ctx) {
return nil, &schemas.BifrostError{
IsBifrostError: false,
@@ -1316,8 +1320,12 @@ func (bifrost *Bifrost) ImageEditStreamRequest(ctx *schemas.BifrostContext, req
},
}
}
- // Prompt is not required when type is background_removal
- if (req.Params == nil || req.Params.Type == nil || *req.Params.Type != "background_removal") &&
+ // Prompt is not required for certain operation types that work without a text prompt
+ var imageEditStreamParamsType *string
+ if req.Params != nil {
+ imageEditStreamParamsType = req.Params.Type
+ }
+ if !isPromptOptionalImageEditType(imageEditStreamParamsType) &&
(req.Input == nil || req.Input.Prompt == "") && !isLargePayloadPassthrough(ctx) {
return nil, &schemas.BifrostError{
IsBifrostError: false,
diff --git a/core/providers/bedrock/bedrock.go b/core/providers/bedrock/bedrock.go
index 9799c74ac6..9d8f09a246 100644
--- a/core/providers/bedrock/bedrock.go
+++ b/core/providers/bedrock/bedrock.go
@@ -1953,8 +1953,10 @@ func (provider *BedrockProvider) ImageGenerationStream(ctx *schemas.BifrostConte
}
// ImageEdit performs image editing using Amazon Bedrock.
-// Supports Titan Image Generator v1, Nova Canvas v1, and Titan Image Generator v2.
-// Supports three edit types: INPAINTING, OUTPAINTING, and BACKGROUND_REMOVAL.
+// Supports Titan Image Generator v1, Nova Canvas v1, Titan Image Generator v2 (three edit types:
+// INPAINTING, OUTPAINTING, BACKGROUND_REMOVAL), and Stability AI edit models (inpaint, outpaint,
+// recolor, search-replace, erase-object, remove-bg, control-sketch, control-structure, style-guide,
+// style-transfer, upscale-creative, upscale-conservative, upscale-fast).
// Returns a BifrostImageGenerationResponse containing the edited images and any error that occurred.
func (provider *BedrockProvider) ImageEdit(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostImageEditRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) {
if err := providerUtils.CheckOperationAllowed(schemas.Bedrock, provider.customProviderConfig, schemas.ImageEditRequest); err != nil {
@@ -1969,17 +1971,25 @@ func (provider *BedrockProvider) ImageEdit(ctx *schemas.BifrostContext, key sche
var jsonData []byte
var bifrostError *schemas.BifrostError
+ // Resolve deployment alias before building the request body so that
+ // Stability AI routing and task-type inference use the actual model ID.
+ path, deployment := provider.getModelPath("invoke", request.Model, key)
+
jsonData, bifrostError = providerUtils.CheckContextAndGetRequestBody(
ctx,
request,
- func() (providerUtils.RequestBodyWithExtraParams, error) { return ToBedrockImageEditRequest(request) },
+ func() (providerUtils.RequestBodyWithExtraParams, error) {
+ if isStabilityAIModel(deployment) {
+ return ToStabilityAIImageEditRequest(request, deployment)
+ }
+ return ToBedrockImageEditRequest(request)
+ },
provider.GetProviderKey())
if bifrostError != nil {
return nil, bifrostError
}
// Make API request (same URL as image generation)
- path, deployment := provider.getModelPath("invoke", request.Model, key)
rawResponse, latency, providerResponseHeaders, bifrostError := provider.completeRequest(ctx, jsonData, path, key)
if providerResponseHeaders != nil {
ctx.SetValue(schemas.BifrostContextKeyProviderResponseHeaders, providerResponseHeaders)
diff --git a/core/providers/bedrock/images.go b/core/providers/bedrock/images.go
index eba0f1f7ef..bbf9330a48 100644
--- a/core/providers/bedrock/images.go
+++ b/core/providers/bedrock/images.go
@@ -405,6 +405,292 @@ func buildImageGenerationConfig(params *schemas.ImageEditParameters) *ImageGener
return config
}
+// getStabilityAITaskTypeFromParams maps the generic BifrostImageEditParameters.Type value
+// to a Stability AI task type string. Returns "" if the value is not a recognized Stability AI task type.
+func getStabilityAITaskTypeFromParams(t string) string {
+ switch strings.ToLower(t) {
+ case "inpainting", "inpaint":
+ return "inpaint"
+ case "outpainting", "outpaint":
+ return "outpaint"
+ case "background_removal", "remove_background":
+ return "remove-bg"
+ case "erase_object":
+ return "erase-object"
+ case "upscale_fast":
+ return "upscale-fast"
+ case "upscale_creative":
+ return "upscale-creative"
+ case "upscale_conservative":
+ return "upscale-conservative"
+ case "recolor":
+ return "recolor"
+ case "search_replace":
+ return "search-replace"
+ case "control_sketch":
+ return "control-sketch"
+ case "control_structure":
+ return "control-structure"
+ case "style_guide":
+ return "style-guide"
+ case "style_transfer":
+ return "style-transfer"
+ default:
+ return ""
+ }
+}
+
+// getStabilityAIEditTaskType infers the Stability AI edit task from the model name.
+// Returns an error if the model name does not match any known pattern.
+func getStabilityAIEditTaskType(model string) (string, error) {
+ m := strings.ToLower(model)
+ switch {
+ case strings.Contains(m, "stable-creative-upscale"):
+ return "upscale-creative", nil
+ case strings.Contains(m, "stable-conservative-upscale"):
+ return "upscale-conservative", nil
+ case strings.Contains(m, "stable-fast-upscale"):
+ return "upscale-fast", nil
+ case strings.Contains(m, "stable-image-inpaint"):
+ return "inpaint", nil
+ case strings.Contains(m, "stable-outpaint"):
+ return "outpaint", nil
+ case strings.Contains(m, "stable-image-search-recolor"):
+ return "recolor", nil
+ case strings.Contains(m, "stable-image-search-replace"):
+ return "search-replace", nil
+ case strings.Contains(m, "stable-image-erase-object"):
+ return "erase-object", nil
+ case strings.Contains(m, "stable-image-remove-background"):
+ return "remove-bg", nil
+ case strings.Contains(m, "stable-image-control-sketch"):
+ return "control-sketch", nil
+ case strings.Contains(m, "stable-image-control-structure"):
+ return "control-structure", nil
+ case strings.Contains(m, "stable-image-style-guide"):
+ return "style-guide", nil
+ case strings.Contains(m, "stable-style-transfer"):
+ return "style-transfer", nil
+ default:
+ return "", fmt.Errorf("cannot determine task type from stability ai model name %q", model)
+ }
+}
+
+// ToStabilityAIImageEditRequest converts a Bifrost image edit request to the Stability AI flat request
+// format used by Bedrock edit models. Only fields valid for the detected task type are populated.
+// deployment is the resolved model identifier (after applying any deployment alias mapping); it is
+// used for task-type inference so that alias-mapped models route correctly.
+func ToStabilityAIImageEditRequest(request *schemas.BifrostImageEditRequest, deployment string) (*StabilityAIImageEditRequest, error) {
+ if request == nil || request.Input == nil {
+ return nil, fmt.Errorf("request or input is nil")
+ }
+
+ var taskType string
+ if request.Params != nil && request.Params.Type != nil {
+ taskType = getStabilityAITaskTypeFromParams(*request.Params.Type)
+ }
+ if taskType == "" {
+ var err error
+ taskType, err = getStabilityAIEditTaskType(deployment)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ req := &StabilityAIImageEditRequest{}
+
+ // Image sourcing
+ if taskType == "style-transfer" {
+ if len(request.Input.Images) != 2 {
+ return nil, fmt.Errorf("style-transfer requires exactly two images: init_image and style_image")
+ }
+ if len(request.Input.Images[0].Image) == 0 || len(request.Input.Images[1].Image) == 0 {
+ return nil, fmt.Errorf("style-transfer requires non-empty init_image and style_image")
+ }
+ initB64 := base64.StdEncoding.EncodeToString(request.Input.Images[0].Image)
+ styleB64 := base64.StdEncoding.EncodeToString(request.Input.Images[1].Image)
+ req.InitImage = &initB64
+ req.StyleImage = &styleB64
+ } else {
+ if len(request.Input.Images) == 0 || len(request.Input.Images[0].Image) == 0 {
+ return nil, fmt.Errorf("at least one image is required")
+ }
+ imageB64 := base64.StdEncoding.EncodeToString(request.Input.Images[0].Image)
+ req.Image = &imageB64
+ }
+
+ // Common fields populated based on task allowlist
+ prompt := request.Input.Prompt
+ switch taskType {
+ case "inpaint", "recolor", "search-replace", "control-sketch", "control-structure",
+ "style-guide", "upscale-creative", "upscale-conservative", "outpaint", "style-transfer":
+ req.Prompt = &prompt
+ }
+
+ // Negative prompt
+ if request.Params != nil && request.Params.NegativePrompt != nil {
+ switch taskType {
+ case "inpaint", "outpaint", "recolor", "search-replace", "control-sketch",
+ "control-structure", "style-guide", "upscale-creative", "upscale-conservative", "style-transfer":
+ req.NegativePrompt = request.Params.NegativePrompt
+ }
+ }
+
+ // Seed
+ if request.Params != nil && request.Params.Seed != nil {
+ switch taskType {
+ case "inpaint", "outpaint", "recolor", "search-replace", "erase-object", "control-sketch",
+ "control-structure", "style-guide", "upscale-creative", "upscale-conservative", "style-transfer":
+ req.Seed = request.Params.Seed
+ }
+ }
+
+ // Mask (from Params.Mask bytes)
+ if request.Params != nil && len(request.Params.Mask) > 0 {
+ switch taskType {
+ case "inpaint", "erase-object":
+ maskB64 := base64.StdEncoding.EncodeToString(request.Params.Mask)
+ req.Mask = &maskB64
+ }
+ }
+
+ // ExtraParams
+ if request.Params != nil {
+ // Typed OutputFormat takes priority over ExtraParams
+ if request.Params.OutputFormat != nil {
+ req.OutputFormat = request.Params.OutputFormat
+ }
+
+ if request.Params.ExtraParams != nil {
+ ep := make(map[string]interface{}, len(request.Params.ExtraParams))
+ for k, v := range request.Params.ExtraParams {
+ ep[k] = v
+ }
+
+ // output_format — all tasks (fallback if not already set by typed field)
+ if req.OutputFormat == nil {
+ if v, ok := schemas.SafeExtractStringPointer(ep["output_format"]); ok {
+ delete(ep, "output_format")
+ req.OutputFormat = v
+ }
+ }
+
+ // style_preset
+ switch taskType {
+ case "inpaint", "outpaint", "recolor", "search-replace", "control-sketch",
+ "control-structure", "style-guide", "upscale-creative":
+ if v, ok := schemas.SafeExtractStringPointer(ep["style_preset"]); ok {
+ delete(ep, "style_preset")
+ req.StylePreset = v
+ }
+ }
+
+ // grow_mask
+ switch taskType {
+ case "inpaint", "recolor", "search-replace", "erase-object":
+ if v, ok := schemas.SafeExtractIntPointer(ep["grow_mask"]); ok {
+ delete(ep, "grow_mask")
+ req.GrowMask = v
+ }
+ }
+
+ // outpaint directional fields
+ if taskType == "outpaint" {
+ if v, ok := schemas.SafeExtractIntPointer(ep["left"]); ok {
+ delete(ep, "left")
+ req.Left = v
+ }
+ if v, ok := schemas.SafeExtractIntPointer(ep["right"]); ok {
+ delete(ep, "right")
+ req.Right = v
+ }
+ if v, ok := schemas.SafeExtractIntPointer(ep["up"]); ok {
+ delete(ep, "up")
+ req.Up = v
+ }
+ if v, ok := schemas.SafeExtractIntPointer(ep["down"]); ok {
+ delete(ep, "down")
+ req.Down = v
+ }
+ }
+
+ // creativity
+ switch taskType {
+ case "upscale-creative", "upscale-conservative", "outpaint":
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["creativity"]); ok {
+ delete(ep, "creativity")
+ req.Creativity = v
+ }
+ }
+
+ // select_prompt (recolor)
+ if taskType == "recolor" {
+ if v, ok := schemas.SafeExtractStringPointer(ep["select_prompt"]); ok {
+ delete(ep, "select_prompt")
+ req.SelectPrompt = v
+ }
+ }
+
+ // search_prompt (search-replace)
+ if taskType == "search-replace" {
+ if v, ok := schemas.SafeExtractStringPointer(ep["search_prompt"]); ok {
+ delete(ep, "search_prompt")
+ req.SearchPrompt = v
+ }
+ }
+
+ // control_strength
+ switch taskType {
+ case "control-sketch", "control-structure":
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["control_strength"]); ok {
+ delete(ep, "control_strength")
+ req.ControlStrength = v
+ }
+ }
+
+ // style-guide fields
+ if taskType == "style-guide" {
+ if v, ok := schemas.SafeExtractStringPointer(ep["aspect_ratio"]); ok {
+ delete(ep, "aspect_ratio")
+ req.AspectRatio = v
+ }
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["fidelity"]); ok {
+ delete(ep, "fidelity")
+ req.Fidelity = v
+ }
+ }
+
+ // style-transfer fields
+ if taskType == "style-transfer" {
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["style_strength"]); ok {
+ delete(ep, "style_strength")
+ req.StyleStrength = v
+ }
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["composition_fidelity"]); ok {
+ delete(ep, "composition_fidelity")
+ req.CompositionFidelity = v
+ }
+ if v, ok := schemas.SafeExtractFloat64Pointer(ep["change_strength"]); ok {
+ delete(ep, "change_strength")
+ req.ChangeStrength = v
+ }
+ }
+
+ req.ExtraParams = ep
+ }
+ }
+
+ // Validate required per-task fields
+ if taskType == "recolor" && (req.SelectPrompt == nil || *req.SelectPrompt == "") {
+ return nil, fmt.Errorf("select_prompt is required for stability ai recolor task")
+ }
+ if taskType == "search-replace" && (req.SearchPrompt == nil || *req.SearchPrompt == "") {
+ return nil, fmt.Errorf("search_prompt is required for stability ai search-replace task")
+ }
+
+ return req, nil
+}
+
// ToBifrostImageGenerationResponse converts a Bedrock image generation response to a Bifrost image generation response
func ToBifrostImageGenerationResponse(response *BedrockImageGenerationResponse) *schemas.BifrostImageGenerationResponse {
if response == nil {
diff --git a/core/providers/bedrock/types.go b/core/providers/bedrock/types.go
index 87468fe976..3950a79f9c 100644
--- a/core/providers/bedrock/types.go
+++ b/core/providers/bedrock/types.go
@@ -770,11 +770,63 @@ func (req *StabilityAIImageGenerationRequest) GetExtraParams() map[string]interf
return req.ExtraParams
}
-// BedrockImageGenerationResponse represents a Bedrock image generation response
+// StabilityAIImageEditRequest is the flat JSON body for Stability AI image-edit models on Bedrock.
+// Only the fields valid for the detected task type are populated.
+type StabilityAIImageEditRequest struct {
+ // Shared params
+ Image *string `json:"image,omitempty"` // base64, primary input image
+ Prompt *string `json:"prompt,omitempty"`
+ NegativePrompt *string `json:"negative_prompt,omitempty"`
+ Seed *int `json:"seed,omitempty"`
+ OutputFormat *string `json:"output_format,omitempty"`
+ StylePreset *string `json:"style_preset,omitempty"`
+ Mask *string `json:"mask,omitempty"` // base64 mask image
+ GrowMask *int `json:"grow_mask,omitempty"`
+
+ // Outpaint
+ Left *int `json:"left,omitempty"`
+ Right *int `json:"right,omitempty"`
+ Up *int `json:"up,omitempty"`
+ Down *int `json:"down,omitempty"`
+
+ // Upscale-creative / upscale-conservative / outpaint
+ Creativity *float64 `json:"creativity,omitempty"`
+
+ // Recolor
+ SelectPrompt *string `json:"select_prompt,omitempty"`
+
+ // Search-replace
+ SearchPrompt *string `json:"search_prompt,omitempty"`
+
+ // Control-sketch / control-structure
+ ControlStrength *float64 `json:"control_strength,omitempty"`
+
+ // Style-guide
+ AspectRatio *string `json:"aspect_ratio,omitempty"`
+ Fidelity *float64 `json:"fidelity,omitempty"`
+
+ // Style-transfer (uses different image field names)
+ InitImage *string `json:"init_image,omitempty"`
+ StyleImage *string `json:"style_image,omitempty"`
+ StyleStrength *float64 `json:"style_strength,omitempty"`
+ CompositionFidelity *float64 `json:"composition_fidelity,omitempty"`
+ ChangeStrength *float64 `json:"change_strength,omitempty"`
+
+ ExtraParams map[string]interface{} `json:"-"`
+}
+
+func (req *StabilityAIImageEditRequest) GetExtraParams() map[string]interface{} {
+ return req.ExtraParams
+}
+
+// BedrockImageGenerationResponse represents a Bedrock image generation response.
+// The Seeds and FinishReasons fields are populated by Stability AI edit models only.
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)
+ 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)
+ Seeds []int `json:"seeds"` // Stability AI: seeds used per image
+ FinishReasons []*string `json:"finish_reasons"` // Stability AI: finish reason per image (may be null)
}
// ==================== MODELS TYPES ====================
diff --git a/core/schemas/images.go b/core/schemas/images.go
index d16df42a10..7f5ded7d7c 100644
--- a/core/schemas/images.go
+++ b/core/schemas/images.go
@@ -254,7 +254,7 @@ type ImageInput struct {
}
type ImageEditParameters struct {
- Type *string `json:"type,omitempty"` // "inpainting", "outpainting", "background_removal",
+ Type *string `json:"type,omitempty"` // "inpainting", "outpainting", "background_removal", "remove_background", "erase_object", "recolor", "search_replace", "control_sketch", "control_structure", "style_guide", "style_transfer", "upscale_fast", "upscale_creative", "upscale_conservative"
Background *string `json:"background,omitempty"` // "transparent", "opaque", "auto"
InputFidelity *string `json:"input_fidelity,omitempty"` // "low", "high"
Mask []byte `json:"mask,omitempty"`
diff --git a/core/utils.go b/core/utils.go
index dfbc7a95b6..8e926c94a7 100644
--- a/core/utils.go
+++ b/core/utils.go
@@ -10,6 +10,7 @@ import (
"math/rand"
"net"
"net/url"
+ "slices"
"strings"
"time"
@@ -508,3 +509,17 @@ func buildSessionKey(providerKey schemas.ModelProvider, sessionID string, model
}
return "session:" + string(providerKey) + ":" + hashedSessionID + ":" + hashSHA256(discriminator)
}
+
+// isPromptOptionalImageEditType returns true for edit task types that do not require a text prompt.
+// It normalises hyphenated variants (e.g. "erase-object") to underscore form before matching.
+func isPromptOptionalImageEditType(t *string) bool {
+ if t == nil {
+ return false
+ }
+ normalized := strings.ToLower(strings.TrimSpace(*t))
+ normalized = strings.ReplaceAll(normalized, "-", "_")
+ return slices.Contains(
+ []string{"background_removal", "remove_background", "remove_bg", "erase_object", "upscale_fast"},
+ normalized,
+ )
+}
diff --git a/docs/providers/supported-providers/bedrock.mdx b/docs/providers/supported-providers/bedrock.mdx
index 47492afd84..f3a288541c 100644
--- a/docs/providers/supported-providers/bedrock.mdx
+++ b/docs/providers/supported-providers/bedrock.mdx
@@ -26,6 +26,7 @@ AWS Bedrock supports multiple model families (Claude, Nova, Mistral, Llama, Cohe
| **Llama** | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| **Cohere** | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| **Titan** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
+| **Stability AI** | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
### Supported Operations
@@ -761,6 +762,62 @@ resp, err := client.ImageGenerationRequest(schemas.NewBifrostContext(ctx, schema
+## Stability AI models
+
+Supported generation models: **`stability.stable-image-core-v1:1`**, **`stability.stable-image-ultra-v1:1`**
+
+These models use a flat JSON body (not the nested Bedrock `taskType` structure). Bifrost detects them automatically — any model ID containing `"stability."` is converted via `ToStabilityAIImageGenerationRequest`.
+
+**Request Parameters**
+
+| Parameter | Type | Required | Notes |
+|-----------|------|----------|-------|
+| `prompt` | string | ✅ | Text description of the image |
+| `negative_prompt` | string | ❌ | What to exclude |
+| `seed` | int | ❌ | Reproducibility seed |
+| `aspect_ratio` | string | ❌ | e.g. `"16:9"`, `"1:1"`, `"21:9"` — via `aspect_ratio` param or `ExtraParams["aspect_ratio"]` |
+| `output_format` | string | ❌ | `"png"`, `"jpeg"`, `"webp"` — via `output_format` param |
+
+### Example Request
+
+
+
+
+```bash
+curl -X POST http://localhost:8080/v1/images/generations \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "bedrock/us.stability.stable-image-ultra-v1:1",
+ "prompt": "A majestic mountain range at golden hour",
+ "negative_prompt": "blurry, low quality",
+ "aspect_ratio": "16:9",
+ "output_format": "png",
+ "seed": 42
+ }'
+```
+
+
+
+
+```go
+resp, err := client.ImageGenerationRequest(schemas.NewBifrostContext(ctx, schemas.NoDeadline), &schemas.BifrostImageGenerationRequest{
+ Provider: schemas.Bedrock,
+ Model: "us.stability.stable-image-ultra-v1:1",
+ Input: &schemas.ImageGenerationInput{
+ Prompt: "A majestic mountain range at golden hour",
+ },
+ Params: &schemas.ImageGenerationParameters{
+ NegativePrompt: schemas.Ptr("blurry, low quality"),
+ AspectRatio: schemas.Ptr("16:9"),
+ OutputFormat: schemas.Ptr("png"),
+ Seed: schemas.Ptr(42),
+ },
+})
+```
+
+
+
+
---
# 6. Image Edit
@@ -840,6 +897,176 @@ Bedrock supports three image edit task types: **INPAINTING**, **OUTPAINTING**, a
---
+## Stability AI models
+
+
+Requests use **multipart/form-data**, not JSON.
+
+
+Stability AI edit models are automatically detected by their model ID (contains `"stability."`). The **task type is inferred from the model name** by default, but you can also set the `type` field explicitly — useful when using deployment aliases. See [Type values for explicit task selection](#type-values-for-explicit-task-selection) below.
+
+### Supported models
+
+| Model ID | Task | Images required | Prompt |
+|----------|------|-----------------|--------|
+| `stability.stable-image-inpaint-v1:0` | inpaint | 1 + mask | ✅ |
+| `stability.stable-outpaint-v1:0` | outpaint | 1 (optional mask) | ✅ |
+| `stability.stable-image-search-recolor-v1:0` | recolor | 1 | ✅ |
+| `stability.stable-image-search-replace-v1:0` | search-replace | 1 | ✅ |
+| `stability.stable-image-erase-object-v1:0` | erase-object | 1 + mask | ❌ |
+| `stability.stable-image-remove-background-v1:0` | remove-bg | 1 | ❌ |
+| `stability.stable-image-control-sketch-v1:0` | control-sketch | 1 | ✅ |
+| `stability.stable-image-control-structure-v1:0` | control-structure | 1 | ✅ |
+| `stability.stable-image-style-guide-v1:0` | style-guide | 1 | ✅ |
+| `stability.stable-style-transfer-v1:0` | style-transfer | **2 required** | ✅ |
+| `stability.stable-creative-upscale-v1:0` | upscale-creative | 1 | ✅ |
+| `stability.stable-conservative-upscale-v1:0` | upscale-conservative | 1 | ✅ |
+| `stability.stable-fast-upscale-v1:0` | upscale-fast | 1 | ❌ |
+
+### Common parameters
+
+| Parameter | Type | Required | Notes |
+|-----------|------|----------|-------|
+| `model` | string | ✅ | Stability AI model ID (see table above) |
+| `image[]` | binary | ✅ | Input image(s). `style-transfer` requires exactly 2. |
+| `prompt` | string | task-dependent | Required for all tasks except `remove-bg`, `upscale-fast`, and `erase-object`. For these no-prompt operations, set `type` to `remove_background`, `upscale_fast`, or `erase_object` to skip prompt validation at the gateway level. |
+| `negative_prompt` | string | ❌ | Not applied for: `remove-bg`, `upscale-fast`, `erase-object` |
+| `seed` | int | ❌ | Not applied for: `remove-bg`, `upscale-fast` |
+| `mask` | binary | task-dependent | Required for: `inpaint`, `erase-object`; ignored for others |
+
+### Task-specific extra parameters
+
+Pass these via `extra_params` (Go SDK) or as top-level form fields (Gateway).
+
+| Extra parameter | Type | Task(s) |
+|-----------------|------|---------|
+| `output_format` | string | All — `"png"`, `"jpeg"`, `"webp"` |
+| `style_preset` | string | inpaint, outpaint, recolor, search-replace, control-sketch, control-structure, style-guide, upscale-creative |
+| `grow_mask` | int | inpaint, recolor, search-replace, erase-object |
+| `left`, `right`, `up`, `down` | int | outpaint — pixels to expand in each direction |
+| `creativity` | float | upscale-creative, upscale-conservative, outpaint |
+| `select_prompt` | string | recolor — which region to recolor |
+| `search_prompt` | string | search-replace — what object to find and replace |
+| `control_strength` | float | control-sketch, control-structure — 0.0–1.0 |
+| `aspect_ratio` | string | style-guide — output aspect ratio |
+| `fidelity` | float | style-guide — 0.0–1.0 |
+| `style_strength` | float | style-transfer — 0.0–1.0 |
+| `composition_fidelity` | float | style-transfer — 0.0–1.0 |
+| `change_strength` | float | style-transfer — 0.0–1.0 |
+
+
+**Style-transfer image order matters.** The first image (`image[0]`) becomes `init_image` (the content to transform) and the second (`image[1]`) becomes `style_image` (the artistic reference). Both images must be non-empty.
+
+
+### Type values for explicit task selection
+
+You can set the `type` field to override model-name inference. This is especially useful with deployment aliases where the alias name may not contain the Stability AI model pattern.
+
+| `type` value | Stability AI task |
+|---|---|
+| `inpainting` or `inpaint` | inpaint |
+| `outpainting` or `outpaint` | outpaint |
+| `background_removal` or `remove_background` or `remove_bg` | remove-bg |
+| `erase_object` | erase-object |
+| `upscale_fast` | upscale-fast |
+| `upscale_creative` | upscale-creative |
+| `upscale_conservative` | upscale-conservative |
+| `recolor` | recolor |
+| `search_replace` | search-replace |
+| `control_sketch` | control-sketch |
+| `control_structure` | control-structure |
+| `style_guide` | style-guide |
+| `style_transfer` | style-transfer |
+
+### Example requests
+
+
+
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-image-inpaint-v1:0" \
+ -F "image[]=@photo.png;type=image/png" \
+ -F "mask=@mask.png;type=image/png" \
+ -F "prompt=A beautiful garden replacing the masked area" \
+ -F "negative_prompt=ugly, blurry" \
+ -F "output_format=png"
+```
+
+
+
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-style-transfer-v1:0" \
+ -F "image[]=@content.png;type=image/png" \
+ -F "image[]=@style.png;type=image/png" \
+ -F "prompt=Apply the artistic style to the content image" \
+ -F "style_strength=0.8" \
+ -F "composition_fidelity=0.5" \
+ -F "change_strength=0.4" \
+ -F "output_format=png"
+```
+
+
+
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-outpaint-v1:0" \
+ -F "image[]=@photo.png;type=image/png" \
+ -F "prompt=Extend the scene naturally" \
+ -F "left=200" \
+ -F "right=200" \
+ -F "output_format=png"
+```
+
+
+
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-image-remove-background-v1:0" \
+ -F "image[]=@photo.png;type=image/png" \
+ -F "output_format=png"
+```
+
+
+
+
+No prompt required. Set `type=erase_object` to skip gateway prompt validation.
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-image-erase-object-v1:0" \
+ -F "image[]=@photo.png;type=image/png" \
+ -F "mask=@mask.png;type=image/png" \
+ -F "type=erase_object" \
+ -F "output_format=png"
+```
+
+
+
+
+No prompt required. Set `type=upscale_fast` to skip gateway prompt validation.
+
+```bash
+curl -X POST http://localhost:8080/v1/images/edits \
+ -F "model=bedrock/us.stability.stable-fast-upscale-v1:0" \
+ -F "image[]=@photo.png;type=image/png" \
+ -F "type=upscale_fast" \
+ -F "output_format=png"
+```
+
+
+
+
+**Endpoint**: `invoke` endpoint (same as all other Bedrock image operations)
+
+**Streaming**: Not supported.
+
+---
+
# 7. Image Variation
diff --git a/transports/bifrost-http/handlers/inference.go b/transports/bifrost-http/handlers/inference.go
index d88d56ebb4..733403bcf9 100644
--- a/transports/bifrost-http/handlers/inference.go
+++ b/transports/bifrost-http/handlers/inference.go
@@ -1836,11 +1836,6 @@ func prepareImageEditRequest(ctx *fasthttp.RequestCtx) (*ImageEditHTTPRequest, *
editType = typeValues[0]
}
promptValues := form.Value["prompt"]
- if editType != "background_removal" {
- if len(promptValues) == 0 || promptValues[0] == "" {
- return nil, nil, fmt.Errorf("prompt is required")
- }
- }
var imageFiles []*multipart.FileHeader
if imageFilesArray := form.File["image[]"]; len(imageFilesArray) > 0 {
imageFiles = imageFilesArray