Skip to content

feat: removes enable_litellm_fallback option for more granular settings#2260

Closed
sammaji wants to merge 1 commit into03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_levelfrom
03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings
Closed

feat: removes enable_litellm_fallback option for more granular settings#2260
sammaji wants to merge 1 commit into03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_levelfrom
03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings

Conversation

@sammaji
Copy link
Copy Markdown
Member

@sammaji sammaji commented Mar 24, 2026

Summary

Replaces the single enable_litellm_fallbacks boolean configuration with three granular compat plugin feature flags: convert_text_to_chat, convert_chat_to_responses, and should_drop_params. This provides more fine-grained control over LiteLLM compatibility features.

Changes

  • Configuration Structure: Replaced enable_litellm_fallbacks with a compat object containing three boolean flags
  • Database Migration: Added migration to convert existing enable_litellm_fallbacks values to the new compat_convert_text_to_chat column
  • Plugin Logic: Updated compat plugin to check individual feature flags instead of a single enabled flag
  • UI Updates: Replaced single toggle with expandable accordion containing three separate switches for each compat feature
  • Documentation: Updated OpenAPI specs and feature documentation to reflect the new configuration structure
  • Helm Charts: Updated values schema and templates to support the new nested compat configuration

The migration preserves existing behavior by setting convert_text_to_chat = true only when the original enable_litellm_fallbacks was true.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Validate the configuration changes and UI updates:

# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

# Test migration
# Start with old config containing enable_litellm_fallbacks: true
# Verify it migrates to compat.convert_text_to_chat: true

# Test new configuration format
curl -X PUT /api/config \
  -H "Content-Type: application/json" \
  -d '{
    "client_config": {
      "compat": {
        "convert_text_to_chat": true,
        "convert_chat_to_responses": false,
        "should_drop_params": true
      }
    }
  }'

Screenshots/Recordings

The UI now shows an expandable "LiteLLM Compat" section with three individual toggles instead of a single "Enable LiteLLM Fallbacks" switch.

Breaking changes

  • Yes
  • No

Migration Required: Existing configurations using enable_litellm_fallbacks need to be updated to use the new compat object structure. The database migration handles this automatically, but JSON configurations and Helm values need manual updates.

Before:

{
  "client_config": {
    "enable_litellm_fallbacks": true
  }
}

After:

{
  "client_config": {
    "compat": {
      "convert_text_to_chat": true,
      "convert_chat_to_responses": false,
      "should_drop_params": false
    }
  }
}

Related issues

Improves granular control over LiteLLM compatibility features as requested in feature discussions.

Security considerations

No security implications - this is a configuration structure change that maintains the same plugin functionality with more granular control.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 24, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 37fea4ce-8cfc-4869-8d4b-c5748a7da8a7

📥 Commits

Reviewing files that changed from the base of the PR and between 05c065e and c4b8a62.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • framework/modelcatalog/main.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Four granular LiteLLM-compat toggles: convert text→chat, convert chat→responses, drop unsupported params, and convert unsupported parameter values (IsEnabled when any set).
  • Configuration Changes

    • Single fallback flag replaced by a structured client.compat object; parameter-conversion defaults to enabled.
  • UI

    • Client settings: "LiteLLM Compat" accordion with four individual toggles and updated change detection.
  • Documentation

    • Docs and API schemas updated with new compat object, conversion flows, metadata, and examples.

Walkthrough

Replaces the single boolean enable_litellm_fallbacks with a structured compat object of four flags (convert_text_to_chat, convert_chat_to_responses, should_drop_params, should_convert_params), updating configs, schemas, DB migrations/persistence, plugin logic, server handlers, UI/types, docs, tests, and removing many ModelCatalog methods.

Changes

Cohort / File(s) Summary
Config examples & fixtures
\.github/workflows/configs/.../config.json, examples/configs/.../config.json, examples/dockers/data/config.json, tests/governance/config.json, tests/integrations/python/config.json, tests/integrations/typescript/config.json
Removed client.enable_litellm_fallbacks; added/expect client.compat where applicable (four flags, should_convert_params default true in some fixtures).
CI scripts & validation
.github/workflows/scripts/run-migration-tests.sh, .github/workflows/scripts/test-docker-image.sh, .github/workflows/scripts/validate-helm-config-fields.sh
Updated generated config/SQL/assertions to drop legacy field and use new compat columns/fields; faker seed adjusted to include new compat columns.
Config types & hashing
framework/configstore/clientconfig.go, framework/configstore/tables/clientconfig.go
Added exported CompatConfig (4 booleans); replaced EnableLiteLLMFallbacks with Compat in ClientConfig; updated config-hash generation to incorporate compat flags.
DB migrations & persistence
framework/configstore/migrations.go, framework/configstore/rdb.go
Added migration to add four compat_* columns, backfill from enable_litellm_fallbacks, set compat_should_convert_params = TRUE, then drop legacy column; rdb read/write updated to persist/restore compat columns.
Transport/server & plugin lifecycle
transports/bifrost-http/handlers/config.go, transports/bifrost-http/lib/config.go, transports/bifrost-http/server/plugins.go, transports/config.schema.json
Handlers compare/persist ClientConfig.Compat; plugin reload/remove now constructed from individual compat flags and returns 400 on reload/remove failures; default client config now sets Compat.ShouldConvertParams=true; schema updated.
Compat plugin behavior
plugins/compat/main.go
Plugin Config expanded to four flags and IsEnabled() added; conversion, param-dropping, and param-conversion are gated by respective flags and modelCatalog presence.
Frontend types & UI
ui/lib/types/config.ts, ui/app/workspace/config/views/clientSettingsView.tsx, ui/components/ui/accordion.tsx
Added CompatConfig type and updated CoreConfig/defaults; replaced single toggle with “LiteLLM Compat” accordion exposing four switches and updated change detection/handlers; minor alignment tweak.
Schemas, Helm & templates
docs/openapi/openapi.json, docs/openapi/schemas/management/config.yaml, helm-charts/bifrost/values.schema.json, helm-charts/bifrost/values.yaml, helm-charts/bifrost/templates/_helpers.tpl
OpenAPI/schema and Helm values/templates replace enable_litellm_fallbacks with compat object (four properties; shouldConvertParams default true); Helm helper conditionally builds client.compat.
Documentation & provider notes
docs/features/litellm-compat.mdx, docs/providers/supported-providers/overview.mdx
Docs expanded with chat→responses conversion, param-dropping semantics, updated config schema/examples and flowcharts; metadata semantics updated.
Tests, go.mod & miscellaneous
transports/bifrost-http/lib/config_test.go, transports/go.mod, various test fixtures
Tests updated for compat-based hashing/parity and defaults; go.mod had local replace removed and a duplicate require entry added (needs attention).
Large internal change
framework/modelcatalog/main.go
Removed many exported ModelCatalog methods (pricing, capability lookups, model/provider queries, routing helpers, upsert/delete/override methods); large deletion requiring careful review.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Frontend UI
  participant API as ConfigHandler (Server)
  participant DB as ConfigStore (DB)
  participant Plugin as CompatPluginManager
  UI->>API: PATCH /config (payload.client.compat)
  API->>API: compare payload.ClientConfig.Compat vs currentConfig.Compat
  alt compat changed
    API->>DB: persist updated ClientConfig.Compat
    DB-->>API: ACK
    API->>Plugin: if any flag true -> load/reload with compat.Config; else -> remove plugin
    Plugin-->>API: success / error
    API-->>UI: 200 OK or 400 error ("Failed to load/remove compat plugin")
  else no compat change
    API-->>UI: 200 OK (no plugin action)
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐰 I nudged one toggle into four,
Flags that open many a door.
Text to chat, chat to responses too,
Params that drop or transform true.
A little rabbit applauds the new.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: replacing a single boolean configuration with three granular settings for better control over LiteLLM compatibility features.
Description check ✅ Passed The description comprehensively covers the purpose, changes, affected areas, testing instructions, breaking changes with migration guidance, and includes all checklist items marked complete.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Member Author

sammaji commented Mar 24, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@sammaji sammaji mentioned this pull request Mar 24, 2026
11 tasks
@sammaji sammaji marked this pull request as ready for review March 24, 2026 12:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/features/litellm-compat.mdx (1)

9-9: ⚠️ Potential issue | 🟡 Minor

Documentation inconsistency: mentions "two transformations" but three compat flags are now available.

Line 9 states "two transformations" but the new compat configuration (lines 66-69 and 79-83) exposes three flags. The document body also lacks descriptions for convert_chat_to_responses and should_drop_params transformations beyond the brief toggle descriptions in the UI section.

Consider updating the intro to reflect all three options and adding sections describing the other two transformations (or clarifying if some are not strictly "transformations").

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` at line 9, Intro line claims "two
transformations" but the plugin exposes three compat flags; update the docs to
reflect all three options and add descriptions for the missing transformations.
In the LiteLLM compatibility plugin docs update the sentence to mention three
transformations/flags and add short sections explaining
convert_chat_to_responses and should_drop_params (in addition to the existing
convert_responses_to_chat), include where these flags are shown in the UI, and
clarify if any flag is not a true "transformation" vs. a toggle for behavior to
remove ambiguity.
🧹 Nitpick comments (5)
.github/workflows/scripts/validate-helm-config-fields.sh (1)

206-208: Add a negative assertion for the removed Helm key.

These checks prove the new client.compat.* fields render, but they still pass if the chart accidentally emits the removed client.enable_litellm_fallbacks alongside them. Since this rename is a breaking change, one absence check here would close that gap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/scripts/validate-helm-config-fields.sh around lines 206 -
208, Add a negative assertion that verifies the removed Helm key is not present:
call the existing absence-check helper (e.g., assert_field_absent) for
'client.enable_litellm_fallbacks' with the jq path
'.client.enable_litellm_fallbacks' so the test not only validates the new
'client.compat.*' fields but also fails if the old key is still emitted.
helm-charts/bifrost/templates/_helpers.tpl (1)

230-242: Minor: Empty compat object may be set if parent key exists but no sub-keys are defined.

If a user specifies bifrost.client.compat: {} (empty object) in their Helm values, the template will still set an empty compat object in the generated config. This differs from other similar blocks in this file (e.g., headerFilterConfig at lines 255-266) which check if the object has content before setting it.

If an empty compat object is acceptable to the downstream config parser, this is fine. Otherwise, consider guarding the set:

♻️ Optional: Only set compat if it has content
 {{- if .Values.bifrost.client.compat }}
 {{- $compat := dict }}
 {{- if hasKey .Values.bifrost.client.compat "convertTextToChat" }}
 {{- $_ := set $compat "convert_text_to_chat" .Values.bifrost.client.compat.convertTextToChat }}
 {{- end }}
 {{- if hasKey .Values.bifrost.client.compat "convertChatToResponses" }}
 {{- $_ := set $compat "convert_chat_to_responses" .Values.bifrost.client.compat.convertChatToResponses }}
 {{- end }}
 {{- if hasKey .Values.bifrost.client.compat "shouldDropParams" }}
 {{- $_ := set $compat "should_drop_params" .Values.bifrost.client.compat.shouldDropParams }}
 {{- end }}
+{{- if $compat }}
 {{- $_ := set $client "compat" $compat }}
+{{- end }}
 {{- end }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@helm-charts/bifrost/templates/_helpers.tpl` around lines 230 - 242, The
template currently always sets an empty $compat object when
.Values.bifrost.client.compat exists even if it has no sub-keys; update the
logic around $compat (the block creating $compat and the final set $client
"compat" $compat) to only call set $client "compat" $compat when $compat
contains at least one key (e.g., by checking length or presence of any handled
sub-keys after the hasKey checks) so an empty compat object is not emitted into
the generated config.
docs/openapi/openapi.json (1)

132105-132112: Define explicit defaults (and close object shape) for compat flags.

At Line [132109]–Line [132111], the new booleans are optional without defaults. Adding default: false and additionalProperties: false makes client behavior deterministic and prevents typoed keys from being silently accepted.

