Skip to content

Commit 78c4962

Browse files
akshaydeoslyang08
authored andcommitted
fix: set fixed index 0 for stream responses and remove nil check for usage (#983)
Fixed inconsistencies in stream response handling for Anthropic and Bedrock providers by standardizing index values and removing unnecessary conditional checks. - Removed conditional check for `usage` in Anthropic response handling, ensuring usage is always assigned - Changed dynamic index values to fixed `0` index in stream responses for both Anthropic and Bedrock providers - Removed unnecessary content block index handling in Bedrock provider - [x] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (Next.js) - [ ] Docs Test streaming responses from Anthropic and Bedrock providers to ensure proper index values and usage information: ```sh go version go test ./core/providers/anthropic/... go test ./core/providers/bedrock/... ``` - [ ] Yes - [x] No Fixes inconsistencies in stream response handling across providers. No security implications. - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [x] I verified the CI pipeline passes locally if applicable
2 parents 3f2a3fa + 07655d7 commit 78c4962

File tree

12 files changed

+125
-37
lines changed

12 files changed

+125
-37
lines changed

core/bifrost.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,12 +2504,22 @@ func (bifrost *Bifrost) selectKeyFromProviderForModel(ctx *context.Context, requ
25042504
if requestType == schemas.ListModelsRequest {
25052505
// Skip deployment check but still check if the key has a value
25062506
for _, k := range keys {
2507+
// Skip disabled keys
2508+
if k.Enabled != nil && !*k.Enabled {
2509+
continue
2510+
}
2511+
25072512
if strings.TrimSpace(k.Value) != "" || canProviderKeyValueBeEmpty(baseProviderType) {
25082513
supportedKeys = append(supportedKeys, k)
25092514
}
25102515
}
25112516
} else {
25122517
for _, key := range keys {
2518+
// Skip disabled keys
2519+
if key.Enabled != nil && !*key.Enabled {
2520+
continue
2521+
}
2522+
25132523
modelSupported := (slices.Contains(key.Models, model) && (strings.TrimSpace(key.Value) != "" || canProviderKeyValueBeEmpty(baseProviderType))) || len(key.Models) == 0
25142524

25152525
// Additional deployment checks for Azure, Bedrock and Vertex

core/changelog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
fix: vertex and bedrock usage aggregation improvements for streaming
1+
fix: vertex and bedrock usage aggregation improvements for streaming
2+
fix: choice index fixed to 0 for anthropic and bedrock streaming

core/providers/anthropic/anthropic.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -931,9 +931,7 @@ func HandleAnthropicResponsesStream(
931931
if response.Response == nil {
932932
response.Response = &schemas.BifrostResponsesResponse{}
933933
}
934-
if usage != nil {
935-
response.Response.Usage = usage
936-
}
934+
response.Response.Usage = usage
937935
response.ExtraFields.Latency = time.Since(startTime).Milliseconds()
938936
ctx = context.WithValue(ctx, schemas.BifrostContextKeyStreamEndIndicator, true)
939937
providerUtils.ProcessAndSendResponse(ctx, postHookRunner, providerUtils.GetBifrostResponseForStreamResponse(nil, nil, response, nil, nil), responseChan)

core/providers/anthropic/chat.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ func (chunk *AnthropicStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bif
725725
Object: "chat.completion.chunk",
726726
Choices: []schemas.BifrostResponseChoice{
727727
{
728-
Index: *chunk.Index,
728+
Index: 0,
729729
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
730730
Delta: &schemas.ChatStreamResponseChoiceDelta{
731731
ToolCalls: []schemas.ChatAssistantMessageToolCall{
@@ -760,7 +760,7 @@ func (chunk *AnthropicStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bif
760760
Object: "chat.completion.chunk",
761761
Choices: []schemas.BifrostResponseChoice{
762762
{
763-
Index: *chunk.Index,
763+
Index: 0,
764764
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
765765
Delta: &schemas.ChatStreamResponseChoiceDelta{
766766
Content: chunk.Delta.Text,
@@ -781,7 +781,7 @@ func (chunk *AnthropicStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bif
781781
Object: "chat.completion.chunk",
782782
Choices: []schemas.BifrostResponseChoice{
783783
{
784-
Index: *chunk.Index,
784+
Index: 0,
785785
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
786786
Delta: &schemas.ChatStreamResponseChoiceDelta{
787787
ToolCalls: []schemas.ChatAssistantMessageToolCall{
@@ -809,7 +809,7 @@ func (chunk *AnthropicStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bif
809809
Object: "chat.completion.chunk",
810810
Choices: []schemas.BifrostResponseChoice{
811811
{
812-
Index: *chunk.Index,
812+
Index: 0,
813813
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
814814
Delta: &schemas.ChatStreamResponseChoiceDelta{
815815
Thought: chunk.Delta.Thinking,

core/providers/bedrock/chat.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,6 @@ func (chunk *BedrockStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bifro
187187
return streamResponse, nil, false
188188

189189
case chunk.Start != nil && chunk.Start.ToolUse != nil:
190-
// Handle tool use start event
191-
contentBlockIndex := 0
192-
if chunk.ContentBlockIndex != nil {
193-
contentBlockIndex = *chunk.ContentBlockIndex
194-
}
195-
196190
toolUseStart := chunk.Start.ToolUse
197191

198192
// Create tool call structure for start event
@@ -206,7 +200,7 @@ func (chunk *BedrockStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bifro
206200
Object: "chat.completion.chunk",
207201
Choices: []schemas.BifrostResponseChoice{
208202
{
209-
Index: contentBlockIndex,
203+
Index: 0,
210204
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
211205
Delta: &schemas.ChatStreamResponseChoiceDelta{
212206
ToolCalls: []schemas.ChatAssistantMessageToolCall{toolCall},
@@ -218,10 +212,7 @@ func (chunk *BedrockStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bifro
218212

219213
return streamResponse, nil, false
220214

221-
case chunk.ContentBlockIndex != nil && chunk.Delta != nil:
222-
// Handle contentBlockDelta event
223-
contentBlockIndex := *chunk.ContentBlockIndex
224-
215+
case chunk.Delta != nil:
225216
switch {
226217
case chunk.Delta.Text != nil:
227218
// Handle text delta
@@ -231,7 +222,7 @@ func (chunk *BedrockStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bifro
231222
Object: "chat.completion.chunk",
232223
Choices: []schemas.BifrostResponseChoice{
233224
{
234-
Index: contentBlockIndex,
225+
Index: 0,
235226
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
236227
Delta: &schemas.ChatStreamResponseChoiceDelta{
237228
Content: &text,
@@ -260,7 +251,7 @@ func (chunk *BedrockStreamEvent) ToBifrostChatCompletionStream() (*schemas.Bifro
260251
Object: "chat.completion.chunk",
261252
Choices: []schemas.BifrostResponseChoice{
262253
{
263-
Index: contentBlockIndex,
254+
Index: 0,
264255
ChatStreamResponseChoice: &schemas.ChatStreamResponseChoice{
265256
Delta: &schemas.ChatStreamResponseChoiceDelta{
266257
ToolCalls: []schemas.ChatAssistantMessageToolCall{toolCall},

core/schemas/account.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Key struct {
1414
AzureKeyConfig *AzureKeyConfig `json:"azure_key_config,omitempty"` // Azure-specific key configuration
1515
VertexKeyConfig *VertexKeyConfig `json:"vertex_key_config,omitempty"` // Vertex-specific key configuration
1616
BedrockKeyConfig *BedrockKeyConfig `json:"bedrock_key_config,omitempty"` // AWS Bedrock-specific key configuration
17+
Enabled *bool `json:"enabled,omitempty"` // Whether the key is active (default: true)
1718
}
1819

1920
// AzureKeyConfig represents the Azure-specific configuration.

framework/configstore/migrations.go

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ func triggerMigrations(ctx context.Context, db *gorm.DB) error {
7979
if err := migrationAddLogRetentionDaysColumn(ctx, db); err != nil {
8080
return err
8181
}
82+
if err := migrationAddEnabledColumnToKeyTable(ctx, db); err != nil {
83+
return err
84+
}
8285
if err := migrationAddBatchAndCachePricingColumns(ctx, db); err != nil {
8386
return err
8487
}
@@ -1079,6 +1082,49 @@ func migrationAddLogRetentionDaysColumn(ctx context.Context, db *gorm.DB) error
10791082
return nil
10801083
}
10811084

1085+
// migrationAddEnabledColumnToKeyTable adds the enabled column to the config_keys table
1086+
func migrationAddEnabledColumnToKeyTable(ctx context.Context, db *gorm.DB) error {
1087+
m := migrator.New(db, migrator.DefaultOptions, []*migrator.Migration{{
1088+
ID: "add_enabled_column_to_key_table",
1089+
Migrate: func(tx *gorm.DB) error {
1090+
tx = tx.WithContext(ctx)
1091+
mg := tx.Migrator()
1092+
1093+
// Check if column already exists
1094+
if !mg.HasColumn(&tables.TableKey{}, "enabled") {
1095+
// Add the column
1096+
if err := mg.AddColumn(&tables.TableKey{}, "enabled"); err != nil {
1097+
return fmt.Errorf("failed to add enabled column: %w", err)
1098+
}
1099+
1100+
// Set default = true for existing rows
1101+
if err := tx.Exec("UPDATE config_keys SET enabled = TRUE WHERE enabled IS NULL").Error; err != nil {
1102+
return fmt.Errorf("failed to backfill enabled column: %w", err)
1103+
}
1104+
}
1105+
1106+
return nil
1107+
},
1108+
Rollback: func(tx *gorm.DB) error {
1109+
tx = tx.WithContext(ctx)
1110+
mg := tx.Migrator()
1111+
1112+
if mg.HasColumn(&tables.TableKey{}, "enabled") {
1113+
if err := mg.DropColumn(&tables.TableKey{}, "enabled"); err != nil {
1114+
return fmt.Errorf("failed to drop enabled column: %w", err)
1115+
}
1116+
}
1117+
1118+
return nil
1119+
},
1120+
}})
1121+
1122+
if err := m.Migrate(); err != nil {
1123+
return fmt.Errorf("error running enabled column migration: %s", err.Error())
1124+
}
1125+
return nil
1126+
}
1127+
10821128
// migrationAddBatchAndCachePricingColumns adds the cache_read_input_token_cost, cache_creation_input_token_cost, input_cost_per_token_batches, and output_cost_per_token_batches columns to the model_pricing table
10831129
func migrationAddBatchAndCachePricingColumns(ctx context.Context, db *gorm.DB) error {
10841130
m := migrator.New(db, migrator.DefaultOptions, []*migrator.Migration{{
@@ -1137,18 +1183,18 @@ func migrationMoveKeysToProviderConfig(ctx context.Context, db *gorm.DB) error {
11371183
tx = tx.WithContext(ctx)
11381184
gormMigrator := tx.Migrator()
11391185

1140-
// Step 1: Create the new join table for provider config -> keys relationship
1141-
// Setup the join table so GORM knows about the custom structure
1142-
if err := tx.SetupJoinTable(&tables.TableVirtualKeyProviderConfig{}, "Keys", &tables.TableVirtualKeyProviderConfigKey{}); err != nil {
1143-
return fmt.Errorf("failed to setup join table for provider config keys: %w", err)
1144-
}
1186+
// Step 1: Create the new join table for provider config -> keys relationship
1187+
// Setup the join table so GORM knows about the custom structure
1188+
if err := tx.SetupJoinTable(&tables.TableVirtualKeyProviderConfig{}, "Keys", &tables.TableVirtualKeyProviderConfigKey{}); err != nil {
1189+
return fmt.Errorf("failed to setup join table for provider config keys: %w", err)
1190+
}
11451191

1146-
// Create the join table if it doesn't exist
1147-
if !gormMigrator.HasTable(&tables.TableVirtualKeyProviderConfigKey{}) {
1148-
if err := gormMigrator.CreateTable(&tables.TableVirtualKeyProviderConfigKey{}); err != nil {
1149-
return fmt.Errorf("failed to create join table for provider config keys: %w", err)
1192+
// Create the join table if it doesn't exist
1193+
if !gormMigrator.HasTable(&tables.TableVirtualKeyProviderConfigKey{}) {
1194+
if err := gormMigrator.CreateTable(&tables.TableVirtualKeyProviderConfigKey{}); err != nil {
1195+
return fmt.Errorf("failed to create join table for provider config keys: %w", err)
1196+
}
11501197
}
1151-
}
11521198

11531199
// Step 2: Migrate existing key associations from virtual key to provider config level
11541200
// Check if old join table exists
@@ -1276,4 +1322,4 @@ func migrationAddPluginVersionColumn(ctx context.Context, db *gorm.DB) error {
12761322
return fmt.Errorf("error while running add plugin version column migration: %s", err.Error())
12771323
}
12781324
return nil
1279-
}
1325+
}

framework/configstore/tables/key.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type TableKey struct {
1919
Value string `gorm:"type:text;not null" json:"value"`
2020
ModelsJSON string `gorm:"type:text" json:"-"` // JSON serialized []string
2121
Weight float64 `gorm:"default:1.0" json:"weight"`
22+
Enabled *bool `gorm:"default:true" json:"enabled,omitempty"`
2223
CreatedAt time.Time `gorm:"index;not null" json:"created_at"`
2324
UpdatedAt time.Time `gorm:"index;not null" json:"updated_at"`
2425

@@ -64,6 +65,11 @@ func (k *TableKey) BeforeSave(tx *gorm.DB) error {
6465
k.ModelsJSON = "[]"
6566
}
6667

68+
if k.Enabled == nil {
69+
enabled := true // DB default
70+
k.Enabled = &enabled
71+
}
72+
6773
if k.AzureKeyConfig != nil {
6874
if k.AzureKeyConfig.Endpoint != "" {
6975
k.AzureEndpoint = &k.AzureKeyConfig.Endpoint
@@ -168,6 +174,11 @@ func (k *TableKey) AfterFind(tx *gorm.DB) error {
168174
}
169175
}
170176

177+
if k.Enabled == nil {
178+
enabled := true // DB default
179+
k.Enabled = &enabled
180+
}
181+
171182
// Reconstruct Azure config if fields are present
172183
if k.AzureEndpoint != nil {
173184
azureConfig := &schemas.AzureKeyConfig{

transports/bifrost-http/lib/config.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,10 +1383,11 @@ func (c *Config) GetProviderConfigRedacted(provider schemas.ModelProvider) (*con
13831383
redactedConfig.Keys = make([]schemas.Key, len(config.Keys))
13841384
for i, key := range config.Keys {
13851385
redactedConfig.Keys[i] = schemas.Key{
1386-
ID: key.ID,
1387-
Name: key.Name,
1388-
Models: key.Models, // Copy slice reference - read-only so safe
1389-
Weight: key.Weight,
1386+
ID: key.ID,
1387+
Name: key.Name,
1388+
Models: key.Models, // Copy slice reference - read-only so safe
1389+
Weight: key.Weight,
1390+
Enabled: key.Enabled,
13901391
}
13911392

13921393
// Redact API key value

transports/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fix: vertex and bedrock usage aggregation improvements for streaming
2+
fix: choice index fixed to 0 for anthropic and bedrock streaming

0 commit comments

Comments
 (0)