Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
194 commits
Select commit Hold shift + click to select a range
f94940b
feat: add granular RBAC checks for API keys, inference, metrics, and …
impoiler May 8, 2026
7c838b2
fix: hide delete log button instead of disabling it when user lacks d…
impoiler May 8, 2026
6e4044c
feat: add `MCPLogs` RBAC resource and enforce access control on MCP l…
impoiler May 8, 2026
2ec0b20
fix: replace unsafe inline jsonb cast with `bifrost_safe_jsonb` PL/pg…
impoiler May 12, 2026
9329830
feat: add required headers input to prompt playground settings panel …
impoiler May 12, 2026
e2d4127
fix: skip pagination clamp for virtual keys export requests (#3416)
impoiler May 12, 2026
a64338e
chore: bump `@maximhq/bifrost` to v1.6.3 (#3417)
impoiler May 12, 2026
46d5e0a
feat: add volume histogram chart to MCP logs page and fix drag-select…
impoiler May 12, 2026
a3b91f4
refactor: semantic cache plugin (#3210)
Pratham-Mishra04 May 12, 2026
896e5e0
feat: remove `cleanup_on_shutdown` from semantic cache plugin config …
Pratham-Mishra04 May 12, 2026
122fd65
refactor: semantic cache ui revamp (#3331)
Pratham-Mishra04 May 12, 2026
488182e
fix: resolve cache plugin at request time to support post-boot loads …
Pratham-Mishra04 May 12, 2026
a97fe51
fix: decouple cache telemetry from write decision and guard no-op sea…
Pratham-Mishra04 May 12, 2026
a05f9e1
test: add semantic cache e2e test suite skeleton (#3425)
Pratham-Mishra04 May 12, 2026
49216bb
test: add direct cache e2e test suite (#3426)
Pratham-Mishra04 May 12, 2026
4f85b11
test: add semantic cache e2e test suite (#3427)
Pratham-Mishra04 May 12, 2026
a4d0ffa
test: add semantic cache plugin lifecycle tests (#3428)
Pratham-Mishra04 May 12, 2026
3d624d0
feat: add `test-semantic-cache` and `test-semantic-cache-complete` Ma…
Pratham-Mishra04 May 12, 2026
cda4391
harness improvements (#3457)
akshaydeo May 13, 2026
d8da0e9
makefile diff fixes (#3462)
akshaydeo May 13, 2026
17e45f5
Preserve Anthropic output schema refs (#3449)
Javtor May 13, 2026
c66bc56
feat: use the new parameter json schema compliant to json schema spec…
BearTS May 14, 2026
b794482
feat: replace log delete button with actions dropdown menu and pin ac…
impoiler May 14, 2026
8ed6606
fix: constrain model catalog table column widths and truncate overflo…
impoiler May 14, 2026
803e1b5
fix: constrain provider keys table column widths and truncate long ke…
impoiler May 14, 2026
2d63fcb
feat: replace inline edit/delete buttons with dropdown menu in model …
impoiler May 14, 2026
b5e2200
feat: replace routing rule action buttons with dropdown menu (#3484)
impoiler May 14, 2026
c098839
feat: replace inline edit/delete buttons with dropdown menu in pricin…
impoiler May 14, 2026
8ecca79
feat: replace inline action buttons with dropdown menu and pin action…
impoiler May 14, 2026
267f0e9
feat: replace inline action buttons with pinned dropdown menus and ad…
impoiler May 14, 2026
d7f5132
chore: `/ui` code formatting (#3494)
impoiler May 14, 2026
df50f36
send last n messages helm upgrade (#3490)
akshaydeo May 14, 2026
52849a9
fix: wrap Makefile subshell cd commands in parentheses (#3333)
danpiths May 14, 2026
2579242
feat: add Azure realtime provider and nested model normalization (#3334)
danpiths May 14, 2026
736bd7f
feat: enrich realtime routing, logging, cost, and session tracking (#…
danpiths May 14, 2026
db343c3
feat: improve realtime log detail UI with voice, transport, and audio…
danpiths May 14, 2026
ff9601d
fix: max tokens and thinking budget value (#3498)
TejasGhatte May 14, 2026
823bb0d
fix: include blob fields of azure in batch responses (#3469)
TejasGhatte May 14, 2026
2786102
feat: add animated totals/averages to dashboard chart card headers (#…
impoiler May 14, 2026
630eae2
fix: set idle stream timeouts in streaming requests (#3495)
TejasGhatte May 14, 2026
04842b1
feat: add tooltip with full precision values to chart card totals and…
impoiler May 14, 2026
818a58c
fix: trim trailing whitespaces for anthropic and bedrock anthropic pr…
sammaji May 14, 2026
afb6064
harness updates (#3466)
akshaydeo May 14, 2026
d612433
[docs]: docs for patronus ai guardrail provider (#3508)
Madhuvod May 14, 2026
bf8a8fe
feat: add claude skill to validate API docs / openapi schema correctn…
roroghost17 May 14, 2026
66a816e
chore: update openapi files for missing docs on api endpoints (#3410)
roroghost17 May 14, 2026
2384fd5
feat: adds support for custom selection of plugins for otel trace spa…
roroghost17 May 15, 2026
13d4ba5
streaming calls support for hanress (#3507)
akshaydeo May 15, 2026
7ef9a9b
broker mode schema changes (#3509)
akshaydeo May 15, 2026
8a20d41
broker docs (#3515)
akshaydeo May 15, 2026
ad59af1
fix: adds prefill message handling for responses in bedrock (#3517)
sammaji May 15, 2026
bd315bf
feat: updates playwright config to support enterprise ui tests and al…
sammaji May 15, 2026
fc2941b
fix: updates e2e ui tests for virtual keys management (#3460)
sammaji May 15, 2026
98339cd
fix: updates e2e ui tests for provider management (#3463)
sammaji May 15, 2026
6b78c0a
fix: adds e2e tests for mcp headers auth, oauth and per-user oauth (#…
sammaji May 15, 2026
e48cb17
[feat]: use chat completions for openai custom providers that disable…
kevinpdev May 15, 2026
f47850e
fix: allow catalog urls from env
dsherniiazov May 15, 2026
b96accf
Add changelog entry for model catalog URL override
dsherniiazov May 15, 2026
9ceebdd
Merge branch 'dev' into fix/3238-custom-model-parameters
dsherniiazov May 15, 2026
1d80b08
test: update union type test to verify `parametersJsonSchema` passthr…
BearTS May 15, 2026
199a020
feat: add Bedrock Mantle inference engine support for `gpt-oss` model…
BearTS May 15, 2026
171c9a7
fix: broaden Red Hat registry allowlist from `registry.access.redhat.…
BearTS May 15, 2026
e74655d
fix: dont pass multipart request bodies in enrich error (#3524)
TejasGhatte May 15, 2026
76f37d2
fix: send missing bedrock lifecycle events (#3527)
TejasGhatte May 15, 2026
d9a76a3
fix: bedrock stop reason (#3506)
TejasGhatte May 15, 2026
ad7e37c
handle ctx cancel before handling read errors in streaming (#3522)
akshaydeo May 15, 2026
3061821
test case fixes (#3525)
akshaydeo May 15, 2026
685aed8
remove budget level calendar alignemnt (#3434)
akshaydeo May 15, 2026
34ad812
fix: fixes calendar_aligned migration and UI for VK (#3452)
roroghost17 May 15, 2026
8142ae6
feat: implements calendar align feature at team level (#3476)
roroghost17 May 15, 2026
d2a19bf
feat: bedrock system tools (#3435)
TejasGhatte May 15, 2026
8b3a47f
[fix]: openai provider - add usage to completed event in responses to…
kevinpdev May 15, 2026
7fb22fc
codeeditor changes (#3529)
akshaydeo May 15, 2026
c4517e9
fix: preserve OpenAI responses stream metadata (#3528)
etnperlong May 15, 2026
4f33dd8
[fix]: add missing padding to provider api structure form (#3513)
d3lm May 15, 2026
9ff81e4
fix: address model catalog URL review comments
dsherniiazov May 15, 2026
6f1d08a
fix: guard semantic cache `Cleanup` with `sync.Once` to prevent doubl…
Pratham-Mishra04 May 15, 2026
d5c26cf
Merge branch 'dev' into fix/3238-custom-model-parameters
dsherniiazov May 15, 2026
dc73564
feat: add granular RBAC checks for API keys, inference, metrics, and …
impoiler May 8, 2026
69555e6
fix: hide delete log button instead of disabling it when user lacks d…
impoiler May 8, 2026
e250398
feat: add `MCPLogs` RBAC resource and enforce access control on MCP l…
impoiler May 8, 2026
9b62156
fix: replace unsafe inline jsonb cast with `bifrost_safe_jsonb` PL/pg…
impoiler May 12, 2026
2c6bd6d
feat: add required headers input to prompt playground settings panel …
impoiler May 12, 2026
0c13600
fix: skip pagination clamp for virtual keys export requests (#3416)
impoiler May 12, 2026
6caffa5
chore: bump `@maximhq/bifrost` to v1.6.3 (#3417)
impoiler May 12, 2026
8c37ed1
feat: add volume histogram chart to MCP logs page and fix drag-select…
impoiler May 12, 2026
5b54832
refactor: semantic cache plugin (#3210)
Pratham-Mishra04 May 12, 2026
fe6eea8
feat: remove `cleanup_on_shutdown` from semantic cache plugin config …
Pratham-Mishra04 May 12, 2026
a532cf7
refactor: semantic cache ui revamp (#3331)
Pratham-Mishra04 May 12, 2026
8216bd0
fix: resolve cache plugin at request time to support post-boot loads …
Pratham-Mishra04 May 12, 2026
7df5e38
fix: decouple cache telemetry from write decision and guard no-op sea…
Pratham-Mishra04 May 12, 2026
8e4684a
test: add semantic cache e2e test suite skeleton (#3425)
Pratham-Mishra04 May 12, 2026
b71899d
test: add direct cache e2e test suite (#3426)
Pratham-Mishra04 May 12, 2026
8f8e108
test: add semantic cache e2e test suite (#3427)
Pratham-Mishra04 May 12, 2026
335be6a
test: add semantic cache plugin lifecycle tests (#3428)
Pratham-Mishra04 May 12, 2026
f9cfe36
feat: add `test-semantic-cache` and `test-semantic-cache-complete` Ma…
Pratham-Mishra04 May 12, 2026
06eb289
harness improvements (#3457)
akshaydeo May 13, 2026
4fccacb
makefile diff fixes (#3462)
akshaydeo May 13, 2026
c4a01bc
Preserve Anthropic output schema refs (#3449)
Javtor May 13, 2026
c3cb27a
feat: use the new parameter json schema compliant to json schema spec…
BearTS May 14, 2026
9b98959
feat: replace log delete button with actions dropdown menu and pin ac…
impoiler May 14, 2026
fd1f6a5
fix: constrain model catalog table column widths and truncate overflo…
impoiler May 14, 2026
ca77d2a
fix: constrain provider keys table column widths and truncate long ke…
impoiler May 14, 2026
be8c682
feat: replace inline edit/delete buttons with dropdown menu in model …
impoiler May 14, 2026
a393ff9
feat: replace routing rule action buttons with dropdown menu (#3484)
impoiler May 14, 2026
d1f342a
feat: replace inline edit/delete buttons with dropdown menu in pricin…
impoiler May 14, 2026
49ce7c6
feat: replace inline action buttons with dropdown menu and pin action…
impoiler May 14, 2026
f2a270b
feat: replace inline action buttons with pinned dropdown menus and ad…
impoiler May 14, 2026
9a83fde
chore: `/ui` code formatting (#3494)
impoiler May 14, 2026
00cddd2
send last n messages helm upgrade (#3490)
akshaydeo May 14, 2026
b1a7d70
fix: wrap Makefile subshell cd commands in parentheses (#3333)
danpiths May 14, 2026
d9edc3d
feat: add Azure realtime provider and nested model normalization (#3334)
danpiths May 14, 2026
11f11a0
feat: enrich realtime routing, logging, cost, and session tracking (#…
danpiths May 14, 2026
a50c8e9
feat: improve realtime log detail UI with voice, transport, and audio…
danpiths May 14, 2026
23f64ce
fix: max tokens and thinking budget value (#3498)
TejasGhatte May 14, 2026
4837b8c
fix: include blob fields of azure in batch responses (#3469)
TejasGhatte May 14, 2026
63c4654
feat: add animated totals/averages to dashboard chart card headers (#…
impoiler May 14, 2026
08d8f7d
fix: set idle stream timeouts in streaming requests (#3495)
TejasGhatte May 14, 2026
359fb6e
feat: add tooltip with full precision values to chart card totals and…
impoiler May 14, 2026
fff90c2
fix: trim trailing whitespaces for anthropic and bedrock anthropic pr…
sammaji May 14, 2026
8d195db
harness updates (#3466)
akshaydeo May 14, 2026
9a1af9d
[docs]: docs for patronus ai guardrail provider (#3508)
Madhuvod May 14, 2026
4b61b2c
feat: add claude skill to validate API docs / openapi schema correctn…
roroghost17 May 14, 2026
fe0ce57
chore: update openapi files for missing docs on api endpoints (#3410)
roroghost17 May 14, 2026
fedacb2
feat: adds support for custom selection of plugins for otel trace spa…
roroghost17 May 15, 2026
91131be
streaming calls support for hanress (#3507)
akshaydeo May 15, 2026
8726002
broker mode schema changes (#3509)
akshaydeo May 15, 2026
4b4c916
broker docs (#3515)
akshaydeo May 15, 2026
52bc07b
fix: adds prefill message handling for responses in bedrock (#3517)
sammaji May 15, 2026
9460264
feat: updates playwright config to support enterprise ui tests and al…
sammaji May 15, 2026
3c97739
fix: updates e2e ui tests for virtual keys management (#3460)
sammaji May 15, 2026
2b6b680
fix: updates e2e ui tests for provider management (#3463)
sammaji May 15, 2026
65809e4
fix: adds e2e tests for mcp headers auth, oauth and per-user oauth (#…
sammaji May 15, 2026
81197c1
[feat]: use chat completions for openai custom providers that disable…
kevinpdev May 15, 2026
aa26bbc
test: update union type test to verify `parametersJsonSchema` passthr…
BearTS May 15, 2026
5322c8a
feat: add Bedrock Mantle inference engine support for `gpt-oss` model…
BearTS May 15, 2026
ace5b1c
fix: broaden Red Hat registry allowlist from `registry.access.redhat.…
BearTS May 15, 2026
1f39a81
fix: dont pass multipart request bodies in enrich error (#3524)
TejasGhatte May 15, 2026
55c17a0
fix: send missing bedrock lifecycle events (#3527)
TejasGhatte May 15, 2026
e5b8a68
fix: bedrock stop reason (#3506)
TejasGhatte May 15, 2026
abddb6c
handle ctx cancel before handling read errors in streaming (#3522)
akshaydeo May 15, 2026
d507c01
test case fixes (#3525)
akshaydeo May 15, 2026
d051793
remove budget level calendar alignemnt (#3434)
akshaydeo May 15, 2026
07f27b1
fix: fixes calendar_aligned migration and UI for VK (#3452)
roroghost17 May 15, 2026
aa0c652
feat: implements calendar align feature at team level (#3476)
roroghost17 May 15, 2026
d364a7b
feat: bedrock system tools (#3435)
TejasGhatte May 15, 2026
92ad762
[fix]: openai provider - add usage to completed event in responses to…
kevinpdev May 15, 2026
df0effe
codeeditor changes (#3529)
akshaydeo May 15, 2026
fa9acbe
fix: preserve OpenAI responses stream metadata (#3528)
etnperlong May 15, 2026
753c8eb
[fix]: add missing padding to provider api structure form (#3513)
d3lm May 15, 2026
ffa1888
fix: guard semantic cache `Cleanup` with `sync.Once` to prevent doubl…
Pratham-Mishra04 May 15, 2026
46e156f
fix: preserve OpenAI responses stream metadata (#3530)
akshaydeo May 15, 2026
218e73d
fixes alias in migration for team calendar aligned fixes (#3535)
akshaydeo May 15, 2026
18c4207
[image] : crowdstrike transparent logo (#3538)
Madhuvod May 15, 2026
4fdb7c7
sidebar ux improvement when collapsed (#3539)
akshaydeo May 15, 2026
ef7759f
fix(ui): validate OAuth popup messages (#2615)
binbandit May 16, 2026
e588891
adds missing cancel() to integration router (#3541)
akshaydeo May 16, 2026
d4924b1
[docs] : docs for crowdstrike aidr as provider (#3540)
Madhuvod May 16, 2026
91fac3d
Merge branch 'dev' into fix/3238-custom-model-parameters
dsherniiazov May 16, 2026
b218a7a
adds all scim providers in heml chanrt (#3544)
akshaydeo May 17, 2026
fd50409
updated budgets and limits documentation to indicate the multi-node l…
akshaydeo May 17, 2026
cef12d1
add budget and rate-limit dump for budget tracker (#3550)
akshaydeo May 17, 2026
44b56a9
chore(npx): bump @maximhq/bifrost to v1.6.3 (#3340)
impoiler May 17, 2026
89a99f0
migration fix for calendar aligned (#3553)
akshaydeo May 17, 2026
cb3cd32
fix: remove `defaultFilterDataLimit` cap from filter data queries (#3…
impoiler May 18, 2026
811acfc
feat: service tier mappings for gemini and anthropic (#3554)
TejasGhatte May 18, 2026
fd904ac
fix: bedrock chat tool arguments (#3564)
TejasGhatte May 18, 2026
db2552e
fix: emit role chunk from anthropic message start in chat stream (#3575)
TejasGhatte May 18, 2026
80d1828
feat: add `limit` and `query` params to filter data endpoints for ser…
impoiler May 18, 2026
ae35e04
feat: add server-side search to filter sidebar checkbox lists via deb…
impoiler May 18, 2026
bd09f03
feat: add search icon and fetching spinner to filter sidebar search i…
impoiler May 18, 2026
ab42a5e
fix(configstore): improve error message when API key name conflicts a…
SahilChoudhary22 May 18, 2026
30ed554
fix: bedrock mantle fixes (#3566)
TejasGhatte May 18, 2026
4e004af
fix(mcp): remove stale stats from logs list response (#3583)
Vaibhav701161 May 19, 2026
dc20c79
fix(images): passthrough extra params (#3572)
Vaibhav701161 May 19, 2026
a9d0192
feat: add `access_profile_id` to virtual keys for direct access profi…
BearTS May 19, 2026
a78a528
feat: add source_id column and GetTeamBySourceID lookup to governance…
BearTS May 19, 2026
71d8375
fix: add `FullyRedacted()` for proxy passwords and `MarshalForStorage…
BearTS May 19, 2026
721d3a5
dac oss changes (#3198)
akshaydeo May 19, 2026
7ecdba2
feature flags (#3581)
akshaydeo May 19, 2026
654f969
fix: fixes nil pointer deref in stream cancellations (#3582)
roroghost17 May 19, 2026
81c4c7e
feat: replace user ID text input with searchable checkbox list in log…
impoiler May 19, 2026
b600aea
fix: fixes forwarding of reasoning content while conversion of Respon…
roroghost17 May 19, 2026
4a42d35
fix: set anthropic beta headers in vertex requests headers as well (#…
TejasGhatte May 19, 2026
3a33800
fix: harness test fixes (#3589)
TejasGhatte May 19, 2026
d3d9f21
fix the race condition for remote stream close on context cancel (#3591)
akshaydeo May 19, 2026
c25f5da
feat: add cluster-aware log metadata and per-node usage aggregation (…
danpiths May 19, 2026
b00555c
clustering docs image fixes (#3593)
akshaydeo May 19, 2026
82ad1db
fix: core test fixes (#3594)
TejasGhatte May 19, 2026
eef1ffa
[docs] : docs for forwarding headers to grayswan (#3601)
Madhuvod May 19, 2026
607dd80
Merge branch 'dev' into fix/3238-custom-model-parameters
dsherniiazov May 19, 2026
6f32c34
Merge upstream dev into custom model parameters fix
dsherniiazov May 20, 2026
1a3ce06
test: isolate pricing URL env fallback cases
dsherniiazov May 20, 2026
7f5b84e
Merge branch 'dev' into fix/3238-custom-model-parameters
dsherniiazov May 21, 2026
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
19 changes: 19 additions & 0 deletions framework/modelcatalog/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package modelcatalog

import (
"os"
"strings"
"time"
)

Expand All @@ -18,10 +20,27 @@ const (
ConfigLastParamsSyncKey = "LastModelParametersSync"
DefaultPricingURL = "https://getbifrost.ai/datasheet"
DefaultModelParametersURL = "https://getbifrost.ai/datasheet/model-parameters"
PricingURLEnvVar = "BIFROST_PRICING_URL"
ModelParametersURLEnvVar = "BIFROST_MODEL_PARAMETERS_URL"
DefaultPricingTimeout = 45 * time.Second
DefaultModelParametersTimeout = 45 * time.Second
)

func defaultURLWithEnv(defaultURL, envVar string) string {
if value := strings.TrimSpace(os.Getenv(envVar)); value != "" {
return value
}
return defaultURL
}

func defaultPricingURL() string {
return defaultURLWithEnv(DefaultPricingURL, PricingURLEnvVar)
}

func defaultModelParametersURL() string {
return defaultURLWithEnv(DefaultModelParametersURL, ModelParametersURLEnvVar)
}

// Config is the model pricing configuration.
type Config struct {
PricingURL *string `json:"pricing_url,omitempty"`
Expand Down
51 changes: 51 additions & 0 deletions framework/modelcatalog/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package modelcatalog

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"sync/atomic"
"testing"
)

func TestDefaultURLWithEnv(t *testing.T) {
t.Setenv(PricingURLEnvVar, " https://internal.example/datasheet ")
if got := defaultPricingURL(); got != "https://internal.example/datasheet" {
t.Fatalf("expected env pricing URL, got %q", got)
}

t.Setenv(ModelParametersURLEnvVar, "")
if got := defaultModelParametersURL(); got != DefaultModelParametersURL {
t.Fatalf("expected default model parameters URL, got %q", got)
}
}

func TestLoadModelParametersFromURLUsesConfiguredURL(t *testing.T) {
var requested atomic.Bool
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requested.Store(true)
_ = json.NewEncoder(w).Encode(map[string]any{
"test-model": map[string]any{
"max_output_tokens": 4096,
},
})
}))
defer server.Close()

mc := &ModelCatalog{
modelParametersURL: server.URL,
logger: noOpLogger{},
}

params, err := mc.loadModelParametersFromURL(context.Background())
if err != nil {
t.Fatalf("expected model parameters load to succeed, got %v", err)
}
if !requested.Load() {
t.Fatal("expected configured URL to be requested")
}
if _, ok := params["test-model"]; !ok {
t.Fatal("expected test model parameters to be loaded")
}
}
9 changes: 4 additions & 5 deletions framework/modelcatalog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ type ModelCatalog struct {
// Init initializes the model catalog
func Init(ctx context.Context, config *Config, configStore configstore.ConfigStore, logger schemas.Logger) (*ModelCatalog, error) {
// Initialize pricing URL and sync interval
pricingURL := DefaultPricingURL
pricingURL := defaultPricingURL()
if config.PricingURL != nil {
pricingURL = *config.PricingURL
}
modelParametersURL := DefaultModelParametersURL
modelParametersURL := defaultModelParametersURL()
if config.ModelParametersURL != nil && *config.ModelParametersURL != "" {
modelParametersURL = *config.ModelParametersURL
}
Expand Down Expand Up @@ -273,12 +273,11 @@ func (mc *ModelCatalog) UpdateSyncConfig(ctx context.Context, config *Config) er
}

// Update pricing configuration
mc.pricingURL = DefaultPricingURL
mc.pricingURL = defaultPricingURL()
if config.PricingURL != nil {
mc.pricingURL = *config.PricingURL
}

mc.modelParametersURL = DefaultModelParametersURL
mc.modelParametersURL = defaultModelParametersURL()
if config.ModelParametersURL != nil && *config.ModelParametersURL != "" {
mc.modelParametersURL = *config.ModelParametersURL
}
Expand Down
29 changes: 25 additions & 4 deletions transports/bifrost-http/lib/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2997,7 +2997,13 @@ func ResolveFrameworkPricingConfig(
fileConfig *framework.FrameworkConfig,
) (*configstoreTables.TableFrameworkConfig, *modelcatalog.Config, bool) {
defaultPricingURL := modelcatalog.DefaultPricingURL
if value := strings.TrimSpace(os.Getenv(modelcatalog.PricingURLEnvVar)); value != "" {
defaultPricingURL = value
}
defaultModelParametersURL := modelcatalog.DefaultModelParametersURL
if value := strings.TrimSpace(os.Getenv(modelcatalog.ModelParametersURLEnvVar)); value != "" {
defaultModelParametersURL = value
}
Comment on lines 3003 to +3006
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Env-backed URL overrides become sticky after the first DB backfill.

BIFROST_PRICING_URL / BIFROST_MODEL_PARAMETERS_URL are only folded into the default layer here, and the resolved values are then persisted. After the first boot with either env var set, a later redeploy with a different env value keeps using the stale DB row because Phase 3 still lets dbConfig.* win. That defeats the deployment-level override this PR is adding for Docker/Helm/air-gapped installs.

Please either avoid persisting env-derived defaults, or treat a current env override that differs from the stored row as a refresh condition before applying DB precedence.

Also applies to: 3119-3138, 3177-3197

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@transports/bifrost-http/lib/config.go` around lines 3003 - 3006, The code
sets defaultModelParametersURL from modelcatalog.DefaultModelParametersURL and
then overrides it with the env var (modelcatalog.ModelParametersURLEnvVar) and
later persists that resolved value into the DB, which makes env-backed overrides
"sticky" across redeploys because dbConfig.* wins in Phase 3; change the logic
so env-derived values are not persisted as the canonical DB default or are
treated as a refresh: either (A) keep env overrides only in-memory and do not
write them into the persisted defaults, or (B) when loading persisted dbConfig.*
compare the current env value (modelcatalog.ModelParametersURLEnvVar and the
analogous BIFROST_PRICING env var) to the stored value and, if they differ,
treat that as a refresh condition that replaces the DB value before Phase 3
precedence is applied; update the code paths that compute
defaultModelParametersURL and the similar blocks (lines around the other two
occurrences) to implement one of these approaches so Docker/Helm env overrides
are honored on redeploy.

defaultSyncSeconds := int64(modelcatalog.DefaultSyncInterval.Seconds())

filePricingURL := (*string)(nil)
Expand Down Expand Up @@ -3081,9 +3087,19 @@ func ResolveFrameworkPricingConfig(
configID := uint(0)

// Hash the file-resolved values; skip if nothing valid survived Phase 1.
hashPricingURL := filePricingURL
if skipURLBackfill {
hashPricingURL = nil
}
hashModelParametersURL := fileModelParametersURL
if skipModelParamsURLBackfill {
hashModelParametersURL = nil
}

fileHash := ""
if fileConfig != nil && fileConfig.Pricing != nil && !skipURLBackfill && (filePricingURL != nil || fileSyncSeconds != nil) {
h, err := configstore.GenerateFrameworkConfigHash(filePricingURL, fileModelParametersURL, fileSyncSeconds)
if fileConfig != nil && fileConfig.Pricing != nil &&
(hashPricingURL != nil || hashModelParametersURL != nil || fileSyncSeconds != nil) {
h, err := configstore.GenerateFrameworkConfigHash(hashPricingURL, hashModelParametersURL, fileSyncSeconds)
if err != nil {
logger.Warn("failed to compute framework config hash: %v", err)
} else {
Expand All @@ -3101,7 +3117,7 @@ func ResolveFrameworkPricingConfig(
configID = dbConfig.ID

if dbConfig.PricingURL != nil {
if fileChanged && filePricingURL != nil {
if fileChanged && filePricingURL != nil && !skipURLBackfill {
logger.Info("pricing_url from config.json overrides DB (file hash changed) — updating DB")
needsDBUpdate = true
} else {
Expand All @@ -3111,7 +3127,12 @@ func ResolveFrameworkPricingConfig(
needsDBUpdate = true
}
if dbConfig.ModelParametersURL != nil && *dbConfig.ModelParametersURL != "" {
resolvedModelParametersURL = dbConfig.ModelParametersURL
if fileChanged && fileModelParametersURL != nil && !skipModelParamsURLBackfill {
logger.Info("model_parameters_url from config.json overrides DB (file hash changed) — updating DB")
needsDBUpdate = true
} else {
resolvedModelParametersURL = dbConfig.ModelParametersURL
}
} else if !skipModelParamsURLBackfill {
needsDBUpdate = true
}
Expand Down
151 changes: 150 additions & 1 deletion transports/bifrost-http/lib/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,14 @@ func (m *MockConfigStore) Ping(ctx context.Context) error { retu
func (m *MockConfigStore) EncryptPlaintextRows(ctx context.Context) error { return nil }
func (m *MockConfigStore) Close(ctx context.Context) error { return nil }
func (m *MockConfigStore) DB() *gorm.DB { return nil }
func (m *MockConfigStore) ScopedDB(ctx context.Context) *gorm.DB { return nil }
func (m *MockConfigStore) ExecuteTransaction(ctx context.Context, fn func(tx *gorm.DB) error) error {
return fn(nil)
}

func (m *MockConfigStore) ScopedDB(ctx context.Context) *gorm.DB {
return m.DB()
}

func (m *MockConfigStore) GetOauthConfigByID(ctx context.Context, id string) (*tables.TableOauthConfig, error) {
return nil, nil
}
Expand Down Expand Up @@ -16238,6 +16241,121 @@ func TestResolveFrameworkPricingConfig(t *testing.T) {
require.Equal(t, newFileSyncSeconds, *normalizedModelCatalog.PricingSyncInterval)
})

t.Run("file model parameters url overrides db when file changes after ui edit", func(t *testing.T) {
storedHash, err := configstore.GenerateFrameworkConfigHash(nil, &defaultModelParamsURL, nil)
require.NoError(t, err)
uiEditedModelParamsURL := "https://ui-edited.example.com/model-parameters.json"
dbConfig := &tables.TableFrameworkConfig{
ID: 10,
PricingURL: &dbURL,
ModelParametersURL: &uiEditedModelParamsURL,
PricingSyncInterval: &dbSyncSeconds,
ConfigHash: storedHash,
}
newFileModelParamsURL := "https://new-file.example.com/model-parameters.json"
fileConfig := &framework.FrameworkConfig{
Pricing: &modelcatalog.Config{
ModelParametersURL: &newFileModelParamsURL,
},
}

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(dbConfig, fileConfig)
require.True(t, needsDBUpdate)
require.Equal(t, uint(10), normalizedTable.ID)
require.Equal(t, dbURL, *normalizedTable.PricingURL)
require.Equal(t, newFileModelParamsURL, *normalizedTable.ModelParametersURL)
require.Equal(t, dbSyncSeconds, *normalizedTable.PricingSyncInterval)
require.Equal(t, dbURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, newFileModelParamsURL, *normalizedModelCatalog.ModelParametersURL)
require.Equal(t, dbSyncSeconds, *normalizedModelCatalog.PricingSyncInterval)
require.NotEqual(t, storedHash, normalizedTable.ConfigHash)
})

t.Run("unresolved model parameters env does not block pricing file change", func(t *testing.T) {
oldFileURL := "https://old-file.example.com/pricing.json"
missingModelParamsEnv := "env.BIFROST_TEST_MODEL_PARAMS_URL_NONEXISTENT_XYZ"
storedHash, err := configstore.GenerateFrameworkConfigHash(&oldFileURL, &missingModelParamsEnv, nil)
require.NoError(t, err)
prev, existed := os.LookupEnv("BIFROST_TEST_MODEL_PARAMS_URL_NONEXISTENT_XYZ")
os.Unsetenv("BIFROST_TEST_MODEL_PARAMS_URL_NONEXISTENT_XYZ")
t.Cleanup(func() {
if existed {
os.Setenv("BIFROST_TEST_MODEL_PARAMS_URL_NONEXISTENT_XYZ", prev)
}
})

dbModelParamsURL := "https://db.example.com/model-parameters.json"
dbConfig := &tables.TableFrameworkConfig{
ID: 11,
PricingURL: &dbURL,
ModelParametersURL: &dbModelParamsURL,
PricingSyncInterval: &dbSyncSeconds,
ConfigHash: storedHash,
}
newFileURL := "https://new-file.example.com/pricing.json"
fileConfig := &framework.FrameworkConfig{
Pricing: &modelcatalog.Config{
PricingURL: &newFileURL,
ModelParametersURL: &missingModelParamsEnv,
},
}

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(dbConfig, fileConfig)
require.True(t, needsDBUpdate)
require.Equal(t, uint(11), normalizedTable.ID)
require.Equal(t, newFileURL, *normalizedTable.PricingURL)
require.Equal(t, dbModelParamsURL, *normalizedTable.ModelParametersURL)
require.Equal(t, dbSyncSeconds, *normalizedTable.PricingSyncInterval)
require.Equal(t, newFileURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, dbModelParamsURL, *normalizedModelCatalog.ModelParametersURL)
require.Equal(t, dbSyncSeconds, *normalizedModelCatalog.PricingSyncInterval)
require.NotEqual(t, storedHash, normalizedTable.ConfigHash)
})

t.Run("unresolved pricing env does not block other file changes", func(t *testing.T) {
missingPricingEnv := "env.BIFROST_TEST_PRICING_URL_NONEXISTENT_XYZ"
oldModelParamsURL := "https://old-file.example.com/model-parameters.json"
oldSyncSeconds := int64((12 * time.Hour).Seconds())
storedHash, err := configstore.GenerateFrameworkConfigHash(&missingPricingEnv, &oldModelParamsURL, &oldSyncSeconds)
require.NoError(t, err)
prev, existed := os.LookupEnv("BIFROST_TEST_PRICING_URL_NONEXISTENT_XYZ")
os.Unsetenv("BIFROST_TEST_PRICING_URL_NONEXISTENT_XYZ")
t.Cleanup(func() {
if existed {
os.Setenv("BIFROST_TEST_PRICING_URL_NONEXISTENT_XYZ", prev)
}
})

dbModelParamsURL := "https://db.example.com/model-parameters.json"
dbConfig := &tables.TableFrameworkConfig{
ID: 12,
PricingURL: &dbURL,
ModelParametersURL: &dbModelParamsURL,
PricingSyncInterval: &dbSyncSeconds,
ConfigHash: storedHash,
}
newModelParamsURL := "https://new-file.example.com/model-parameters.json"
newSyncSeconds := int64((48 * time.Hour).Seconds())
fileConfig := &framework.FrameworkConfig{
Pricing: &modelcatalog.Config{
PricingURL: &missingPricingEnv,
ModelParametersURL: &newModelParamsURL,
PricingSyncInterval: &newSyncSeconds,
},
}

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(dbConfig, fileConfig)
require.True(t, needsDBUpdate)
require.Equal(t, uint(12), normalizedTable.ID)
require.Equal(t, dbURL, *normalizedTable.PricingURL)
require.Equal(t, newModelParamsURL, *normalizedTable.ModelParametersURL)
require.Equal(t, newSyncSeconds, *normalizedTable.PricingSyncInterval)
require.Equal(t, dbURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, newModelParamsURL, *normalizedModelCatalog.ModelParametersURL)
require.Equal(t, newSyncSeconds, *normalizedModelCatalog.PricingSyncInterval)
require.NotEqual(t, storedHash, normalizedTable.ConfigHash)
})

t.Run("fallback to file when db fields are missing", func(t *testing.T) {
dbConfig := &tables.TableFrameworkConfig{
ID: 3,
Expand All @@ -16261,14 +16379,45 @@ func TestResolveFrameworkPricingConfig(t *testing.T) {
})

t.Run("fallback to defaults when db and file are missing", func(t *testing.T) {
t.Setenv(modelcatalog.PricingURLEnvVar, "")
t.Setenv(modelcatalog.ModelParametersURLEnvVar, "")

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(nil, nil)
require.False(t, needsDBUpdate)
require.Equal(t, defaultURL, *normalizedTable.PricingURL)
require.Equal(t, defaultModelParamsURL, *normalizedTable.ModelParametersURL)
require.Equal(t, defaultSyncSeconds, *normalizedTable.PricingSyncInterval)
require.Equal(t, defaultURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, defaultModelParamsURL, *normalizedModelCatalog.ModelParametersURL)
require.Equal(t, defaultSyncSeconds, *normalizedModelCatalog.PricingSyncInterval)
})

t.Run("fallback default pricing url uses env override", func(t *testing.T) {
envURL := "https://env-default.example.com/pricing.json"
t.Setenv(modelcatalog.PricingURLEnvVar, envURL)
t.Setenv(modelcatalog.ModelParametersURLEnvVar, "")

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(nil, nil)
require.False(t, needsDBUpdate)
require.Equal(t, envURL, *normalizedTable.PricingURL)
require.Equal(t, defaultModelParamsURL, *normalizedTable.ModelParametersURL)
require.Equal(t, envURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, defaultModelParamsURL, *normalizedModelCatalog.ModelParametersURL)
})

t.Run("fallback default model parameters url uses env override", func(t *testing.T) {
envURL := "https://env-default.example.com/model-parameters.json"
t.Setenv(modelcatalog.PricingURLEnvVar, "")
t.Setenv(modelcatalog.ModelParametersURLEnvVar, envURL)

normalizedTable, normalizedModelCatalog, needsDBUpdate := ResolveFrameworkPricingConfig(nil, nil)
require.False(t, needsDBUpdate)
require.Equal(t, defaultURL, *normalizedTable.PricingURL)
require.Equal(t, envURL, *normalizedTable.ModelParametersURL)
require.Equal(t, defaultURL, *normalizedModelCatalog.PricingURL)
require.Equal(t, envURL, *normalizedModelCatalog.ModelParametersURL)
})

t.Run("invalid db interval (zero) falls back and requests db update", func(t *testing.T) {
invalidDBSync := int64(0)
dbConfig := &tables.TableFrameworkConfig{
Expand Down
Loading