Proposed diff
 "compat": {
   "type": "object",
   "description": "Compat plugin configuration",
+  "additionalProperties": false,
   "properties": {
-    "convert_text_to_chat": { "type": "boolean", "description": "Convert text completion requests to chat" },
-    "convert_chat_to_responses": { "type": "boolean", "description": "Convert chat completion requests to responses" },
-    "should_drop_params": { "type": "boolean", "description": "Drop unsupported parameters based on model catalog" }
+    "convert_text_to_chat": { "type": "boolean", "default": false, "description": "Convert text completion requests to chat" },
+    "convert_chat_to_responses": { "type": "boolean", "default": false, "description": "Convert chat completion requests to responses" },
+    "should_drop_params": { "type": "boolean", "default": false, "description": "Drop unsupported parameters based on model catalog" }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/openapi/openapi.json` around lines 132105 - 132112, The compat object
schema currently defines optional boolean flags (convert_text_to_chat,
convert_chat_to_responses, should_drop_params) without defaults or closed shape;
update the compat schema (the "compat" object) to set default: false for each of
these boolean properties and add "additionalProperties": false to the compat
object so unrecognized keys are rejected and clients get deterministic false
defaults.
helm-charts/bifrost/values.yaml (1)

191-194: Consider adding an inline migration hint for chart upgraders.

A short comment near Line 191 that enableLitellmFallbacks was replaced by client.compat.* would make manual values migration easier.

Suggested comment-only patch
     compat:
+      # Replaces deprecated client.enableLitellmFallbacks
       convertTextToChat: false
       convertChatToResponses: false
       shouldDropParams: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@helm-charts/bifrost/values.yaml` around lines 191 - 194, Add a short inline
comment above the compat block explaining that the previous
enableLitellmFallbacks flag was replaced by the new client.compat.* keys
(convertTextToChat, convertChatToResponses, shouldDropParams) so upgraders know
to map their old setting to these three booleans; update the comment near the
compat stanza (adjacent to compat.convertTextToChat / convertChatToResponses /
shouldDropParams) to explicitly state the migration mapping and intent.
transports/bifrost-http/lib/config_test.go (1)

12425-12430: Exercise every compat flag with a non-default hash/parity case.

Right now the suite only proves ConvertTextToChat changes the hash, and the runtime-vs-migration parity path still round-trips all three compat columns as false. A regression that drops ConvertChatToResponses or ShouldDropParams from hashing or DB persistence would still pass. Please add table-driven cases that flip each compat flag to true and assert both hash changes and SQLite parity.

Also applies to: 13389-13389, 13408-13408

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/lib/config_test.go` around lines 12425 - 12430, The
test currently only flips Compat.ConvertTextToChat; update the test around
cc1/cc13 and GenerateClientConfigHash to exercise every Compat flag: create a
table-driven list of the compat boolean fields (ConvertTextToChat,
ConvertChatToResponses, ShouldDropParams), iterate and for each make a copy of
cc1, set that field to true, call GenerateClientConfigHash() and assert the hash
differs from the original, then write/read via the same SQLite parity path used
elsewhere in this test to assert the stored/restored Compat field round-trips
correctly; reference the cc1 variable, the Compat struct fields,
GenerateClientConfigHash, and the existing SQLite parity assertions when adding
these cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/scripts/run-migration-tests.sh:
- Around line 525-526: The INSERT INTO config_client has 25 VALUES for 24
columns (column/value mismatch): in the VALUES tuple for the INSERT in
run-migration-tests.sh there's an extra boolean value inserted before the
numeric max_request_body_size_mb (the stray 'true' between allow_direct_keys and
100). Remove that extra boolean so the VALUES list lines up with the column list
(ensure the sequence matches id, drop_excess_requests, ..., allow_direct_keys,
max_request_body_size_mb, ... , config_hash, created_at, updated_at).

In `@framework/configstore/clientconfig.go`:
- Around line 116-123: migrationReplaceEnableLiteLLMWithCompatColumns currently
adds the three compat columns and copies enable_litellm_fallbacks but does not
recompute the per-row config_hash, leaving stored hashes stale; update
migrationReplaceEnableLiteLLMWithCompatColumns to iterate all rows of the client
config table after adding/migrating the compat columns, recompute the
config_hash the same way migrationAddAdditionalConfigHashColumns and the
provider/virtual key migrations do (load each row, compute the hash including
compatConvertTextToChat, compatConvertChatToResponses, compatShouldDropParams),
and persist the new config_hash values to the DB so loadClientConfig() will
match file hashes and avoid spurious reconciles.

In `@framework/configstore/migrations.go`:
- Around line 5234-5241: After copying enable_litellm_fallbacks into
compat_convert_text_to_chat, recompute and persist the config_hash for the
affected client rows before dropping the legacy column: run the project's
existing config-hash recomputation routine (or an UPDATE that recalculates
config_hash) for rows whose compat_convert_text_to_chat value changed (e.g.,
WHERE compat_convert_text_to_chat = true or matching the rows updated by the
earlier tx.Exec), and do this in the same transaction (using tx) prior to
calling mig.DropColumn on TableClientConfig so reconciliation won't remain
stale.

In `@framework/configstore/rdb.go`:
- Around line 55-57: The compat flags in updatedConfig.Compat are being
unconditionally written to the DB (via UpdateClientConfig()) even when the
request omitted the compat object, causing omitted fields to reset to false;
change the update logic so the handler only assigns/overwrites
CompatConvertTextToChat, CompatConvertChatToResponses, and
CompatShouldDropParams on updatedConfig when the incoming payload explicitly
provided them (e.g., use nullable/pointer fields or an "isSet" flag for the
compat object in the request parsing) similar to how MCPAgentDepth is guarded
(>0), or alternatively document that clients must send the full compat object on
partial updates; ensure UpdateClientConfig() receives the selectively-updated
updatedConfig.Compat values.

In `@transports/go.mod`:
- Line 17: The transports module currently pins
github.com/maximhq/bifrost/plugins/compat v0.0.1 but the published tag doesn't
exist and the local compat API changes (ConvertTextToChat,
ConvertChatToResponses, ShouldDropParams in plugins/compat/main.go) are
unreachable; fix by either restoring the local replacement for the compat module
(add the replace directive pointing to ../plugins/compat), or update the require
to a real published tag that contains those API changes, or add a go.work to
include the local plugins/compat module in the workspace so transports can
resolve ConvertTextToChat, ConvertChatToResponses and ShouldDropParams.

In `@ui/app/workspace/config/views/clientSettingsView.tsx`:
- Around line 333-399: The new LiteLLM Compat controls lack data-testid
attributes which breaks E2E targeting; add data-testid attributes following the
project's pattern to the AccordionTrigger (e.g.,
data-testid="compat-accordion-trigger") and to each Switch for
convert_text_to_chat, convert_chat_to_responses, and should_drop_params (e.g.,
data-testid="compat-convert-text-to-chat-switch",
"compat-convert-chat-to-responses-switch", "compat-should-drop-params-switch")
by adding the attributes to the AccordionTrigger JSX and the three Switch
components (referencing AccordionTrigger and the Switch elements with ids
"compat-convert-text-to-chat", "compat-convert-chat-to-responses", and
"compat-should-drop-params"); ensure naming follows
data-testid="<entity>-<element>-<qualifier>".
- Around line 333-347: The Link with data-testid="litellm-docs-link" must be
moved out of the AccordionTrigger to avoid nesting an anchor inside the trigger
button; update the JSX so AccordionTrigger only contains the title/description
(the block with "LiteLLM Compat") and render the Link as a sibling element
adjacent to AccordionTrigger (preserve its href, target, rel, className and
data-testid), remove or adjust the onClick stopPropagation if no longer needed,
and ensure the surrounding layout/spacing still matches the original design.

---

Outside diff comments:
In `@docs/features/litellm-compat.mdx`:
- Line 9: Intro line claims "two transformations" but the plugin exposes three
compat flags; update the docs to reflect all three options and add descriptions
for the missing transformations. In the LiteLLM compatibility plugin docs update
the sentence to mention three transformations/flags and add short sections
explaining convert_chat_to_responses and should_drop_params (in addition to the
existing convert_responses_to_chat), include where these flags are shown in the
UI, and clarify if any flag is not a true "transformation" vs. a toggle for
behavior to remove ambiguity.

---

Nitpick comments:
In @.github/workflows/scripts/validate-helm-config-fields.sh:
- Around line 206-208: Add a negative assertion that verifies the removed Helm
key is not present: call the existing absence-check helper (e.g.,
assert_field_absent) for 'client.enable_litellm_fallbacks' with the jq path
'.client.enable_litellm_fallbacks' so the test not only validates the new
'client.compat.*' fields but also fails if the old key is still emitted.

In `@docs/openapi/openapi.json`:
- Around line 132105-132112: The compat object schema currently defines optional
boolean flags (convert_text_to_chat, convert_chat_to_responses,
should_drop_params) without defaults or closed shape; update the compat schema
(the "compat" object) to set default: false for each of these boolean properties
and add "additionalProperties": false to the compat object so unrecognized keys
are rejected and clients get deterministic false defaults.

In `@helm-charts/bifrost/templates/_helpers.tpl`:
- Around line 230-242: The template currently always sets an empty $compat
object when .Values.bifrost.client.compat exists even if it has no sub-keys;
update the logic around $compat (the block creating $compat and the final set
$client "compat" $compat) to only call set $client "compat" $compat when $compat
contains at least one key (e.g., by checking length or presence of any handled
sub-keys after the hasKey checks) so an empty compat object is not emitted into
the generated config.

In `@helm-charts/bifrost/values.yaml`:
- Around line 191-194: Add a short inline comment above the compat block
explaining that the previous enableLitellmFallbacks flag was replaced by the new
client.compat.* keys (convertTextToChat, convertChatToResponses,
shouldDropParams) so upgraders know to map their old setting to these three
booleans; update the comment near the compat stanza (adjacent to
compat.convertTextToChat / convertChatToResponses / shouldDropParams) to
explicitly state the migration mapping and intent.

In `@transports/bifrost-http/lib/config_test.go`:
- Around line 12425-12430: The test currently only flips
Compat.ConvertTextToChat; update the test around cc1/cc13 and
GenerateClientConfigHash to exercise every Compat flag: create a table-driven
list of the compat boolean fields (ConvertTextToChat, ConvertChatToResponses,
ShouldDropParams), iterate and for each make a copy of cc1, set that field to
true, call GenerateClientConfigHash() and assert the hash differs from the
original, then write/read via the same SQLite parity path used elsewhere in this
test to assert the stored/restored Compat field round-trips correctly; reference
the cc1 variable, the Compat struct fields, GenerateClientConfigHash, and the
existing SQLite parity assertions when adding these cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb4b3f54-f9b3-42b5-823d-c148deb2adf4

📥 Commits

Reviewing files that changed from the base of the PR and between 07e3cf4 and c12a940.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • examples/configs/withvirtualkeys/config.json
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json

Comment thread .github/workflows/scripts/run-migration-tests.sh Outdated
Comment thread framework/configstore/clientconfig.go
Comment thread framework/configstore/migrations.go
Comment thread framework/configstore/rdb.go
Comment thread transports/go.mod Outdated
Comment thread ui/app/workspace/config/views/clientSettingsView.tsx
Comment thread ui/app/workspace/config/views/clientSettingsView.tsx
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from c12a940 to 4a9d345 Compare March 24, 2026 16:05
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from 07e3cf4 to d286969 Compare March 24, 2026 16:05
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
.github/workflows/scripts/run-migration-tests.sh (1)

525-526: ⚠️ Potential issue | 🔴 Critical

Fix config_client INSERT column/value mismatch (stray legacy boolean).

Line 526 currently has 25 values for 24 columns. The extra true after allow_direct_keys shifts subsequent fields and makes the SQL invalid.

🛠️ Proposed fix
-VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, true, 100, 10, 30, 'server', 10, false, false, false, 'client-config-hash-001', $now, $now)
+VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, 100, 10, 30, 'server', 10, false, false, false, 'client-config-hash-001', $now, $now)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/scripts/run-migration-tests.sh around lines 525 - 526, The
INSERT into table config_client has 24 columns but 25 VALUES (a stray legacy
boolean `true` after `allow_direct_keys`) causing a column/value mismatch; fix
by removing that extra boolean from the VALUES list so each value aligns with
its corresponding column (ensure the sequence matches columns like
allow_direct_keys, max_request_body_size_mb, mcp_agent_depth, ... and ends with
config_hash, created_at, updated_at), or alternatively if that boolean is
actually a needed column, add the missing column name to the column list instead
of the extra value.
framework/configstore/migrations.go (1)

338-340: ⚠️ Potential issue | 🟠 Major

Recompute config_hash when backfilling compat state.

Because triggerMigrations schedules this migration after the earlier client-config hash backfill, rows upgraded from enable_litellm_fallbacks = true get compat_convert_text_to_chat = true here but keep a pre-compat config_hash. That can leave config reconciliation stale until a later write. Please refresh the hash in the same transaction before dropping the legacy column.

Also applies to: 5234-5241

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 338 - 340, In
migrationReplaceEnableLiteLLMWithCompatColumns, after updating rows to set
compat_convert_text_to_chat = true for legacy enable_litellm_fallbacks but
before dropping the legacy column, recompute and update the config_hash for
those affected rows within the same transaction (use the same ctx and db/tx used
by migrationReplaceEnableLiteLLMWithCompatColumns) so the hashed config reflects
the new compat fields; ensure the config_hash update targets the same row
selection logic used for the backfill and runs prior to removing the legacy
column to avoid stale reconciliation.
ui/app/workspace/config/views/clientSettingsView.tsx (2)

333-399: ⚠️ Potential issue | 🟡 Minor

Add data-testid to the new compat interactive controls

At Line 333 and Line 361-399, the new trigger and switches are interactive but missing data-testid, which violates the UI testing selector convention for newly added controls.

🔧 Suggested fix
-						<AccordionTrigger className="py-0 hover:no-underline">
+						<AccordionTrigger className="py-0 hover:no-underline" data-testid="compat-settings-trigger">
...
 								<Switch
+									data-testid="compat-convert-text-to-chat-switch"
 									id="compat-convert-text-to-chat"
...
 								<Switch
+									data-testid="compat-convert-chat-to-responses-switch"
 									id="compat-convert-chat-to-responses"
...
 								<Switch
+									data-testid="compat-should-drop-params-switch"
 									id="compat-should-drop-params"

As per coding guidelines, ui/**/*.{tsx,ts}: Add new interactive UI elements with data-testid attributes following the pattern: data-testid="<entity>-<element>-<qualifier>".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 333 - 399,
The new LiteLLM Compat interactive elements (AccordionTrigger and the three
Switches in clientSettingsView.tsx) are missing data-testid attributes; add
data-testid values following the pattern "<entity>-<element>-<qualifier>" to the
AccordionTrigger and each Switch (references: AccordionTrigger element
containing the "LiteLLM Compat" label, and the Switch components with ids
"compat-convert-text-to-chat", "compat-convert-chat-to-responses", and
"compat-should-drop-params") so the trigger and each interactive Switch have
unique testids for UI tests.

333-347: ⚠️ Potential issue | 🟠 Major

Don’t nest the docs link inside AccordionTrigger

At Line 333-347, AccordionTrigger is interactive and contains a nested interactive Link. This breaks HTML/a11y semantics; stopPropagation() doesn’t fully fix keyboard/screen-reader behavior.

🔧 Suggested fix
-					<AccordionTrigger className="py-0 hover:no-underline">
-						<div className="space-y-0.5 text-left">
-							<span className="text-sm font-medium">LiteLLM Compat</span>
-							<p className="text-muted-foreground text-sm font-normal">
-								Request type conversion and parameter dropping.{" "}
-								<Link
-									className="text-primary cursor-pointer underline"
-									href="https://docs.getbifrost.ai/features/litellm-compat"
-									target="_blank"
-									rel="noopener noreferrer"
-									data-testid="litellm-docs-link"
-									onClick={(e) => e.stopPropagation()}
-								>
-									Learn more
-								</Link>
-							</p>
-						</div>
-					</AccordionTrigger>
+					<div className="flex items-start justify-between gap-3">
+						<AccordionTrigger className="py-0 hover:no-underline">
+							<div className="space-y-0.5 text-left">
+								<span className="text-sm font-medium">LiteLLM Compat</span>
+								<p className="text-muted-foreground text-sm font-normal">
+									Request type conversion and parameter dropping.
+								</p>
+							</div>
+						</AccordionTrigger>
+						<Link
+							className="text-primary cursor-pointer underline"
+							href="https://docs.getbifrost.ai/features/litellm-compat"
+							target="_blank"
+							rel="noopener noreferrer"
+							data-testid="litellm-docs-link"
+						>
+							Learn more
+						</Link>
+					</div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 333 - 347,
AccordionTrigger currently nests an interactive Link (the <Link ...
data-testid="litellm-docs-link">) which breaks accessibility; move the docs Link
out of the AccordionTrigger and render it as a sibling (for example inside the
AccordionContent or immediately after AccordionTrigger) so the trigger contains
only non-interactive content (title/summary). Remove the stopPropagation()
handler from the Link and ensure the same href/attributes (target, rel,
data-testid) are preserved when relocated; update any styling or container
markup so visual layout and tests remain the same while restoring correct
keyboard/screen-reader behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@transports/bifrost-http/handlers/config.go`:
- Around line 344-362: When applying compat changes in the handler, fail the
whole update if the plugin mutation fails instead of only logging: after calling
h.configManager.ReloadPlugin(ctx, compat.PluginName, ..., compatCfg, ..., ...)
or h.configManager.RemovePlugin(disabledCtx, compat.PluginName) check the
returned error and propagate it (return the error from the handler) so
updatedConfig.Compat is not persisted on failure; reference the
newCompat/oldCompat comparison block, the calls to ReloadPlugin and
RemovePlugin, and the updatedConfig.Compat assignment to locate where to bail
out and return the error when plugin reload/remove fails.

In `@ui/app/workspace/config/views/clientSettingsView.tsx`:
- Around line 111-113: The equality checks for compat flags
(convert_text_to_chat, convert_chat_to_responses, should_drop_params) on
localConfig vs config can treat undefined and false as different, causing
hasCoreConfigChanges to stay true; normalize these optional flags before
comparing by coalescing undefined to false (or a consistent default) when
evaluating the comparisons used to compute hasCoreConfigChanges (references:
localConfig.compat, config.compat, and the hasCoreConfigChanges calculation in
clientSettingsView.tsx) so toggling back to the implicit backend default no
longer registers as a change.

---

Duplicate comments:
In @.github/workflows/scripts/run-migration-tests.sh:
- Around line 525-526: The INSERT into table config_client has 24 columns but 25
VALUES (a stray legacy boolean `true` after `allow_direct_keys`) causing a
column/value mismatch; fix by removing that extra boolean from the VALUES list
so each value aligns with its corresponding column (ensure the sequence matches
columns like allow_direct_keys, max_request_body_size_mb, mcp_agent_depth, ...
and ends with config_hash, created_at, updated_at), or alternatively if that
boolean is actually a needed column, add the missing column name to the column
list instead of the extra value.

In `@framework/configstore/migrations.go`:
- Around line 338-340: In migrationReplaceEnableLiteLLMWithCompatColumns, after
updating rows to set compat_convert_text_to_chat = true for legacy
enable_litellm_fallbacks but before dropping the legacy column, recompute and
update the config_hash for those affected rows within the same transaction (use
the same ctx and db/tx used by migrationReplaceEnableLiteLLMWithCompatColumns)
so the hashed config reflects the new compat fields; ensure the config_hash
update targets the same row selection logic used for the backfill and runs prior
to removing the legacy column to avoid stale reconciliation.

In `@ui/app/workspace/config/views/clientSettingsView.tsx`:
- Around line 333-399: The new LiteLLM Compat interactive elements
(AccordionTrigger and the three Switches in clientSettingsView.tsx) are missing
data-testid attributes; add data-testid values following the pattern
"<entity>-<element>-<qualifier>" to the AccordionTrigger and each Switch
(references: AccordionTrigger element containing the "LiteLLM Compat" label, and
the Switch components with ids "compat-convert-text-to-chat",
"compat-convert-chat-to-responses", and "compat-should-drop-params") so the
trigger and each interactive Switch have unique testids for UI tests.
- Around line 333-347: AccordionTrigger currently nests an interactive Link (the
<Link ... data-testid="litellm-docs-link">) which breaks accessibility; move the
docs Link out of the AccordionTrigger and render it as a sibling (for example
inside the AccordionContent or immediately after AccordionTrigger) so the
trigger contains only non-interactive content (title/summary). Remove the
stopPropagation() handler from the Link and ensure the same href/attributes
(target, rel, data-testid) are preserved when relocated; update any styling or
container markup so visual layout and tests remain the same while restoring
correct keyboard/screen-reader behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6527bd2c-6341-4756-992c-76fd2fa432df

📥 Commits

Reviewing files that changed from the base of the PR and between c12a940 and 4a9d345.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (7)
  • examples/configs/withprompushgateway/config.json
  • plugins/compat/version
  • .github/workflows/scripts/test-docker-image.sh
  • docs/providers/supported-providers/overview.mdx
  • ui/components/ui/accordion.tsx
  • examples/dockers/data/config.json
  • helm-charts/bifrost/values.schema.json
🚧 Files skipped from review as they are similar to previous changes (15)
  • transports/bifrost-http/server/plugins.go
  • tests/governance/config.json
  • tests/integrations/typescript/config.json
  • transports/go.mod
  • docs/openapi/openapi.json
  • docs/features/litellm-compat.mdx
  • docs/openapi/schemas/management/config.yaml
  • helm-charts/bifrost/values.yaml
  • transports/config.schema.json
  • transports/bifrost-http/lib/config.go
  • framework/configstore/rdb.go
  • ui/lib/types/config.ts
  • tests/integrations/python/config.json
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/lib/config_test.go

Comment thread transports/bifrost-http/handlers/config.go
Comment thread ui/app/workspace/config/views/clientSettingsView.tsx Outdated
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 4a9d345 to fd76fc6 Compare March 24, 2026 17:41
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from d286969 to 7057a7a Compare March 24, 2026 17:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
.github/workflows/scripts/run-migration-tests.sh (1)

525-526: ⚠️ Potential issue | 🔴 Critical

Fix config_client INSERT arity/ordering mismatch (extra value).

Line 526 has one extra boolean (true) after allow_direct_keys, producing 25 values for 24 columns and shifting all subsequent assignments.

🛠️ Proposed fix
-VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, true, 100, 10, 30, 'server', 10, false, false, false, 'client-config-hash-001', $now, $now)
+VALUES (1, false, '["provider", "model"]', '["*"]', '["Authorization"]', '{}', 300, true, false, false, 365, true, false, 100, 10, 30, 'server', 10, false, false, false, 'client-config-hash-001', $now, $now)
#!/bin/bash
set -euo pipefail

FILE=".github/workflows/scripts/run-migration-tests.sh"

python3 - <<'PY'
import re, pathlib

p = pathlib.Path(".github/workflows/scripts/run-migration-tests.sh")
txt = p.read_text()

m = re.search(r"INSERT INTO config_client \((.*?)\)\s*VALUES \((.*?)\)\s*ON CONFLICT DO NOTHING;", txt, re.S)
if not m:
    raise SystemExit("config_client INSERT not found")

cols_raw = m.group(1)
vals_raw = m.group(2)

cols = [c.strip() for c in cols_raw.split(",")]

vals = []
buf = []
in_str = False
i = 0
while i < len(vals_raw):
    ch = vals_raw[i]
    if ch == "'" and (i == 0 or vals_raw[i-1] != "\\"):
        in_str = not in_str
        buf.append(ch)
    elif ch == "," and not in_str:
        vals.append("".join(buf).strip())
        buf = []
    else:
        buf.append(ch)
    i += 1
if buf:
    vals.append("".join(buf).strip())

print(f"columns={len(cols)}")
print(f"values={len(vals)}")
for idx, (c, v) in enumerate(zip(cols, vals), 1):
    print(f"{idx:02d}. {c} <= {v}")

if len(cols) != len(vals):
    print("MISMATCH: column/value count differs")
    raise SystemExit(1)
PY

As per coding guidelines, “always check the stack if there is one for the current PR…”, this seed mismatch should be fixed to keep stacked migration validation trustworthy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/scripts/run-migration-tests.sh around lines 525 - 526, The
INSERT INTO config_client statement has one extra boolean value after
allow_direct_keys causing a 25-value vs 24-column mismatch; edit the VALUES
tuple in the INSERT INTO config_client (...) VALUES (...) statement to remove
the redundant boolean (the extra true after allow_direct_keys) so the number and
ordering of values exactly matches the column list (refer to the INSERT INTO
config_client and the allow_direct_keys column name to locate the row), then run
the provided sanity script to confirm columns.count == values.count.
framework/configstore/migrations.go (1)

5234-5241: ⚠️ Potential issue | 🟠 Major

Refresh config_hash in the compat backfill.

The update at Line 5236 changes persisted client-config state, but this migration still drops the legacy column without recalculating config_hash. Existing installs can stay on the pre-compat hash shape and keep reconciliation dirty until some later write fixes it. Recompute the hash in the same transaction before Line 5239.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 5234 - 5241, The migration
updates compat_convert_text_to_chat from enable_litellm_fallbacks but never
recomputes config_hash, leaving reconciler dirty; modify the transaction (within
the same block where mig.HasColumn(&tables.TableClientConfig{},
"enable_litellm_fallbacks") and after tx.Exec("UPDATE config_client SET
compat_convert_text_to_chat = enable_litellm_fallbacks")) to recalculate and
update config_hash for affected rows (e.g., run an UPDATE that sets config_hash
= <recompute logic> or call the existing hash computation routine) before
calling mig.DropColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks");
ensure you reference the same tx and table (config_client / TableClientConfig)
so the drop happens only after hashes are refreshed.
transports/bifrost-http/handlers/config.go (1)

344-362: ⚠️ Potential issue | 🟠 Major

Fail the request when the compat plugin update fails.

If ReloadPlugin or RemovePlugin errors here, the handler still falls through to updatedConfig.Compat = newCompat and can later persist/return success. In this stack, client_config.compat is now the source of truth, so that leaves stored/UI state out of sync with the actual compat behavior.

Proposed fix
 	if newCompat != oldCompat {
 		newEnabled := newCompat.ConvertTextToChat || newCompat.ConvertChatToResponses || newCompat.ShouldDropParams
 		if newEnabled {
 			compatCfg := &compat.Config{
 				ConvertTextToChat:      newCompat.ConvertTextToChat,
 				ConvertChatToResponses: newCompat.ConvertChatToResponses,
 				ShouldDropParams:       newCompat.ShouldDropParams,
 			}
 			if err := h.configManager.ReloadPlugin(ctx, compat.PluginName, nil, compatCfg, nil, nil); err != nil {
-				logger.Warn(fmt.Sprintf("failed to load compat plugin: %v", err))
+				logger.Warn("failed to load compat plugin: %v", err)
+				SendError(ctx, fasthttp.StatusInternalServerError, fmt.Sprintf("failed to load compat plugin: %v", err))
+				return
 			}
 		} else {
 			disabledCtx := context.WithValue(ctx, PluginDisabledKey, true)
 			if err := h.configManager.RemovePlugin(disabledCtx, compat.PluginName); err != nil {
 				logger.Warn("failed to remove compat plugin: %v", err)
+				SendError(ctx, fasthttp.StatusInternalServerError, fmt.Sprintf("failed to remove compat plugin: %v", err))
+				return
 			}
 		}
 	}
 	updatedConfig.Compat = newCompat
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/handlers/config.go` around lines 344 - 362, The
handler currently ignores errors from h.configManager.ReloadPlugin and
RemovePlugin and proceeds to set updatedConfig.Compat, causing stored/UI state
to diverge from runtime plugin state; change both error branches so that on
error you log and return the error (or a wrapped fmt.Errorf) to abort the
request instead of falling through, and only set updatedConfig.Compat =
newCompat after the plugin operation succeeds; target the blocks around
h.configManager.ReloadPlugin and h.configManager.RemovePlugin and ensure any
context'ed RemovePlugin call also returns its error to the caller.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/migrations.go`:
- Around line 759-762: The rollback SQL uses PostgreSQL-only "ALTER TABLE ...
DROP COLUMN IF EXISTS" which breaks SQLite; update the Rollback closure in the
migration (the Rollback func using tx.WithContext(ctx)) to detect the dialect
via tx.Dialector.Name() and execute a dialect-appropriate statement: for
"postgres" use "ALTER TABLE config_client DROP COLUMN IF EXISTS
enable_litellm_fallbacks" and for "sqlite" use "ALTER TABLE config_client DROP
COLUMN enable_litellm_fallbacks"; ensure the chosen SQL is executed via tx.Exec
and errors are returned as before.

In `@helm-charts/bifrost/values.schema.json`:
- Around line 296-302: The compat object in values.schema.json currently defines
properties convertTextToChat, convertChatToResponses, and shouldDropParams but
allows unknown keys; add "additionalProperties": false to the "compat" schema so
nested unknown or snake_case keys (e.g., convert_text_to_chat) will be rejected;
update the compat object schema (the block with "properties": {
"convertTextToChat", "convertChatToResponses", "shouldDropParams" }) to include
"additionalProperties": false to enforce strict validation.

---

Duplicate comments:
In @.github/workflows/scripts/run-migration-tests.sh:
- Around line 525-526: The INSERT INTO config_client statement has one extra
boolean value after allow_direct_keys causing a 25-value vs 24-column mismatch;
edit the VALUES tuple in the INSERT INTO config_client (...) VALUES (...)
statement to remove the redundant boolean (the extra true after
allow_direct_keys) so the number and ordering of values exactly matches the
column list (refer to the INSERT INTO config_client and the allow_direct_keys
column name to locate the row), then run the provided sanity script to confirm
columns.count == values.count.

In `@framework/configstore/migrations.go`:
- Around line 5234-5241: The migration updates compat_convert_text_to_chat from
enable_litellm_fallbacks but never recomputes config_hash, leaving reconciler
dirty; modify the transaction (within the same block where
mig.HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") and after
tx.Exec("UPDATE config_client SET compat_convert_text_to_chat =
enable_litellm_fallbacks")) to recalculate and update config_hash for affected
rows (e.g., run an UPDATE that sets config_hash = <recompute logic> or call the
existing hash computation routine) before calling
mig.DropColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks"); ensure
you reference the same tx and table (config_client / TableClientConfig) so the
drop happens only after hashes are refreshed.

In `@transports/bifrost-http/handlers/config.go`:
- Around line 344-362: The handler currently ignores errors from
h.configManager.ReloadPlugin and RemovePlugin and proceeds to set
updatedConfig.Compat, causing stored/UI state to diverge from runtime plugin
state; change both error branches so that on error you log and return the error
(or a wrapped fmt.Errorf) to abort the request instead of falling through, and
only set updatedConfig.Compat = newCompat after the plugin operation succeeds;
target the blocks around h.configManager.ReloadPlugin and
h.configManager.RemovePlugin and ensure any context'ed RemovePlugin call also
returns its error to the caller.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: df21bc17-4668-4905-85e7-73197bffc688

📥 Commits

Reviewing files that changed from the base of the PR and between 4a9d345 and fd76fc6.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (5)
  • plugins/compat/version
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withprompushgateway/config.json
  • docs/openapi/openapi.json
  • framework/configstore/clientconfig.go
🚧 Files skipped from review as they are similar to previous changes (18)
  • tests/governance/config.json
  • tests/integrations/typescript/config.json
  • .github/workflows/scripts/test-docker-image.sh
  • examples/dockers/data/config.json
  • ui/components/ui/accordion.tsx
  • transports/bifrost-http/server/plugins.go
  • transports/go.mod
  • docs/features/litellm-compat.mdx
  • docs/openapi/schemas/management/config.yaml
  • transports/bifrost-http/lib/config.go
  • framework/configstore/tables/clientconfig.go
  • framework/configstore/rdb.go
  • transports/config.schema.json
  • plugins/compat/main.go
  • ui/lib/types/config.ts
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • tests/integrations/python/config.json
  • transports/bifrost-http/lib/config_test.go

Comment thread framework/configstore/migrations.go
Comment thread helm-charts/bifrost/values.schema.json
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from 7057a7a to df3d2b2 Compare March 24, 2026 18:40
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from fd76fc6 to 905602b Compare March 24, 2026 18:40
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/features/litellm-compat.mdx (1)

9-13: ⚠️ Potential issue | 🟡 Minor

Documentation inconsistency: claims "two transformations" but only one is listed.

Line 9 states the plugin provides "two transformations" but only one item follows (Text-to-Chat Conversion). This doesn't align with the three config flags now documented in lines 67-69 and 79-83 (convert_text_to_chat, convert_chat_to_responses, should_drop_params).

Consider updating to reflect all three features, or clarify which are "transformations" vs. other behaviors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` around lines 9 - 13, The doc header
incorrectly says "two transformations" while the plugin actually exposes three
behaviors; update the prose to enumerate/clarify all three features —
convert_text_to_chat, convert_chat_to_responses, and should_drop_params — and
distinguish which are true "transformations" (e.g., text-to-chat and
chat-to-responses) versus other behaviors (e.g., dropping params), and mention
that responses include extra_fields.litellm_compat: true when any are applied.
♻️ Duplicate comments (4)
ui/app/workspace/config/views/clientSettingsView.tsx (3)

111-113: ⚠️ Potential issue | 🟡 Minor

Normalize compat flags to avoid sticky dirty-state.

Comparing optional values directly means undefined !== false registers as a change. When the backend baseline is undefined but UI state becomes explicit false after toggling back, hasCoreConfigChanges stays true incorrectly.

🔧 Suggested fix
-			localConfig.compat?.convert_text_to_chat !== config.compat?.convert_text_to_chat ||
-			localConfig.compat?.convert_chat_to_responses !== config.compat?.convert_chat_to_responses ||
-			localConfig.compat?.should_drop_params !== config.compat?.should_drop_params ||
+			(localConfig.compat?.convert_text_to_chat ?? false) !== (config.compat?.convert_text_to_chat ?? false) ||
+			(localConfig.compat?.convert_chat_to_responses ?? false) !== (config.compat?.convert_chat_to_responses ?? false) ||
+			(localConfig.compat?.should_drop_params ?? false) !== (config.compat?.should_drop_params ?? false) ||

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 111 - 113,
The comparison logic for compat flags (e.g.,
localConfig.compat?.convert_text_to_chat, convert_chat_to_responses,
should_drop_params) treats undefined and false as different, causing sticky
dirty state; fix by normalizing these optional flags before comparing (use a
default like false via nullish-coalescing or explicit boolean cast) so the check
(used by hasCoreConfigChanges or similar) compares normalized boolean values on
both sides (e.g., (localConfig.compat?.convert_text_to_chat ?? false) !==
(config.compat?.convert_text_to_chat ?? false)) for each compat property.

333-350: ⚠️ Potential issue | 🟠 Major

Move the docs link outside the accordion trigger.

The Link is nested inside AccordionTrigger, which renders as a <button>. Nesting an interactive element (anchor) inside another interactive element violates HTML semantics. The stopPropagation() only prevents click bubbling but doesn't fix keyboard navigation or screen reader accessibility.

🔧 Suggested restructure
-						<AccordionTrigger className="py-0 hover:no-underline">
-							<div className="space-y-0.5 text-left">
-								<span className="text-sm font-medium">LiteLLM Compat</span>
-								<p className="text-muted-foreground text-sm font-normal">
-									Request type conversion and parameter dropping.{" "}
-									<Link
-										className="text-primary cursor-pointer underline"
-										href="https://docs.getbifrost.ai/features/litellm-compat"
-										target="_blank"
-										rel="noopener noreferrer"
-										data-testid="litellm-docs-link"
-										onClick={(e) => e.stopPropagation()}
-									>
-										Learn more
-									</Link>
-								</p>
-							</div>
-						</AccordionTrigger>
+						<div className="flex items-center justify-between">
+							<AccordionTrigger className="py-0 hover:no-underline" data-testid="compat-settings-trigger">
+								<div className="space-y-0.5 text-left">
+									<span className="text-sm font-medium">LiteLLM Compat</span>
+									<p className="text-muted-foreground text-sm font-normal">
+										Request type conversion and parameter dropping.
+									</p>
+								</div>
+							</AccordionTrigger>
+							<Link
+								className="text-primary cursor-pointer underline text-sm"
+								href="https://docs.getbifrost.ai/features/litellm-compat"
+								target="_blank"
+								rel="noopener noreferrer"
+								data-testid="litellm-docs-link"
+							>
+								Learn more
+							</Link>
+						</div>

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 333 - 350,
The Link (data-testid="litellm-docs-link") is nested inside AccordionTrigger
(which renders a <button>), causing nested interactive elements; move the Link
out of AccordionTrigger so it is not a descendant of AccordionTrigger (e.g.,
render the Link immediately after AccordionTrigger or inside AccordionContent),
remove the now-unnecessary onClick={(e) => e.stopPropagation()} on the Link, and
keep the href/target/rel/data-testid props intact so the docs link remains
functional and accessible while AccordionTrigger remains a single interactive
element.

361-399: ⚠️ Potential issue | 🟡 Minor

Add data-testid attributes to the new compat switches.

The three new Switch components lack data-testid attributes, making them difficult to target in E2E tests.

🏷️ Suggested additions
 								<Switch
+									data-testid="compat-convert-text-to-chat-switch"
 									id="compat-convert-text-to-chat"
 									size="md"
 ...
 								<Switch
+									data-testid="compat-convert-chat-to-responses-switch"
 									id="compat-convert-chat-to-responses"
 									size="md"
 ...
 								<Switch
+									data-testid="compat-should-drop-params-switch"
 									id="compat-should-drop-params"
 									size="md"

As per coding guidelines: ui/**/*.{tsx,ts}: Add new interactive UI elements with data-testid attributes following the pattern: data-testid="<entity>-<element>-<qualifier>".

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 361 - 399,
Add data-testid attributes to the three new Switch components in
clientSettingsView.tsx so E2E tests can target them; for each Switch with id
"compat-convert-text-to-chat", "compat-convert-chat-to-responses", and
"compat-should-drop-params" add a data-testid following the project pattern
(e.g., data-testid="compat-switch-convert-text-to-chat",
"compat-switch-convert-chat-to-responses", and
"compat-switch-should-drop-params") ensuring the attribute is placed on the
Switch element so tests can reliably select the interactive control.
framework/configstore/migrations.go (1)

5234-5241: ⚠️ Potential issue | 🟠 Major

Refresh config_hash in this migration.

Earlier in this migration chain config_hash may already be populated, but this UPDATE changes the persisted client-config shape afterwards. Recompute and persist the hash for the affected config_client rows in the same transaction before DropColumn, otherwise reconciliation stays stale until a later write.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 5234 - 5241, The migration
updates compat_convert_text_to_chat from enable_litellm_fallbacks then drops
that column but doesn't refresh the derived config_hash; update the migration
to, after running tx.Exec("UPDATE config_client SET compat_convert_text_to_chat
= enable_litellm_fallbacks") and before calling
mig.DropColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks"),
recompute and persist the config_hash for the affected config_client rows within
the same transaction (use the same tx and target rows in config_client),
ensuring the new hash is saved so reconciliation isn't stale; reference the
existing mig.HasColumn, tx.Exec, tables.TableClientConfig,
compat_convert_text_to_chat, enable_litellm_fallbacks, and config_hash when
locating where to add the hash recompute and update logic.
🧹 Nitpick comments (2)
plugins/compat/main.go (1)

114-124: Avoid silent no-op when should_drop_params is enabled but model catalog is nil.

Right now this path quietly skips work. A debug/warn log will make misconfiguration obvious in production.

Suggested change
-	// Compute unsupported parameters to drop based on model catalog allowlist
-	if p.config.ShouldDropParams && p.modelCatalog != nil {
-		_, model, _ := req.GetRequestFields()
-		if model != "" {
-			if supportedParams := p.modelCatalog.GetSupportedParameters(model); supportedParams != nil {
-				droppedParams := computeUnsupportedParams(req, supportedParams)
-				if len(droppedParams) > 0 {
-					ctx.SetValue(schemas.BifrostContextKeyCompatPluginDroppedParams, droppedParams)
-				}
-			}
-		}
-	}
+	// Compute unsupported parameters to drop based on model catalog allowlist
+	if p.config.ShouldDropParams {
+		if p.modelCatalog == nil {
+			p.logger.Debug("compat: should_drop_params enabled but model catalog is nil; skipping unsupported-parameter dropping")
+		} else {
+			_, model, _ := req.GetRequestFields()
+			if model != "" {
+				if supportedParams := p.modelCatalog.GetSupportedParameters(model); supportedParams != nil {
+					droppedParams := computeUnsupportedParams(req, supportedParams)
+					if len(droppedParams) > 0 {
+						ctx.SetValue(schemas.BifrostContextKeyCompatPluginDroppedParams, droppedParams)
+					}
+				}
+			}
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/compat/main.go` around lines 114 - 124, When
p.config.ShouldDropParams is true but p.modelCatalog is nil, the current branch
silently does nothing; add a warning or debug log to surface this
misconfiguration. Inside the existing if p.config.ShouldDropParams &&
p.modelCatalog != nil conditional flow, add an else branch (for when
p.modelCatalog == nil) that logs a clear message via the package logger (or ctx
logger) indicating ShouldDropParams is enabled but modelCatalog is missing,
referencing the plugin instance and model name context as appropriate (use
symbols p.config.ShouldDropParams, p.modelCatalog, computeUnsupportedParams,
ctx.SetValue, schemas.BifrostContextKeyCompatPluginDroppedParams to locate the
code). Ensure the log level is warning or debug so it’s visible in production
without changing behavior.
transports/bifrost-http/lib/config_test.go (1)

12425-12430: Expand hash coverage to all new compat fields.

Line 12427 currently validates hash sensitivity for only Compat.ConvertTextToChat. Add checks for Compat.ConvertChatToResponses and Compat.ShouldDropParams too, so each new flag is explicitly guarded.

🔧 Suggested test expansion
 	// Different Compat should produce different hash
 	cc13 := cc1
 	cc13.Compat.ConvertTextToChat = true
 	hash13, _ := cc13.GenerateClientConfigHash()
 	if hash1 == hash13 {
 		t.Error("Different Compat.ConvertTextToChat should produce different hash")
 	}
+
+	cc13b := cc1
+	cc13b.Compat.ConvertChatToResponses = true
+	hash13b, _ := cc13b.GenerateClientConfigHash()
+	if hash1 == hash13b {
+		t.Error("Different Compat.ConvertChatToResponses should produce different hash")
+	}
+
+	cc13c := cc1
+	cc13c.Compat.ShouldDropParams = true
+	hash13c, _ := cc13c.GenerateClientConfigHash()
+	if hash1 == hash13c {
+		t.Error("Different Compat.ShouldDropParams should produce different hash")
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/lib/config_test.go` around lines 12425 - 12430, The
test only checks hash sensitivity for Compat.ConvertTextToChat; update the test
around cc13/cc1 and GenerateClientConfigHash to also mutate and assert
uniqueness for Compat.ConvertChatToResponses and Compat.ShouldDropParams: create
separate copies (e.g., cc13, cc14, cc15) from cc1, flip each flag on Compat
(ConvertTextToChat, ConvertChatToResponses, ShouldDropParams) one at a time,
call GenerateClientConfigHash for each copy (hash13, hash14, hash15), and add
assertions that each new hash is not equal to the original hash1 to ensure the
hash changes for all new compat fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/features/litellm-compat.mdx`:
- Around line 66-69: Update the docs for LiteLLM Compat to describe all three UI
features (not just Text-to-Chat): change the intro wording that currently says
"two transformations" to "three transformations", add a new "Convert Chat to
Responses" section mirroring the Text-to-Chat pattern that explains what it
does, when to use it, detailed request->response transformation behavior, and
supported provider combinations, and add a "Drop Unsupported Params" section
that explains what parameters get removed, when to enable it, exact
request/response effects, and supported provider combinations; finally, extend
the "Transformations Reference" to include entries for both Convert Chat to
Responses and Drop Unsupported Params with the same level of detail as the
existing Text-to-Chat reference.

---

Outside diff comments:
In `@docs/features/litellm-compat.mdx`:
- Around line 9-13: The doc header incorrectly says "two transformations" while
the plugin actually exposes three behaviors; update the prose to
enumerate/clarify all three features — convert_text_to_chat,
convert_chat_to_responses, and should_drop_params — and distinguish which are
true "transformations" (e.g., text-to-chat and chat-to-responses) versus other
behaviors (e.g., dropping params), and mention that responses include
extra_fields.litellm_compat: true when any are applied.

---

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 5234-5241: The migration updates compat_convert_text_to_chat from
enable_litellm_fallbacks then drops that column but doesn't refresh the derived
config_hash; update the migration to, after running tx.Exec("UPDATE
config_client SET compat_convert_text_to_chat = enable_litellm_fallbacks") and
before calling mig.DropColumn(&tables.TableClientConfig{},
"enable_litellm_fallbacks"), recompute and persist the config_hash for the
affected config_client rows within the same transaction (use the same tx and
target rows in config_client), ensuring the new hash is saved so reconciliation
isn't stale; reference the existing mig.HasColumn, tx.Exec,
tables.TableClientConfig, compat_convert_text_to_chat, enable_litellm_fallbacks,
and config_hash when locating where to add the hash recompute and update logic.

In `@ui/app/workspace/config/views/clientSettingsView.tsx`:
- Around line 111-113: The comparison logic for compat flags (e.g.,
localConfig.compat?.convert_text_to_chat, convert_chat_to_responses,
should_drop_params) treats undefined and false as different, causing sticky
dirty state; fix by normalizing these optional flags before comparing (use a
default like false via nullish-coalescing or explicit boolean cast) so the check
(used by hasCoreConfigChanges or similar) compares normalized boolean values on
both sides (e.g., (localConfig.compat?.convert_text_to_chat ?? false) !==
(config.compat?.convert_text_to_chat ?? false)) for each compat property.
- Around line 333-350: The Link (data-testid="litellm-docs-link") is nested
inside AccordionTrigger (which renders a <button>), causing nested interactive
elements; move the Link out of AccordionTrigger so it is not a descendant of
AccordionTrigger (e.g., render the Link immediately after AccordionTrigger or
inside AccordionContent), remove the now-unnecessary onClick={(e) =>
e.stopPropagation()} on the Link, and keep the href/target/rel/data-testid props
intact so the docs link remains functional and accessible while AccordionTrigger
remains a single interactive element.
- Around line 361-399: Add data-testid attributes to the three new Switch
components in clientSettingsView.tsx so E2E tests can target them; for each
Switch with id "compat-convert-text-to-chat",
"compat-convert-chat-to-responses", and "compat-should-drop-params" add a
data-testid following the project pattern (e.g.,
data-testid="compat-switch-convert-text-to-chat",
"compat-switch-convert-chat-to-responses", and
"compat-switch-should-drop-params") ensuring the attribute is placed on the
Switch element so tests can reliably select the interactive control.

---

Nitpick comments:
In `@plugins/compat/main.go`:
- Around line 114-124: When p.config.ShouldDropParams is true but p.modelCatalog
is nil, the current branch silently does nothing; add a warning or debug log to
surface this misconfiguration. Inside the existing if p.config.ShouldDropParams
&& p.modelCatalog != nil conditional flow, add an else branch (for when
p.modelCatalog == nil) that logs a clear message via the package logger (or ctx
logger) indicating ShouldDropParams is enabled but modelCatalog is missing,
referencing the plugin instance and model name context as appropriate (use
symbols p.config.ShouldDropParams, p.modelCatalog, computeUnsupportedParams,
ctx.SetValue, schemas.BifrostContextKeyCompatPluginDroppedParams to locate the
code). Ensure the log level is warning or debug so it’s visible in production
without changing behavior.

In `@transports/bifrost-http/lib/config_test.go`:
- Around line 12425-12430: The test only checks hash sensitivity for
Compat.ConvertTextToChat; update the test around cc13/cc1 and
GenerateClientConfigHash to also mutate and assert uniqueness for
Compat.ConvertChatToResponses and Compat.ShouldDropParams: create separate
copies (e.g., cc13, cc14, cc15) from cc1, flip each flag on Compat
(ConvertTextToChat, ConvertChatToResponses, ShouldDropParams) one at a time,
call GenerateClientConfigHash for each copy (hash13, hash14, hash15), and add
assertions that each new hash is not equal to the original hash1 to ensure the
hash changes for all new compat fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3afd1c1f-5748-4452-885e-86a116119f06

📥 Commits

Reviewing files that changed from the base of the PR and between fd76fc6 and 905602b.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (8)
  • plugins/compat/version
  • examples/dockers/data/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • helm-charts/bifrost/values.yaml
  • .github/workflows/scripts/run-migration-tests.sh
  • transports/bifrost-http/handlers/config.go
  • docs/openapi/openapi.json
🚧 Files skipped from review as they are similar to previous changes (15)
  • .github/workflows/scripts/test-docker-image.sh
  • examples/configs/withprompushgateway/config.json
  • tests/governance/config.json
  • transports/bifrost-http/server/plugins.go
  • docs/openapi/schemas/management/config.yaml
  • transports/go.mod
  • ui/components/ui/accordion.tsx
  • transports/config.schema.json
  • framework/configstore/rdb.go
  • ui/lib/types/config.ts
  • helm-charts/bifrost/values.schema.json
  • docs/providers/supported-providers/overview.mdx
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • framework/configstore/clientconfig.go

Comment thread docs/features/litellm-compat.mdx
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 905602b to 79eddf4 Compare March 25, 2026 10:05
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from df3d2b2 to a591e66 Compare March 25, 2026 10:05
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 25, 2026

Confidence Score: 4/5

Not safe to merge yet — the duplicate go.mod entry breaks the build, the migration silently enables a compat feature for all deployments, and config-hash recomputation is still missing.

A P0 go.mod duplicate (raised in a prior round, still present) prevents go build from succeeding. A new P1 was found: the migration unconditionally sets compat_should_convert_params = TRUE for every row, silently loading the compat plugin on all deployments regardless of their previous opt-in state. The missing config_hash recomputation (prior P1, still unresolved) means every existing deployment will see a hash mismatch on first boot. These issues together justify a 4/5.

transports/go.mod (duplicate require), framework/configstore/migrations.go (unconditional should_convert_params backfill, missing config_hash recompute), framework/configstore/clientconfig.go (hash asymmetry causing churn).

Vulnerabilities

No security concerns identified. The change is confined to configuration structure and database migration with no auth, injection, or data-exposure implications.

Important Files Changed

Filename Overview
framework/configstore/migrations.go New migration adds four compat columns and drops enable_litellm_fallbacks, but unconditionally sets compat_should_convert_params = TRUE for all rows (silently activating the compat plugin on all deployments), does not recompute config_hash, and has an inverted rollback conditional.
framework/configstore/clientconfig.go Hash function switched from always writing `enableLiteLLMFallbacks:{true
framework/configstore/tables/clientconfig.go Adds four compat_* boolean columns with correct GORM tags and DB defaults; schema definition is clean.
transports/go.mod github.com/maximhq/bifrost/plugins/compat v0.1.0 appears twice in the require block; Go treats duplicate require directives as a module graph error that breaks go build.
transports/bifrost-http/handlers/config.go Compat plugin toggle logic correctly gates on newCompat != oldCompat, computes newEnabled across all four flags, and returns after both error paths; no issues found.
transports/bifrost-http/server/plugins.go Startup compat plugin check includes ShouldConvertParams in the OR condition; because the migration unconditionally sets this flag to true, the plugin loads for all existing deployments.
plugins/compat/main.go Plugin logic correctly branches on each individual feature flag; applyParameterConversion is scoped to Bedrock/Vertex/Gemini.
ui/lib/types/config.ts Adds CompatConfig interface and updates CoreConfig; DefaultCoreConfig sets should_convert_params: true matching the new DB default.
ui/app/workspace/config/views/clientSettingsView.tsx Replaces single toggle with per-flag compat controls; uses optional chaining on compat?. despite the type being non-optional.

Reviews (17): Last reviewed commit: "feat: removes enable_litellm_fallback op..." | Re-trigger Greptile

Comment thread framework/configstore/migrations.go
Comment thread ui/app/workspace/config/views/clientSettingsView.tsx Outdated
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from a591e66 to 9c75725 Compare March 25, 2026 10:14
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 79eddf4 to 540542d Compare March 25, 2026 10:14
Comment thread framework/configstore/migrations.go Outdated
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 540542d to 4386a9d Compare March 25, 2026 10:26
@sammaji sammaji changed the base branch from 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level to graphite-base/2260 March 25, 2026 10:26
Comment thread plugins/compat/version Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
framework/configstore/migrations.go (2)

761-764: ⚠️ Potential issue | 🟡 Minor

Make the rollback DROP COLUMN dialect-aware.

Line 763 uses DROP COLUMN IF EXISTS, which SQLite does not support, so rollback will fail on SQLite.

Does SQLite support `ALTER TABLE ... DROP COLUMN IF EXISTS`, and what syntax should be used for SQLite versus PostgreSQL when dropping a column conditionally?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 761 - 764, The rollback
currently executes "ALTER TABLE config_client DROP COLUMN IF EXISTS
enable_litellm_fallbacks" which fails on SQLite; update the Rollback func (the
anonymous Rollback: func(tx *gorm.DB) error) to be dialect-aware by checking
tx.Dialector.Name() and: for PostgreSQL run the DROP COLUMN ... IF EXISTS SQL
via tx.Exec as before, and for SQLite perform the safe column removal sequence
(create a temp table without enable_litellm_fallbacks, copy remaining columns,
drop the original table, then rename the temp table) or skip the DROP if you
prefer not to change schema on SQLite; ensure all tx.Exec calls inside Rollback
use tx.WithContext(ctx) and return any exec errors.

5266-5273: ⚠️ Potential issue | 🟠 Major

Recompute config_hash in the same migration.

This update changes persisted client-config state, but affected rows keep the pre-compat hash. That can leave config reconciliation dirty until a later write touches the row.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 5266 - 5273, After copying
enable_litellm_fallbacks into compat_convert_text_to_chat, recompute and persist
the config_hash for those affected client rows in the same transaction so they
don’t retain the old hash; specifically, in the migration after the
tx.Exec("UPDATE config_client SET compat_convert_text_to_chat =
enable_litellm_fallbacks") call add a tx.Exec that recalculates and updates the
config_hash column for the same rows (using the same hashing routine your
codebase uses for client configs — e.g., the Compute/Generate client config hash
helper used elsewhere) and do this before calling
mig.DropColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") so
TableClientConfig rows have an up-to-date config_hash immediately.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 761-764: The rollback currently executes "ALTER TABLE
config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks" which fails on
SQLite; update the Rollback func (the anonymous Rollback: func(tx *gorm.DB)
error) to be dialect-aware by checking tx.Dialector.Name() and: for PostgreSQL
run the DROP COLUMN ... IF EXISTS SQL via tx.Exec as before, and for SQLite
perform the safe column removal sequence (create a temp table without
enable_litellm_fallbacks, copy remaining columns, drop the original table, then
rename the temp table) or skip the DROP if you prefer not to change schema on
SQLite; ensure all tx.Exec calls inside Rollback use tx.WithContext(ctx) and
return any exec errors.
- Around line 5266-5273: After copying enable_litellm_fallbacks into
compat_convert_text_to_chat, recompute and persist the config_hash for those
affected client rows in the same transaction so they don’t retain the old hash;
specifically, in the migration after the tx.Exec("UPDATE config_client SET
compat_convert_text_to_chat = enable_litellm_fallbacks") call add a tx.Exec that
recalculates and updates the config_hash column for the same rows (using the
same hashing routine your codebase uses for client configs — e.g., the
Compute/Generate client config hash helper used elsewhere) and do this before
calling mig.DropColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks")
so TableClientConfig rows have an up-to-date config_hash immediately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 62639205-e346-4755-8556-bff313fe5b09

📥 Commits

Reviewing files that changed from the base of the PR and between 905602b and 4386a9d.

⛔ Files ignored due to path filters (1)
  • transports/go.sum is excluded by !**/*.sum
📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (4)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • transports/go.mod
✅ Files skipped from review due to trivial changes (9)
  • examples/dockers/data/config.json
  • examples/configs/withprompushgateway/config.json
  • .github/workflows/scripts/test-docker-image.sh
  • plugins/compat/version
  • tests/integrations/typescript/config.json
  • ui/components/ui/accordion.tsx
  • docs/providers/supported-providers/overview.mdx
  • helm-charts/bifrost/templates/_helpers.tpl
  • .github/workflows/scripts/run-migration-tests.sh
🚧 Files skipped from review as they are similar to previous changes (13)
  • tests/governance/config.json
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/bifrost-http/lib/config.go
  • tests/integrations/python/config.json
  • helm-charts/bifrost/values.yaml
  • transports/bifrost-http/handlers/config.go
  • plugins/compat/main.go
  • framework/configstore/rdb.go
  • transports/bifrost-http/lib/config_test.go

@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 4386a9d to 5587929 Compare March 25, 2026 11:11
@sammaji sammaji changed the base branch from graphite-base/2260 to 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level March 25, 2026 11:11
Comment thread transports/bifrost-http/handlers/config.go
Comment thread framework/configstore/clientconfig.go
@sammaji sammaji force-pushed the graphite-base/2260 branch from 6c2e458 to 12a24fa Compare April 7, 2026 08:57
@sammaji sammaji changed the base branch from graphite-base/2260 to 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level April 7, 2026 08:57
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from fe7525d to 523c153 Compare April 7, 2026 09:00
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/features/litellm-compat.mdx`:
- Around line 139-142: Update the chat→responses table row for "OpenAI (o1-pro)"
so the "Native Responses" column shows "Yes" instead of "No" to match the
narrative; locate the table where the row contains "OpenAI (o1-pro)" and change
the first data cell from "No" to "Yes" (leave the "With Fallback" cell as-is).
- Around line 184-190: The docs list incorrect error metadata keys for the
compat plugin; update the text to remove extra_fields.litellm_compat, rename
extra_fields.model_requested to extra_fields.original_model_requested, and state
that extra_fields.converted_request_type is present only in response metadata
(BifrostResponseExtraFields) not in error metadata (BifrostErrorExtraFields).
Ensure the error-path section only claims extra_fields.provider,
extra_fields.original_model_requested, and
extra_fields.dropped_compat_plugin_params are present, and adjust any lines that
imply the original request type is preserved in BifrostErrorExtraFields to
reference BifrostResponseExtraFields if necessary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8806d61-bbc9-477e-8e68-9bc8880b691e

📥 Commits

Reviewing files that changed from the base of the PR and between fa74b89 and 523c153.

📒 Files selected for processing (5)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
💤 Files with no reviewable changes (1)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/run-migration-tests.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/scripts/validate-helm-config-fields.sh

Comment thread docs/features/litellm-compat.mdx Outdated
Comment thread docs/features/litellm-compat.mdx
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 523c153 to bc83fba Compare April 7, 2026 09:53
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from 12a24fa to dabb480 Compare April 7, 2026 09:53
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from bc83fba to c8e2874 Compare April 7, 2026 09:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
transports/bifrost-http/handlers/config.go (1)

345-370: ⚠️ Potential issue | 🟠 Major

Defer compat plugin mutation until after the config write succeeds.

ReloadPlugin/RemovePlugin runs before UpdateClientConfig() and ReloadClientConfigFromConfigStore(). If either later step fails, the live compat plugin can drift from the persisted config. Move this block after the save/reload path, or roll back to oldCompat on failure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/handlers/config.go` around lines 345 - 370, The
compat plugin is being reloaded/removed (calls to h.configManager.ReloadPlugin
and h.configManager.RemovePlugin) before the config persistence steps
(UpdateClientConfig and ReloadClientConfigFromConfigStore), which can leave
runtime state out of sync if persistence fails; move the entire compat mutation
block (the newCompat vs oldCompat logic that sets compatCfg and uses
PluginDisabledKey) to execute only after UpdateClientConfig() and
ReloadClientConfigFromConfigStore() succeed, or alternatively, after performing
ReloadPlugin/RemovePlugin, on any subsequent failure call the inverse operation
to restore oldCompat (i.e., reload the old compatCfg or re-add the plugin with
oldCompat settings) so runtime and persisted config remain consistent.
docs/features/litellm-compat.mdx (2)

9-15: ⚠️ Potential issue | 🟡 Minor

Document the third compat feature consistently.

The page still opens with “two transformations”, but the UI/config now expose three compat features, and Drop Unsupported Params still has no dedicated behavior/reference section. Right now users can enable it without any guidance on what gets removed or when to use it.

Also applies to: 98-115, 150-173

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` around lines 9 - 15, Update the opening
text to list three compat features (Text-to-Chat Conversion, Chat-to-Responses
Conversion, and Drop Unsupported Params) instead of “two transformations”, and
add a short dedicated section describing the third feature: explain what “Drop
Unsupported Params” does, when it runs, which parameters it can remove, and that
dropped keys are listed in extra_fields.dropped_compat_plugin_params; also
update the other occurrences referenced (around the blocks at lines ~98-115 and
~150-173) so they consistently mention the third feature and its behavior and
examples, ensuring the doc references the returned metadata field
extra_fields.converted_request_type for transformed requests and
extra_fields.dropped_compat_plugin_params for dropped params.

184-189: ⚠️ Potential issue | 🟡 Minor

Keep the error-metadata docs aligned with actual compat errors.

This section still claims transformed errors expose extra_fields.converted_request_type / original request type. The compat error path only guarantees extra_fields.provider, extra_fields.original_model_requested, and extra_fields.dropped_compat_plugin_params; converted_request_type belongs in transformed response metadata, not error metadata.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` around lines 184 - 189, Update the
documentation to remove `extra_fields.converted_request_type` from the list of
fields exposed on transformed request errors and instead document it under
transformed response metadata; ensure the error-metadata bullet list only
includes `extra_fields.provider`, `extra_fields.original_model_requested`, and
`extra_fields.dropped_compat_plugin_params` (and remove the claim that the
original request type is preserved via `extra_fields.converted_request_type` in
error metadata).
framework/configstore/migrations.go (1)

6075-6089: ⚠️ Potential issue | 🟠 Major

Rollback never restores the legacy column.

After a successful migrate, enable_litellm_fallbacks is already gone, so this block is skipped and downgrade drops the compat_* columns without recreating the old schema. Even if the condition were true, it drops the legacy column before trying to backfill it, so the UPDATE cannot work.

🛠️ Suggested fix
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
 			mig := tx.Migrator()
-			if tx.Migrator().HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
-				if err := tx.Exec("ALTER TABLE config_client DROP COLUMN enable_litellm_fallbacks").Error; err != nil {
-					return err
-				}
-				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
-					return err
-				}
+			if !mig.HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
+				if err := tx.Exec("ALTER TABLE config_client ADD COLUMN enable_litellm_fallbacks BOOLEAN DEFAULT FALSE").Error; err != nil {
+					return err
+				}
+			}
+			if mig.HasColumn(&tables.TableClientConfig{}, "compat_convert_text_to_chat") {
+				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
+					return err
+				}
 			}
 			for _, col := range []string{
 				"compat_convert_text_to_chat",
 				"compat_convert_chat_to_responses",
 				"compat_should_drop_params",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 6075 - 6089, The rollback
currently drops the compat_* columns without recreating or backfilling the
legacy enable_litellm_fallbacks column and even attempts UPDATE after dropping
it; fix by ensuring the legacy column is present before any backfill: in the
migration/downgrade block check HasColumn(&tables.TableClientConfig{},
"enable_litellm_fallbacks") and if false run an ALTER TABLE ... ADD COLUMN
enable_litellm_fallbacks BOOLEAN (or the original type) via tx.Exec to recreate
it, then perform the UPDATE "UPDATE config_client SET enable_litellm_fallbacks =
compat_convert_text_to_chat" to backfill, and only after successful backfill
drop the compat_* columns (use mig.DropColumn on tables.TableClientConfig for
the compat_* names).
ui/app/workspace/config/views/clientSettingsView.tsx (2)

335-350: ⚠️ Potential issue | 🟠 Major

Move the docs link outside the accordion trigger.

Line 340 places a Link inside AccordionTrigger, creating nested interactive controls and accessibility/semantics issues. Keep trigger content non-interactive and render the docs link as a sibling.

Suggested structure change
- <AccordionTrigger className="py-0 hover:no-underline">
+ <AccordionTrigger className="py-0 hover:no-underline">
    <div className="space-y-0.5 text-left">
      <span className="text-sm font-medium">LiteLLM Compat</span>
-     <p className="text-muted-foreground text-sm font-normal">
-       Request type conversion and parameter dropping.{" "}
-       <Link ... onClick={(e) => e.stopPropagation()}>Learn more</Link>
-     </p>
+     <p className="text-muted-foreground text-sm font-normal">
+       Request type conversion and parameter dropping.
+     </p>
    </div>
  </AccordionTrigger>
+ <div className="pt-2">
+   <Link
+     className="text-primary cursor-pointer underline"
+     href="https://docs.getbifrost.ai/features/litellm-compat"
+     target="_blank"
+     rel="noopener noreferrer"
+     data-testid="litellm-docs-link"
+   >
+     Learn more
+   </Link>
+ </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 335 - 350,
The Link for the docs is inside AccordionTrigger (creating nested interactive
controls); move that <Link ... data-testid="litellm-docs-link"> out of the
AccordionTrigger and render it as a sibling element directly after the
AccordionTrigger block in clientSettingsView (so the trigger remains
non-interactive), preserve the visual classes and href/target/rel/data-testid,
and remove the onClick stopPropagation handler since it will no longer be inside
the trigger; ensure spacing/layout matches the previous appearance.

335-401: ⚠️ Potential issue | 🟡 Minor

Add data-testid attributes to new compat interactive controls.

The new AccordionTrigger and three Switch controls are interactive and currently lack test IDs, which breaks the UI selector convention for new controls.

Suggested test IDs
- <AccordionTrigger className="py-0 hover:no-underline">
+ <AccordionTrigger
+   className="py-0 hover:no-underline"
+   data-testid="compat-accordion-trigger"
+ >
...
  <Switch
+   data-testid="compat-convert-text-to-chat-switch"
    id="compat-convert-text-to-chat"
    ...
  />
...
  <Switch
+   data-testid="compat-convert-chat-to-responses-switch"
    id="compat-convert-chat-to-responses"
    ...
  />
...
  <Switch
+   data-testid="compat-should-drop-params-switch"
    id="compat-should-drop-params"
    ...
  />
As per coding guidelines, `ui/**/*.{tsx,ts}` must add `data-testid` to new interactive elements using the `--` pattern.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/config/views/clientSettingsView.tsx` around lines 335 - 401,
The new interactive controls (AccordionTrigger and the three Switch components
in clientSettingsView.tsx) are missing data-testid attributes; add data-testid
following the <entity>-<element>-<qualifier> pattern to each interactive element
so tests can reliably select them. Specifically, add
data-testid="compat-accordion-trigger" to the AccordionTrigger, and add
data-testid attributes to the three Switches corresponding to their ids, e.g.
data-testid="compat-convert-text-to-chat-switch",
data-testid="compat-convert-chat-to-responses-switch", and
data-testid="compat-should-drop-params-switch" (match the existing id names like
"compat-convert-text-to-chat", "compat-convert-chat-to-responses",
"compat-should-drop-params") and ensure these attributes are applied alongside
the existing props and disabled logic.
🧹 Nitpick comments (1)
transports/config.schema.json (1)

97-115: Schema change looks correct and aligns with the PR objectives.

The new compat object properly replaces the single enable_litellm_fallbacks boolean with three granular flags. The structure is valid, descriptions are clear, and additionalProperties: false enforces strict validation.

Consider adding explicit default: false to each boolean property for documentation clarity and to make the default behavior explicit in the schema:

💡 Optional: Add default values for clarity
         "compat": {
           "type": "object",
           "description": "Compat plugin configuration for request type conversion and parameter dropping",
           "properties": {
             "convert_text_to_chat": {
               "type": "boolean",
-              "description": "Convert text completion requests to chat for models that only support chat"
+              "description": "Convert text completion requests to chat for models that only support chat",
+              "default": false
             },
             "convert_chat_to_responses": {
               "type": "boolean",
-              "description": "Convert chat completion requests to responses for models that only support responses"
+              "description": "Convert chat completion requests to responses for models that only support responses",
+              "default": false
             },
             "should_drop_params": {
               "type": "boolean",
-              "description": "Drop unsupported parameters based on model catalog allowlist"
+              "description": "Drop unsupported parameters based on model catalog allowlist",
+              "default": false
             }
           },
           "additionalProperties": false
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/config.schema.json` around lines 97 - 115, Add explicit default:
false to each boolean property inside the compat object (convert_text_to_chat,
convert_chat_to_responses, should_drop_params) so the schema documents explicit
defaults; update the compat object properties to include default: false for
those three keys while keeping additionalProperties: false and existing
descriptions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@transports/bifrost-http/handlers/config.go`:
- Around line 351-356: The build is failing because the core module is missing
the compat plugin dependency referenced by compat.Config and compat.PluginName
used in handlers/config.go (and the call h.configManager.ReloadPlugin). Fix by
adding the compat module to core's go.mod require section (e.g., add
github.com/maximhq/bifrost/plugins/compat v1.x.x) and run `go mod tidy` to
update go.sum so imports resolve; ensure the declared version matches the plugin
release you expect.

---

Duplicate comments:
In `@docs/features/litellm-compat.mdx`:
- Around line 9-15: Update the opening text to list three compat features
(Text-to-Chat Conversion, Chat-to-Responses Conversion, and Drop Unsupported
Params) instead of “two transformations”, and add a short dedicated section
describing the third feature: explain what “Drop Unsupported Params” does, when
it runs, which parameters it can remove, and that dropped keys are listed in
extra_fields.dropped_compat_plugin_params; also update the other occurrences
referenced (around the blocks at lines ~98-115 and ~150-173) so they
consistently mention the third feature and its behavior and examples, ensuring
the doc references the returned metadata field
extra_fields.converted_request_type for transformed requests and
extra_fields.dropped_compat_plugin_params for dropped params.
- Around line 184-189: Update the documentation to remove
`extra_fields.converted_request_type` from the list of fields exposed on
transformed request errors and instead document it under transformed response
metadata; ensure the error-metadata bullet list only includes
`extra_fields.provider`, `extra_fields.original_model_requested`, and
`extra_fields.dropped_compat_plugin_params` (and remove the claim that the
original request type is preserved via `extra_fields.converted_request_type` in
error metadata).

In `@framework/configstore/migrations.go`:
- Around line 6075-6089: The rollback currently drops the compat_* columns
without recreating or backfilling the legacy enable_litellm_fallbacks column and
even attempts UPDATE after dropping it; fix by ensuring the legacy column is
present before any backfill: in the migration/downgrade block check
HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") and if false
run an ALTER TABLE ... ADD COLUMN enable_litellm_fallbacks BOOLEAN (or the
original type) via tx.Exec to recreate it, then perform the UPDATE "UPDATE
config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat" to
backfill, and only after successful backfill drop the compat_* columns (use
mig.DropColumn on tables.TableClientConfig for the compat_* names).

In `@transports/bifrost-http/handlers/config.go`:
- Around line 345-370: The compat plugin is being reloaded/removed (calls to
h.configManager.ReloadPlugin and h.configManager.RemovePlugin) before the config
persistence steps (UpdateClientConfig and ReloadClientConfigFromConfigStore),
which can leave runtime state out of sync if persistence fails; move the entire
compat mutation block (the newCompat vs oldCompat logic that sets compatCfg and
uses PluginDisabledKey) to execute only after UpdateClientConfig() and
ReloadClientConfigFromConfigStore() succeed, or alternatively, after performing
ReloadPlugin/RemovePlugin, on any subsequent failure call the inverse operation
to restore oldCompat (i.e., reload the old compatCfg or re-add the plugin with
oldCompat settings) so runtime and persisted config remain consistent.

In `@ui/app/workspace/config/views/clientSettingsView.tsx`:
- Around line 335-350: The Link for the docs is inside AccordionTrigger
(creating nested interactive controls); move that <Link ...
data-testid="litellm-docs-link"> out of the AccordionTrigger and render it as a
sibling element directly after the AccordionTrigger block in clientSettingsView
(so the trigger remains non-interactive), preserve the visual classes and
href/target/rel/data-testid, and remove the onClick stopPropagation handler
since it will no longer be inside the trigger; ensure spacing/layout matches the
previous appearance.
- Around line 335-401: The new interactive controls (AccordionTrigger and the
three Switch components in clientSettingsView.tsx) are missing data-testid
attributes; add data-testid following the <entity>-<element>-<qualifier> pattern
to each interactive element so tests can reliably select them. Specifically, add
data-testid="compat-accordion-trigger" to the AccordionTrigger, and add
data-testid attributes to the three Switches corresponding to their ids, e.g.
data-testid="compat-convert-text-to-chat-switch",
data-testid="compat-convert-chat-to-responses-switch", and
data-testid="compat-should-drop-params-switch" (match the existing id names like
"compat-convert-text-to-chat", "compat-convert-chat-to-responses",
"compat-should-drop-params") and ensure these attributes are applied alongside
the existing props and disabled logic.

---

Nitpick comments:
In `@transports/config.schema.json`:
- Around line 97-115: Add explicit default: false to each boolean property
inside the compat object (convert_text_to_chat, convert_chat_to_responses,
should_drop_params) so the schema documents explicit defaults; update the compat
object properties to include default: false for those three keys while keeping
additionalProperties: false and existing descriptions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a366a1f-1f3e-480a-846a-6449e6a5032e

📥 Commits

Reviewing files that changed from the base of the PR and between 523c153 and c8e2874.

📒 Files selected for processing (33)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • plugins/compat/version
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withvirtualkeys/config.json
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (9)
  • tests/integrations/typescript/config.json
  • plugins/compat/version
  • tests/integrations/python/config.json
  • docs/providers/supported-providers/overview.mdx
  • .github/workflows/scripts/test-docker-image.sh
  • examples/dockers/data/config.json
  • tests/governance/config.json
  • ui/components/ui/accordion.tsx
  • docs/openapi/openapi.json
🚧 Files skipped from review as they are similar to previous changes (10)
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • examples/configs/withprompushgateway/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • helm-charts/bifrost/values.yaml
  • transports/bifrost-http/server/plugins.go
  • transports/go.mod
  • helm-charts/bifrost/values.schema.json
  • framework/configstore/clientconfig.go
  • transports/bifrost-http/lib/config_test.go
  • framework/configstore/tables/clientconfig.go

Comment thread transports/bifrost-http/handlers/config.go
@sammaji sammaji changed the base branch from 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level to graphite-base/2260 April 8, 2026 05:39
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from c8e2874 to 59049a3 Compare April 8, 2026 06:00
@sammaji sammaji force-pushed the graphite-base/2260 branch from dabb480 to ef6fb53 Compare April 8, 2026 06:00
@sammaji sammaji changed the base branch from graphite-base/2260 to 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level April 8, 2026 06:01
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 59049a3 to b9cc6b7 Compare April 8, 2026 06:07
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from ef6fb53 to a596ed4 Compare April 8, 2026 06:07
Comment thread framework/configstore/migrations.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
framework/configstore/migrations.go (2)

6110-6132: ⚠️ Potential issue | 🟠 Major

Restore the legacy column before dropping compat_* fields.

After a successful migrate, enable_litellm_fallbacks is absent, so Lines 6113-6120 never run and rollback drops the compat_* columns without recreating the old schema. If the column does exist, the current code drops it before copying the data back, so the UPDATE cannot succeed.

🛠️ Suggested fix
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
 			mig := tx.Migrator()
-			if tx.Migrator().HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
-				if err := tx.Exec("ALTER TABLE config_client DROP COLUMN enable_litellm_fallbacks").Error; err != nil {
-					return err
-				}
-				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
-					return err
-				}
+			if !mig.HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
+				if err := tx.Exec("ALTER TABLE config_client ADD COLUMN enable_litellm_fallbacks BOOLEAN DEFAULT FALSE").Error; err != nil {
+					return err
+				}
+			}
+			if mig.HasColumn(&tables.TableClientConfig{}, "compat_convert_text_to_chat") {
+				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
+					return err
+				}
 			}
 			for _, col := range []string{
 				"compat_convert_text_to_chat",
 				"compat_convert_chat_to_responses",
 				"compat_should_drop_params",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 6110 - 6132, The Rollback
closure in Rollback should restore the legacy enable_litellm_fallbacks column
before removing compat_* columns and must not drop it before copying data;
modify Rollback (tx, mig, tables.TableClientConfig) to: if
enable_litellm_fallbacks is missing, add/create that column first (e.g., via
tx.Migrator().AddColumn or appropriate ALTER TABLE ADD COLUMN), then run an
UPDATE to populate enable_litellm_fallbacks from compat_convert_text_to_chat (or
other compat_* sources as intended), and only after the data is copied
successfully iterate over compat_convert_text_to_chat,
compat_convert_chat_to_responses, compat_should_drop_params and drop those
columns via mig.DropColumn; ensure you remove the current code path that drops
enable_litellm_fallbacks before the UPDATE and use tx.WithContext(ctx) for all
DDL/DML operations.

800-804: ⚠️ Potential issue | 🟡 Minor

Make this rollback dialect-safe for SQLite.

Line 802 still uses ALTER TABLE ... DROP COLUMN IF EXISTS. SQLite supports DROP COLUMN column-name, but not the IF EXISTS modifier, so this rollback still fails on SQLite. (sqlite.org)

🛠️ Suggested fix
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
-			if err := tx.Exec("ALTER TABLE config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks").Error; err != nil {
-				return err
+			if tx.Migrator().HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
+				stmt := "ALTER TABLE config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks"
+				if tx.Dialector.Name() == "sqlite" {
+					stmt = "ALTER TABLE config_client DROP COLUMN enable_litellm_fallbacks"
+				}
+				if err := tx.Exec(stmt).Error; err != nil {
+					return err
+				}
 			}
 			return nil
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 800 - 804, The rollback
uses "ALTER TABLE config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks"
which fails on SQLite because SQLite does not support the IF EXISTS modifier;
update the Rollback anonymous function to branch on the dialect (use
tx.Dialector.Name() or equivalent) and execute "ALTER TABLE config_client DROP
COLUMN enable_litellm_fallbacks" for sqlite while keeping the "DROP COLUMN IF
EXISTS ..." statement for other dialects, ensuring you still call tx.Exec and
return any error; reference the Rollback func, tx.Exec call, and the column name
enable_litellm_fallbacks when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@framework/configstore/migrations.go`:
- Around line 6110-6132: The Rollback closure in Rollback should restore the
legacy enable_litellm_fallbacks column before removing compat_* columns and must
not drop it before copying data; modify Rollback (tx, mig,
tables.TableClientConfig) to: if enable_litellm_fallbacks is missing, add/create
that column first (e.g., via tx.Migrator().AddColumn or appropriate ALTER TABLE
ADD COLUMN), then run an UPDATE to populate enable_litellm_fallbacks from
compat_convert_text_to_chat (or other compat_* sources as intended), and only
after the data is copied successfully iterate over compat_convert_text_to_chat,
compat_convert_chat_to_responses, compat_should_drop_params and drop those
columns via mig.DropColumn; ensure you remove the current code path that drops
enable_litellm_fallbacks before the UPDATE and use tx.WithContext(ctx) for all
DDL/DML operations.
- Around line 800-804: The rollback uses "ALTER TABLE config_client DROP COLUMN
IF EXISTS enable_litellm_fallbacks" which fails on SQLite because SQLite does
not support the IF EXISTS modifier; update the Rollback anonymous function to
branch on the dialect (use tx.Dialector.Name() or equivalent) and execute "ALTER
TABLE config_client DROP COLUMN enable_litellm_fallbacks" for sqlite while
keeping the "DROP COLUMN IF EXISTS ..." statement for other dialects, ensuring
you still call tx.Exec and return any error; reference the Rollback func,
tx.Exec call, and the column name enable_litellm_fallbacks when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc720738-67c0-49fc-8fc6-d318ba411fc3

📥 Commits

Reviewing files that changed from the base of the PR and between c8e2874 and b9cc6b7.

📒 Files selected for processing (32)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (9)
  • examples/dockers/data/config.json
  • tests/integrations/typescript/config.json
  • docs/providers/supported-providers/overview.mdx
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • examples/configs/withprompushgateway/config.json
  • .github/workflows/scripts/test-docker-image.sh
  • docs/openapi/schemas/management/config.yaml
  • ui/app/workspace/config/views/clientSettingsView.tsx
🚧 Files skipped from review as they are similar to previous changes (14)
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • ui/components/ui/accordion.tsx
  • helm-charts/bifrost/values.yaml
  • docs/openapi/openapi.json
  • transports/config.schema.json
  • plugins/compat/main.go
  • framework/configstore/clientconfig.go
  • .github/workflows/scripts/run-migration-tests.sh
  • ui/lib/types/config.ts
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • docs/features/litellm-compat.mdx
  • transports/bifrost-http/lib/config_test.go

@sammaji sammaji changed the base branch from 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level to graphite-base/2260 April 9, 2026 04:30
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from b9cc6b7 to 2734893 Compare April 9, 2026 04:47
@sammaji sammaji force-pushed the graphite-base/2260 branch from a596ed4 to ef3b1d3 Compare April 9, 2026 04:47
@sammaji sammaji changed the base branch from graphite-base/2260 to 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level April 9, 2026 04:47
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 2734893 to 05c065e Compare April 9, 2026 04:52
@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from ef3b1d3 to 6a6d436 Compare April 9, 2026 04:52
Comment thread transports/go.mod
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
docs/features/litellm-compat.mdx (2)

7-15: ⚠️ Potential issue | 🟡 Minor

The intro still underspecifies the new compat surface.

Line 9 still says "two transformations" while the list now exposes three toggles, and Drop Unsupported Params still doesn't get the same detailed section/reference as the other two behaviors. That leaves the third switch effectively undocumented.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` around lines 7 - 15, Update the intro under
"Compatibility Transformations" to correctly state there are three
transformations (Text-to-Chat Conversion, Chat-to-Responses Conversion, and Drop
Unsupported Params) and expand the documentation for "Drop Unsupported Params"
so it mirrors the other two: describe what parameters can be dropped, when the
drop occurs, the shape/location of resulting metadata
(extra_fields.dropped_compat_plugin_params and how keys are listed), and include
a short example of a request before/after conversion; reference the
headings/labels "Text-to-Chat Conversion", "Chat-to-Responses Conversion", "Drop
Unsupported Params", and the metadata keys "extra_fields.converted_request_type"
and "extra_fields.dropped_compat_plugin_params" to ensure readers can locate the
behavior in the doc.

182-189: ⚠️ Potential issue | 🟠 Major

Error metadata section is still documenting the wrong compat fields.

This section still claims extra_fields.converted_request_type is present on compat error payloads and implies the original request type is preserved there. As written, consumers will look for error metadata that won't exist.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/features/litellm-compat.mdx` around lines 182 - 189, The docs
incorrectly claim extra_fields.converted_request_type exists and that the
original request type is preserved; remove any mention of
extra_fields.converted_request_type and the assertion that original request type
is preserved, and update the Error Handling paragraph to state that the compat
layer does NOT include the original request type in error metadata; keep and
verify the other fields (extra_fields.provider,
extra_fields.original_model_requested,
extra_fields.dropped_compat_plugin_params) are correctly described and adjust
wording to explicitly say which metadata is present versus which is not (refer
to the current compat error payload shape when editing).
framework/configstore/migrations.go (2)

6126-6146: ⚠️ Potential issue | 🟠 Major

Restore the legacy column before copying data back.

After a successful migrate, enable_litellm_fallbacks is absent, so Line 6129 skips the restoration path and rollback only removes the new compat_* columns. If the legacy column does exist, Lines 6130-6133 drop it before writing into it, so that branch fails immediately. Downgrades to pre-compat revisions stay broken.

🛠️ Suggested fix
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
 			mig := tx.Migrator()
-			if tx.Migrator().HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
-				if err := tx.Exec("ALTER TABLE config_client DROP COLUMN enable_litellm_fallbacks").Error; err != nil {
-					return err
-				}
-				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
-					return err
-				}
+			if !mig.HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
+				if err := tx.Exec("ALTER TABLE config_client ADD COLUMN enable_litellm_fallbacks BOOLEAN DEFAULT FALSE").Error; err != nil {
+					return err
+				}
+			}
+			if mig.HasColumn(&tables.TableClientConfig{}, "compat_convert_text_to_chat") {
+				if err := tx.Exec("UPDATE config_client SET enable_litellm_fallbacks = compat_convert_text_to_chat").Error; err != nil {
+					return err
+				}
 			}
 			for _, col := range []string{
 				"compat_convert_text_to_chat",
 				"compat_convert_chat_to_responses",
 				"compat_should_drop_params",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 6126 - 6146, The rollback
branch in the Rollback function currently drops or skips the legacy column and
then tries to UPDATE it, breaking downgrades; change the flow in Rollback (using
tx, mig, tx.Migrator(), and HasColumn checks) so that if the legacy column
"enable_litellm_fallbacks" does not exist you CREATE/ADD that column first
(using mig.AddColumn or ALTER TABLE ADD), and if it does exist do NOT DROP it
before copying; then run the UPDATE ("UPDATE config_client SET
enable_litellm_fallbacks = compat_convert_text_to_chat") to restore values, and
only after the copy complete proceed to drop the new compat_* columns
("compat_convert_text_to_chat", "compat_convert_chat_to_responses",
"compat_should_drop_params") via mig.DropColumn as currently implemented.

800-803: ⚠️ Potential issue | 🟠 Major

Make this rollback dialect-aware.

Line 802 still uses ALTER TABLE ... DROP COLUMN IF EXISTS, which SQLite rejects. That breaks rollback on the repo’s SQLite path even though this file already branches on tx.Dialector.Name() for other DDL differences.

🛠️ Suggested fix
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
-			if err := tx.Exec("ALTER TABLE config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks").Error; err != nil {
-				return err
+			if tx.Migrator().HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
+				stmt := "ALTER TABLE config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks"
+				if tx.Dialector.Name() == "sqlite" {
+					stmt = "ALTER TABLE config_client DROP COLUMN enable_litellm_fallbacks"
+				}
+				if err := tx.Exec(stmt).Error; err != nil {
+					return err
+				}
 			}
 			return nil
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 800 - 803, The rollback
currently always runs tx.Exec("ALTER TABLE config_client DROP COLUMN IF EXISTS
enable_litellm_fallbacks") which fails on SQLite; update the Rollback closure to
branch on tx.Dialector.Name() (like other migrations) and run dialect-specific
SQL: for Postgres/MySQL keep the ALTER TABLE ... DROP COLUMN IF EXISTS, and for
sqlite either skip the DROP or perform the safe SQLite pattern (table recreate /
copy without enable_litellm_fallbacks) using tx.Exec; reference the Rollback
func, tx.Dialector.Name(), tx.Exec and the column name enable_litellm_fallbacks
when implementing the fix.
🧹 Nitpick comments (1)
ui/lib/types/config.ts (1)

477-477: Consider a migration-safe transitional type for compat.

Line 477 makes compat strictly required, but this PR also supports legacy configs during migration (and UI code already handles missing compat values). A transitional optional/partial shape can prevent callers from over-trusting the type while legacy payloads still exist.

♻️ Suggested transitional typing
 export interface CoreConfig {
   drop_excess_requests: boolean;
   initial_pool_size: number;
   prometheus_labels: string[];
   enable_logging: boolean;
   disable_content_logging: boolean;
   disable_db_pings_in_health: boolean;
   log_retention_days: number;
   enforce_auth_on_inference: boolean;
   allow_direct_keys: boolean;
   allowed_origins: string[];
   allowed_headers: string[];
   max_request_body_size_mb: number;
-  compat: CompatConfig;
+  compat?: Partial<CompatConfig>;
   mcp_agent_depth: number;
   mcp_tool_execution_timeout: number;
   mcp_code_mode_binding_level?: string;
   mcp_tool_sync_interval: number;
   mcp_disable_auto_tool_inject: boolean;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/lib/types/config.ts` at line 477, The `compat` property is currently
required (`compat: CompatConfig;`) which breaks migration support for legacy
configs; update the type declaration to a migration-safe, optional/partial shape
(e.g., make `compat` optional and use `Partial<CompatConfig>` or `CompatConfig |
Partial<CompatConfig>`) so callers can't assume full presence while legacy
payloads are handled. Locate the `compat` field in the config type definition
and change its type to an optional/partial form and run typechecks to ensure
existing code paths that already handle missing `compat` still compile.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@docs/features/litellm-compat.mdx`:
- Around line 7-15: Update the intro under "Compatibility Transformations" to
correctly state there are three transformations (Text-to-Chat Conversion,
Chat-to-Responses Conversion, and Drop Unsupported Params) and expand the
documentation for "Drop Unsupported Params" so it mirrors the other two:
describe what parameters can be dropped, when the drop occurs, the
shape/location of resulting metadata (extra_fields.dropped_compat_plugin_params
and how keys are listed), and include a short example of a request before/after
conversion; reference the headings/labels "Text-to-Chat Conversion",
"Chat-to-Responses Conversion", "Drop Unsupported Params", and the metadata keys
"extra_fields.converted_request_type" and
"extra_fields.dropped_compat_plugin_params" to ensure readers can locate the
behavior in the doc.
- Around line 182-189: The docs incorrectly claim
extra_fields.converted_request_type exists and that the original request type is
preserved; remove any mention of extra_fields.converted_request_type and the
assertion that original request type is preserved, and update the Error Handling
paragraph to state that the compat layer does NOT include the original request
type in error metadata; keep and verify the other fields (extra_fields.provider,
extra_fields.original_model_requested,
extra_fields.dropped_compat_plugin_params) are correctly described and adjust
wording to explicitly say which metadata is present versus which is not (refer
to the current compat error payload shape when editing).

In `@framework/configstore/migrations.go`:
- Around line 6126-6146: The rollback branch in the Rollback function currently
drops or skips the legacy column and then tries to UPDATE it, breaking
downgrades; change the flow in Rollback (using tx, mig, tx.Migrator(), and
HasColumn checks) so that if the legacy column "enable_litellm_fallbacks" does
not exist you CREATE/ADD that column first (using mig.AddColumn or ALTER TABLE
ADD), and if it does exist do NOT DROP it before copying; then run the UPDATE
("UPDATE config_client SET enable_litellm_fallbacks =
compat_convert_text_to_chat") to restore values, and only after the copy
complete proceed to drop the new compat_* columns
("compat_convert_text_to_chat", "compat_convert_chat_to_responses",
"compat_should_drop_params") via mig.DropColumn as currently implemented.
- Around line 800-803: The rollback currently always runs tx.Exec("ALTER TABLE
config_client DROP COLUMN IF EXISTS enable_litellm_fallbacks") which fails on
SQLite; update the Rollback closure to branch on tx.Dialector.Name() (like other
migrations) and run dialect-specific SQL: for Postgres/MySQL keep the ALTER
TABLE ... DROP COLUMN IF EXISTS, and for sqlite either skip the DROP or perform
the safe SQLite pattern (table recreate / copy without enable_litellm_fallbacks)
using tx.Exec; reference the Rollback func, tx.Dialector.Name(), tx.Exec and the
column name enable_litellm_fallbacks when implementing the fix.

---

Nitpick comments:
In `@ui/lib/types/config.ts`:
- Line 477: The `compat` property is currently required (`compat:
CompatConfig;`) which breaks migration support for legacy configs; update the
type declaration to a migration-safe, optional/partial shape (e.g., make
`compat` optional and use `Partial<CompatConfig>` or `CompatConfig |
Partial<CompatConfig>`) so callers can't assume full presence while legacy
payloads are handled. Locate the `compat` field in the config type definition
and change its type to an optional/partial form and run typechecks to ensure
existing code paths that already handle missing `compat` still compile.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf3bdf6f-7a6f-43af-a02a-babdb01daa7b

📥 Commits

Reviewing files that changed from the base of the PR and between b9cc6b7 and 05c065e.

📒 Files selected for processing (32)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • .github/workflows/scripts/run-migration-tests.sh
  • .github/workflows/scripts/test-docker-image.sh
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • docs/features/litellm-compat.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • docs/providers/supported-providers/overview.mdx
  • examples/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withprompushgateway/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/dockers/data/config.json
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
  • plugins/compat/main.go
  • tests/governance/config.json
  • tests/integrations/python/config.json
  • tests/integrations/typescript/config.json
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/plugins.go
  • transports/config.schema.json
  • transports/go.mod
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • ui/components/ui/accordion.tsx
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (3)
  • .github/workflows/configs/withpostgresmcpclientsinconfig/config.json
  • examples/configs/withvirtualkeys/config.json
  • examples/configs/withpostgresmcpclientsinconfig/config.json
✅ Files skipped from review due to trivial changes (11)
  • examples/dockers/data/config.json
  • .github/workflows/scripts/test-docker-image.sh
  • examples/configs/withprompushgateway/config.json
  • tests/governance/config.json
  • docs/providers/supported-providers/overview.mdx
  • transports/bifrost-http/server/plugins.go
  • tests/integrations/typescript/config.json
  • tests/integrations/python/config.json
  • docs/openapi/schemas/management/config.yaml
  • docs/openapi/openapi.json
  • .github/workflows/scripts/run-migration-tests.sh
🚧 Files skipped from review as they are similar to previous changes (10)
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • helm-charts/bifrost/values.yaml
  • transports/bifrost-http/lib/config.go
  • transports/go.mod
  • framework/configstore/clientconfig.go
  • helm-charts/bifrost/values.schema.json
  • plugins/compat/main.go
  • transports/bifrost-http/handlers/config.go
  • ui/app/workspace/config/views/clientSettingsView.tsx
  • transports/bifrost-http/lib/config_test.go

@sammaji sammaji force-pushed the 03-12-fix_conversions_for_litellm_compat_to_happen_at_the_provider_level branch from 6a6d436 to dff3960 Compare April 9, 2026 19:20
@sammaji sammaji force-pushed the 03-24-feat_removes_enable_litellm_fallback_option_for_more_granular_settings branch from 05c065e to c4b8a62 Compare April 9, 2026 19:20
@sammaji sammaji closed this Apr 9, 2026
Comment on lines +6119 to +6121
if err := tx.Exec("UPDATE config_client SET compat_should_convert_params = TRUE").Error; err != nil {
return err
}
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.

P1 should_convert_params silently activated for all existing deployments

The unconditional UPDATE sets compat_should_convert_params = TRUE for every row in config_client — not just those where enable_litellm_fallbacks was true. Because the startup check in plugins.go line 220 is cc.ConvertTextToChat || ... || cc.ShouldConvertParams, this causes the compat plugin to be loaded for all existing deployments after the migration, even ones that never had enable_litellm_fallbacks: true.

The concrete effect: applyParameterConversion (specifically normalizeDeveloperRoleForChatRequest) will now run for every Bedrock, Vertex, and Gemini request that uses role: "developer", silently converting it to role: "system". This is an undisclosed behavior change for users who opted out of LiteLLM compat. The PR description states "the migration preserves existing behavior", which is inaccurate for this flag.

To preserve the prior opt-out semantics, the backfill should be scoped to rows that already had enable_litellm_fallbacks = true:

// Only enable ShouldConvertParams for rows that had enable_litellm_fallbacks = true,
// preserving the no-op behavior for deployments that never opted in.
if mig.HasColumn(&tables.TableClientConfig{}, "enable_litellm_fallbacks") {
    if err := tx.Exec("UPDATE config_client SET compat_should_convert_params = enable_litellm_fallbacks").Error; err != nil {
        return err
    }
} else {
    // Column was already removed (re-entrant migration run) — leave as-is.
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants