Conversation
|
|
📝 WalkthroughWalkthroughPreserve repeated multipart text fields as strings or aggregated []string; emit each []string element as its own multipart field; avoid duplicate writes during reconstruction; parse multipart ChangesFallback Handling in Transcription
🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
4f9b225 to
43029b7
Compare
Confidence Score: 5/5The changes are narrowly scoped to transcription multipart handling and do not touch inference routing, pooled objects, or provider converters; the logic is straightforward and correct across all traced governance + multipart round-trip paths. All three files change in a consistent, complementary way: the serialization layer, reconstruction layer, and handler all now agree on how multi-value form fields are represented. No new shared state, no concurrency surface, and no provider interface changes. core/network/multipart_test.go — the new ParseMultipartFormFields aggregation path and ReconstructMultipartBody []string dedup path are not directly exercised by any test case. Important Files Changed
Reviews (4): Last reviewed commit: "fix: include fallbacks when preparing tr..." | Re-trigger Greptile |
43029b7 to
f459b4c
Compare
f459b4c to
d0d91d4
Compare
|
I got rid of the JSON encoding of It looks like nothing else was using this other than |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
core/network/multipart_test.go (1)
223-241: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winAdd a regression test for repeated-field reconstruction (dedupe + order preservation).
This test covers write/parse, but the new
ReconstructMultipartBodyduplicate-skip logic is still untested for repeated keys (the critical fallback path). Please add a case that starts with repeatedfallbacks, reconstructs with payload overrides, and asserts no duplicated entries and stable order.As per coding guidelines, “Apply standard Go review practices: … deterministic tests, and table-driven coverage for behavior changes.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/network/multipart_test.go` around lines 223 - 241, The test suite is missing coverage for ReconstructMultipartBody's duplicate-skip fallback path for repeated keys; add a deterministic test that writes an initial multipart body containing repeated field "fallbacks" (e.g., ["f1","f2","f2","f3"]), then call ReconstructMultipartBody with payload overrides that replace some entries, parse the reconstructed body (using ParseMultipartFormFields) and assert that the resulting "fallbacks" has no duplicated values and preserves the intended order (stable ordering after dedupe), and include this as a new table-driven case alongside the existing Test that exercises WriteMultipartField and ParseMultipartFormFields so regressions in ReconstructMultipartBody are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@core/network/multipart_test.go`:
- Around line 223-241: The test suite is missing coverage for
ReconstructMultipartBody's duplicate-skip fallback path for repeated keys; add a
deterministic test that writes an initial multipart body containing repeated
field "fallbacks" (e.g., ["f1","f2","f2","f3"]), then call
ReconstructMultipartBody with payload overrides that replace some entries, parse
the reconstructed body (using ParseMultipartFormFields) and assert that the
resulting "fallbacks" has no duplicated values and preserves the intended order
(stable ordering after dedupe), and include this as a new table-driven case
alongside the existing Test that exercises WriteMultipartField and
ParseMultipartFormFields so regressions in ReconstructMultipartBody are caught.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: f0ffba43-c543-43ef-92c4-474d3f4672bd
📒 Files selected for processing (3)
core/network/multipart.gocore/network/multipart_test.gotransports/bifrost-http/handlers/inference.go
…on rankings chart (maximhq#3950) ## Summary Y-axis labels in the dimension rankings bar chart were taking up too much horizontal space and could overflow without truncation. This PR truncates long dimension names in the chart's Y-axis labels and adds a tooltip `<title>` element so users can still see the full name on hover. ## Changes - Y-axis labels longer than 14 characters are now truncated with an ellipsis (`…`), with the full value exposed via an SVG `<title>` for accessibility and hover visibility - Y-axis width reduced from `110` to `92` to match the shorter label space - Left margin reduced from `4` to `0` to reclaim horizontal space ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test Navigate to the workspace dashboard and open the Dimension Rankings tab. Find a dimension with a long name (more than 14 characters) and verify: 1. The label is truncated with an ellipsis in the chart 2. Hovering over the label shows the full name via the browser's native tooltip ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings Add before/after screenshots showing the truncated Y-axis labels vs. the previous full-length labels. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Style** - Improved dimension ranking chart layout with optimized spacing - Long category labels now display with ellipsis truncation for better readability, with full text visible on hover <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…le (maximhq#3952) ## Summary Fixes layout issues in the `HeadersTable` component where columns were not properly constrained, causing inconsistent sizing of the Name, Value, and Actions columns. ## Changes - Applied `table-fixed` layout to the table to enforce column width constraints - Set the Name column to a fixed width of 40% to ensure consistent proportions between Name and Value columns - Reduced the Actions column width from `w-12` to `w-10` and removed excess padding (`p-0`) to tighten the delete button column - Removed padding from the Actions cell to better align the delete button within its column ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test Navigate to any view that renders the `HeadersTable` component (e.g., a request headers configuration panel) and verify: 1. The Name and Value columns maintain consistent proportions as rows are added or removed. 2. The Actions (delete) column remains compact and does not expand unexpectedly. 3. Long header names or values do not cause the table layout to shift. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings Add before/after screenshots showing the corrected column widths in the headers table. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Style** * Implemented fixed table layout to ensure consistent column widths and improved visual stability. * Refined header and action column sizing for better alignment and visual consistency. * Optimized spacing in the actions column for improved usability of row control buttons. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
`StaleConnectionRetryIfErr` was not retrying on several real-world connection-closure errors because it relied on direct equality checks (`err == io.EOF`) and a fixed set of string patterns. Wrapped errors (e.g. `fmt.Errorf("read response: %w", io.EOF)`) were silently falling through without a retry, and error strings like `"use of closed network connection"` and `"server closed connection"` were not covered.
## Changes
- Replaced `err == io.EOF` with `errors.Is(err, io.EOF)` so wrapped EOF errors are correctly detected.
- Added `errors.Is(err, io.ErrUnexpectedEOF)` to handle unexpected EOF variants.
- Added string match patterns for `"use of closed network connection"` and `"server closed connection"` to cover additional OS- and fasthttp-level connection closure signals.
- Added an early-exit guard for `fasthttp.ErrConnectionClosed` to avoid retrying when fasthttp has already handled the error post-loop.
- Switched `err.Error()` to `strings.ToLower(err.Error())` for case-insensitive string matching consistency.
- Added corresponding test cases for wrapped `io.EOF`, `io.ErrUnexpectedEOF`, wrapped `io.ErrUnexpectedEOF`, `"use of closed network connection"`, and `"server closed connection"`.
## Type of change
- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI
## Affected areas
- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs
## How to test
```sh
go test ./core/network/... -v -run TestStaleConnectionRetryIfErr
```
All existing and new test cases should pass, including the wrapped EOF and new connection-closure string variants.
## Breaking changes
- [ ] Yes
- [x] No
## Related issues
## Security considerations
None. This change only affects retry logic for stale HTTP connections and does not touch authentication, secrets, or PII handling.
## Checklist
- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved HTTP client resilience by expanding retry behavior to handle a broader set of EOF and connection-closed scenarios.
* **Tests**
* Expanded test coverage to validate additional EOF, wrapped-EOF, and server-closure cases.
* **Chores**
* Minor formatting adjustment to an example configuration file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Introduces a `source_of_truth` field to `config.json` that allows operators to make config.json sections authoritative during startup reconciliation. When set to `"config.json"`, any section explicitly present in the file becomes the single source of truth — database-only rows for that section are pruned. When omitted or set to `"split"` (the default), existing merge behavior is preserved.
## Changes
- Added `source_of_truth` field to `ConfigData` with two modes: `"split"` (default, existing behavior) and `"config.json"` (file-authoritative).
- Added `presentSections` and `presentGovernanceSections` tracking maps populated during `UnmarshalJSON` so that explicitly-present-but-empty sections (e.g., `"providers": {}`) can be distinguished from absent sections.
- Added `sectionPresent` and `governanceSectionPresent` helpers on `ConfigData` to query section presence.
- Introduced `syncAuthoritativeProvidersInStore` which, under `config.json` mode, deletes DB-only providers and DB-only keys within kept providers inside a single transaction.
- Introduced `processAuthoritativeProvider` as the authoritative counterpart to `processProvider`, preserving runtime-only fields (status, description) from the DB while making the file's key list canonical.
- Introduced `syncMCPConfigFromFile` which replaces stored MCP clients with exactly those declared in config.json, deleting DB-only clients and upserting file clients.
- Introduced `syncPluginsFromFile` which replaces stored plugins with exactly those declared in config.json, deleting DB-only plugins and upserting file plugins within a transaction.
- Introduced `pruneGovernanceConfigToFile` which, after the normal governance merge, removes DB-only rows for each governance collection that was explicitly present in the file (virtual keys, routing rules, pricing overrides, model configs, teams, customers, providers, budgets, rate limits).
- Added `source_of_truth` to `config.schema.json` as an enum of `["split", "config.json"]` with schema validation.
- Added a schema candidate path for tests running from `transports/bifrost-http/lib/`.
- Fixed `MockConfigStore.DeleteMCPClientConfig` and `DeletePlugin` to actually remove entries so sync tests can assert on store state.
## Type of change
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI
## Affected areas
- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [ ] UI (React)
- [ ] Docs
## How to test
```sh
go test ./transports/bifrost-http/lib/... -run TestConfigDataSourceOfTruth
go test ./transports/bifrost-http/lib/... -run TestSourceOfTruthConfigJSON
go test ./transports/bifrost-http/lib/... -run TestSQLite_SourceOfTruthConfigJSON
go test ./transports/bifrost-http/lib/... -run TestConfigSchemaSourceOfTruthValidation
go test ./transports/bifrost-http/lib/...
```
**New `config.json` field:**
| Field | Type | Values | Default |
|---|---|---|---|
| `source_of_truth` | `string` | `"split"`, `"config.json"` | `"split"` |
To enable authoritative mode, add to `config.json`:
```json
{
"source_of_truth": "config.json",
"providers": { ... },
"governance": { "budgets": [...] }
}
```
Only sections explicitly present in the file will be pruned in the database. Sections omitted from the file leave database rows untouched regardless of mode.
## Breaking changes
- [ ] Yes
- [x] No
Default behavior (`"split"`) is unchanged. Operators must explicitly opt in to `"config.json"` mode.
## Related issues
## Security considerations
Provider API keys that exist only in the database will be permanently deleted when `source_of_truth: "config.json"` is set and the `providers` section is present in the file. Operators should ensure all required keys are declared in config.json before enabling this mode.
## Checklist
- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
This PR closes a DNS rebinding vulnerability that existed between the time `ValidateExternalURL` validated a URL and the time the HTTP client actually opened a TCP connection. An attacker could exploit this window by having a hostname resolve to a public IP during validation and then to a private/internal IP at dial time, bypassing SSRF protections. - Extracted `IsLocalhost` and `IsPrivateIP` into a new `core/network` package so they can be shared across validation and dialing layers. - Updated `ConfigureDialer` to perform its own DNS resolution at dial time, reject any resolved private or loopback IPs, and dial the resolved IP literal directly — eliminating the TOCTOU window between URL validation and connection. - Added `ValidateExternalURL` calls in the HTTP transport's `addProvider` and `updateProvider` handlers to reject private or loopback `BaseURL` values at the API boundary. - Added `core/utils_test.go` with comprehensive tests covering `ValidateExternalURL`, `IsLocalhost`, and `IsPrivateIP`, including RFC 1918 ranges, link-local addresses, the AWS metadata endpoint (`169.254.169.254`), IPv6 private ranges, and query-parameter injection vectors. - [x] Bug fix - [x] Core (Go) - [x] Transports (HTTP) - [x] Providers/Integrations ```sh go version go test ./... ``` Key scenarios validated by the test suite: - `http://169.254.169.254/latest/meta-data/` → rejected as private IP - `http://10.0.0.1/path?x=` → rejected as private IP - `http://localhost:8080` → rejected as loopback - `https://api.openai.com` → allowed - IPv6 loopback (`::1`), link-local (`fe80::1`), and unique-local (`fc00::/7`) → all rejected - [ ] Yes - [x] No This change directly addresses an SSRF / DNS rebinding attack vector. Previously, a malicious actor could register a hostname that resolved to a public IP during `ValidateExternalURL` and then switch the DNS record to an internal address (e.g., `169.254.169.254`, `10.x.x.x`) before the dialer connected. The dialer now resolves DNS independently, validates every returned IP against private ranges, and dials the IP literal, closing this window entirely. The `BaseURL` field on provider add/update endpoints is also now validated at the API layer. - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> * **Security Improvements** * Strengthened SSRF protections: centralized hostname/IP checks now block localhost, link-local, unspecified, and private IPs when validating external URLs and provider Base URLs. * Provider create/update endpoints validate Base URLs and return clear Bad Request responses for unsafe targets. * Network dialing now resolves hosts and rejects disallowed/private addresses early to prevent unsafe connections. * **Tests** * Added extensive unit tests for URL validation, network address classification, and dialer SSRF behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Some OpenAI-compatible backends return valid SSE frames without a `Content-Type: text/event-stream` header. The previous `DrainNonSSEStreamResponse` helper would unconditionally drain and discard the response body in this case, causing the downstream SSE parser to receive an empty stream. This PR introduces a reader-preserving variant that peeks at the first bytes of the stream to detect SSE field prefixes (`data:`, `event:`, `id:`, `retry:`, `:`, or leading newlines) before deciding whether to drain or pass the reader through intact. ## Changes - Introduced `DrainNonSSEStreamReader(resp, reader)` which accepts an `io.Reader` (e.g. a decompressed stream) and returns a potentially buffered reader alongside a `drained` boolean, preserving the stream when it looks like SSE even if the content type header is absent. - `DrainNonSSEStreamResponse` is retained as a thin wrapper delegating to `DrainNonSSEStreamReader` for backward compatibility. - All streaming handlers in the OpenAI provider (`text completion`, `chat completion`, `responses`, `speech`, `transcription`, `image generation`, `image edit`) now use `DrainNonSSEStreamReader` and reassign the reader from its return value so the buffered peek bytes are not lost. - Added `looksLikeSSEPrefix` to perform a case-sensitive, 16-byte peek-based heuristic for SSE field prefixes. - Added tests covering: SSE without content type remains readable, gzip-compressed SSE without content type remains readable, JSON without content type is drained, and uppercase SSE-like prefixes are treated as non-SSE. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/utils/... -run TestDrainNonSSEStreamReader go test ./... ``` Expected: all new `TestDrainNonSSEStreamReader_*` tests pass, and existing streaming tests remain green. To validate end-to-end, route a streaming request through a backend that returns SSE without `Content-Type: text/event-stream` and confirm the response is streamed correctly rather than returning an error. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. The peek reads at most 16 bytes from the stream and does not log or expose any content. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved streaming across text, chat, responses, speech, transcription, image generation and edit flows to detect SSE-like streams, avoid prematurely draining them, and prevent stream hangs or unexpected termination. * **Tests** * Added and updated unit tests for SSE detection, compressed-stream handling, fragmented/tiny-prefix delivery, and correct draining behavior for non-SSE payloads. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Fixes a security vulnerability where provider API key headers injected by Bifrost upstream were being echoed back to clients in response headers. This was identified as a regression in the `/genai_passthrough` endpoint where `x-goog-api-key` values were leaking to clients (e.g., via Google's file-download 302 redirects). fixes maximhq#3954 ## Changes - Added `x-goog-api-key`, `x-api-key`, and `api-key` to the `providerResponseFilterHeaders` blocklist so they are stripped from upstream responses before being forwarded to clients. - Added a regression test `TestExtractProviderResponseHeaders_StripsProviderSecrets` that verifies all four sensitive headers (`x-goog-api-key`, `x-api-key`, `api-key`, `authorization`) are stripped while benign headers like `x-request-id` are preserved. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/utils/... -run TestExtractProviderResponseHeaders_StripsProviderSecrets -v ``` Expected output: the test passes, confirming that `x-goog-api-key`, `x-api-key`, `api-key`, and `authorization` are absent from the extracted response headers map, and that `x-request-id` is preserved. ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues Regression fix for `x-goog-api-key` leak via `/genai_passthrough`. ## Security considerations This patch closes a credential leak where provider API keys (`x-goog-api-key`, `x-api-key`, `api-key`) injected into upstream requests could be reflected back to end clients in HTTP response headers. Any client receiving these responses prior to this fix may have been exposed to the upstream provider credentials. No new secrets or auth mechanisms are introduced. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [x] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * API key and authentication headers (case-insensitive) are now filtered from provider responses to prevent exposure of sensitive credentials to clients. * Legitimate non-sensitive response headers are preserved to maintain request tracing and debugging. * **Tests** * Added a test that verifies sensitive provider headers are stripped while ensuring benign headers remain intact. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Passthrough requests previously had no usage extraction, meaning cost calculation and token logging were silently skipped for all provider passthrough endpoints. This PR adds per-provider usage extraction for both streaming and non-streaming passthrough responses across OpenAI, Azure, Anthropic, and Gemini, and wires the extracted usage into the pricing, logging, and governance plugins. ## Changes - **New `BifrostPassthroughUsage` schema** added to `schemas/passthrough.go` carrying LLM tokens, image counts, audio chars/seconds, video seconds, and container identifiers — covering every billable endpoint type. - **`PassthroughPath` field** added to `BifrostResponseExtraFields` and `BifrostPassthroughResponse` so the path is available downstream without re-parsing the original request. - **Provider-level usage extractors** introduced as new files: - `core/providers/openai/passthrough_usage.go` — handles chat/completions, responses API, embeddings, speech (TTS), transcription/translation, image generation/edit/variation, video generation, and container creation. - `core/providers/anthropic/passthrough_usage.go` — handles `/messages` (SSE and non-streaming) and legacy `/complete`, including cache token details. - `core/providers/gemini/passthrough_usage.go` — handles `:generateContent`/`:streamGenerateContent` (text, audio, image output modalities), embeddings, Imagen (`:predict`), Veo (`:predictLongRunning`), and the Interactions API. - **Streaming accumulation** updated across all four providers to accumulate the full response body (`accBody`) and call the usage extractor on the final EOF chunk, attaching `PassthroughUsage` to the terminal response. - **`core/providers/utils/passthrough.go`** added with shared SSE parsing helpers (`ScanSSEDataLines`, `LastSSEDataLine`, `LastSSEOrBody`) used by all extractors. - **Pricing integration** (`framework/modelcatalog/pricing.go`): `extractCostInput` now checks `PassthroughResponse.PassthroughUsage` first; `inferPassthroughRequestType` maps usage fields and path to the correct `RequestType`; `passthroughUsageToCostInput` converts the usage struct into the existing `costInput` shape so all existing compute functions apply without modification. - **Logging plugin** (`plugins/logging/main.go`, `operations.go`): passthrough token usage is now applied to log entries via `applyNonStreamingOutputToEntry`, and streaming passthrough cost is computed in `PostLLMHook` when `PassthroughUsage` is present. The `Model` field is now forwarded in `PassthroughLogParams`. - **Governance plugin** (`plugins/governance/main.go`): token usage is read from `PassthroughUsage.LLMUsage` for passthrough responses; `HasUsageData` now also triggers when `cost > 0` so non-token-based billing (images, audio, video) is tracked correctly. - **`content-type` removed** from the provider response header filter list so it is forwarded to callers. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/... ./framework/... ./plugins/... ``` To validate end-to-end: 1. Send a passthrough request to `/v1/chat/completions`, `/v1/images/generations`, `/v1/audio/speech`, and a streaming `/v1/responses` endpoint via each supported provider. 2. Confirm that the log entry for each request contains a non-zero `cost` and populated `token_usage_parsed` (or the appropriate usage field for non-token endpoints). 3. For streaming passthrough, confirm that the final accumulated response includes `PassthroughUsage` and that cost appears in the governance usage tracker. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No new auth surfaces. The `content-type` header is now forwarded from providers to callers, which was previously suppressed — callers should be aware the response content type now reflects the provider's actual content type. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Enhanced passthrough tracking: upstream request path is surfaced and detailed usage metrics (tokens, images, audio, video, container identifiers) are captured and returned for passthrough requests. * Streaming passthroughs now reliably forward raw chunks, observe incremental usage, and emit final usage on completion. * **Improvements** * Pricing and logging now use passthrough usage to improve cost calculation and reporting. * **Tests** * Added comprehensive tests for passthrough usage extraction and streaming across providers. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Enables CodeRabbit auto-reviews on all branches, not just the default branch. ## Changes - Added `base_branches: [".*"]` to the CodeRabbit auto-review configuration so that pull requests targeting any branch are automatically reviewed, rather than only those targeting the default branch. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test Open a pull request targeting a non-default branch and verify that CodeRabbit automatically triggers a review. ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations None. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated automated review configuration to expand branch coverage. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…o team and business unit attribute mappings (maximhq#3974) ## Summary Adds optional `attributeType` and `attributeValue` fields to `attributeTeamMappings` and `attributeBusinessUnitMappings` to enable SCIM provisioning on a per-mapping basis. When these fields are present, a mapping can be matched against either a SCIM User attribute (`attributeType: "user"`) or a SCIM Group displayName (`attributeType: "group"`). ## Changes - Added `attributeType` (enum: `"user"` | `"group"`) and `attributeValue` (string) as optional properties to `attributeTeamMappings` and `attributeBusinessUnitMappings` in both `helm-charts/bifrost/values.schema.json` and `transports/config.schema.json`. - Added inline `description` fields to existing `attribute`, `value`, `team`, and `business_unit` properties for improved schema documentation. - Added commented-out examples in `values.yaml` demonstrating SCIM provisioning via user attribute matching and group displayName matching. - For `attributeType: "group"`, `attributeValue` is always expected to be `"displayName"` and is auto-set accordingly. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test Configure `attributeTeamMappings` or `attributeBusinessUnitMappings` with the new fields and verify schema validation accepts valid inputs and rejects invalid ones (e.g., an `attributeType` value outside `["user", "group"]` or extra properties beyond those declared). ```sh # Validate schema changes go test ./... ``` Example mapping to validate: ```yaml attributeTeamMappings: - attribute: "department" value: "engineering" team: "eng-team" attributeType: "user" attributeValue: "engineering" - attribute: "groups" value: "Engineering" team: "eng-team" attributeType: "group" attributeValue: "displayName" ``` ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No new auth flows or secrets handling introduced. The new fields extend existing JWT claim-to-team/business-unit mapping logic with SCIM provisioning metadata only. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Enhanced team and business-unit attribute mappings with two new optional fields to support SCIM provisioning metadata, enabling more flexible attribute-based provisioning. * **Documentation** * Updated commented configuration examples to illustrate the new SCIM attribute/type/value mapping patterns. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary When forwarding raw request bodies to Azure-hosted Anthropic models, the `diagnostics` field (used by Claude Code) is not supported by Azure's API and causes request failures. This PR strips the `diagnostics` field from raw request bodies when the target provider is Azure. ## Changes - `StripUnsupportedFieldsFromRawBody` in `utils.go` now removes the `diagnostics` field from the raw JSON body when the provider is Azure. - A new test case `azure_strips_claude_code_diagnostics` verifies that the `diagnostics` field is removed and that the model is correctly rewritten to the Azure deployment name when using raw request bodies. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/anthropic/... ``` The new test `azure_strips_claude_code_diagnostics` confirms that a raw request body containing a `diagnostics` field is sanitized before being sent to Azure, and that the Azure deployment name is correctly substituted as the model value. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No security implications. This change only removes a non-sensitive, provider-incompatible field from outbound requests. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Azure Anthropic requests now strip an unsupported diagnostics field so deployments accept requests while preserving model selection. * **New Features** * Diagnostics data is preserved for the Anthropic provider when the provider supports it. * **Tests** * Added tests confirming diagnostics are kept for Anthropic and removed for other providers, and that Azure payloads have unsupported fields removed. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary When a virtual key has provider constraints (but no weights), the governance plugin now propagates the list of allowed providers into the Bifrost context. The router then intersects that list with the model catalog's provider list, ensuring that only providers permitted by the virtual key are considered for routing and fallbacks. ## Changes - The governance plugin sets `BifrostContextKeyAvailableProviders` on the context after filtering provider configs, including setting an empty slice when no provider configs exist or when no providers pass the model filter. - The router's `createHandler` intersects the catalog-derived provider list with any pre-existing `BifrostContextKeyAvailableProviders` value set by upstream plugins (e.g., governance). If the intersection is empty, an empty provider list is stored rather than falling back to the full catalog set. - `extractAndParseFallbacks` now accepts a `BifrostContext` and filters parsed fallbacks to only those whose provider appears in `BifrostContextKeyAvailableProviders`. If all fallbacks are filtered out, the fallback list on the request is explicitly cleared to `nil`. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins ## How to test ```sh go test ./plugins/governance/... go test ./transports/bifrost-http/integrations/... ``` - A virtual key with `openai/gpt-4o` and `anthropic/claude-3-5-sonnet` provider configs (no weights) and a request for `gpt-4o` should result in `BifrostContextKeyAvailableProviders` containing only `openai`. - A virtual key with only `openai/gpt-4o` and a request for `claude-3-5-sonnet` should result in an empty `BifrostContextKeyAvailableProviders`. - A request with fallbacks that include providers not in the allowed list should have those fallbacks stripped before the request is dispatched. ## Breaking changes - [ ] Yes - [x] No ## Related issues Closes maximhq#2516 ## Security considerations Provider constraints enforced by virtual keys are now respected end-to-end through routing and fallback resolution, preventing requests from being routed to providers that the virtual key does not permit. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Tests** * Added comprehensive test coverage for governance HTTP transport pre-hook with provider-constrained virtual keys. * Added router tests verifying proper provider constraint enforcement during request handling. * **Bug Fixes** * Router now correctly respects provider availability constraints when selecting providers for requests. * Fallback extraction now filters to only providers permitted by governance constraints. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…3930) ## Summary When a routing layer selects a specific provider, `CheckAndSetDefaultProvider` was ignoring that selection and falling back to the route's default provider. This PR ensures that a routing-resolved provider takes precedence over the default, as long as it is still within the allowed set of available providers. ## Changes - Added a new context key `BifrostContextKeyResolvedProvider` to carry the provider selected by the routing layer. - Updated `CheckAndSetDefaultProvider` to check for a resolved provider in context and return it immediately if it is present in the available providers list, before falling back to the default provider check. - Added two tests: one verifying the resolved provider is used when allowed, and one verifying it is ignored when not in the available providers list. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/utils/... -run TestCheckAndSetDefaultProvider ``` Expected: both `TestCheckAndSetDefaultProviderUsesResolvedProvider` and `TestCheckAndSetDefaultProviderIgnoresDisallowedResolvedProvider` pass. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations The resolved provider context key is explicitly marked `DO NOT SET THIS MANUALLY` and is only populated by the routing layer. It cannot be used to bypass available-provider constraints, as the check enforces membership in the allowed list before honoring the resolved provider. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Improvements** * Enhanced provider selection logic to better utilize routing-determined providers when available. * Improved fallback behavior for provider resolution in routing scenarios. * **Tests** * Added test coverage for provider selection scenarios with and without routing-resolved providers. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Adds support for `file` content blocks in chat message logs. Users can now view file metadata and download attached files directly from the log detail view. ## Changes - Added a `file` content type and corresponding `file` field to the `ContentBlock` type in `logs.ts`, enabling the frontend to parse file blocks from message content - Introduced `LogChatFileBlockView`, a new exported component that renders file block metadata (filename, type, size, file ID) and provides a download button when inline file data is available - Integrated `LogChatFileBlockView` into `ContentBlockView` to handle `file`-typed content blocks in the general message view - Rendered attached file blocks in `logDetailView.tsx` alongside image attachments when a message contains `file`-typed content - Exposed `EnqueueLogEntry` as a public method on `LoggerPlugin` to allow external callers to push complete log entries through the plugin's async write queue ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Send a request that includes a `file` content block in a chat message (e.g., using the Files API with an inline `file_data` payload or a `file_id` reference). 2. Open the log detail view for that request. 3. Verify the file block is rendered with its filename, type, size, and file ID. 4. If `file_data` is present, click **Download** and confirm the file downloads correctly. 5. If `file_url` is present, confirm the **Open file** link is rendered and navigates correctly. ```sh # UI cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings _Add before/after screenshots showing the file block rendered in the log detail view._ ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations Inline `file_data` is base64-encoded and decoded entirely in the browser before being offered as a download. No file data is sent to any external endpoint. Care should be taken to ensure that `file_data` in logs does not inadvertently expose sensitive content to unauthorized users viewing logs. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * File content blocks are now rendered and viewable within message histories * Files attached to messages can be downloaded directly from log entries * File details including name, type, and size are displayed alongside message content <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary When replaying reasoning items through the OpenAI Responses API (e.g. Codex/GPT-5.5), the `content` field on a reasoning message can arrive as a string (notably an empty `""` after round-tripping). OpenAI types `reasoning.content` as an array of `reasoning_text` blocks and rejects a string value with `"expected an array ... got a string"`. This fix normalizes string content on outbound reasoning messages: empty strings are dropped entirely, and non-empty strings are promoted to a `reasoning_text` block. ## Changes - In `ToOpenAIResponsesRequest`, when a reasoning message has `Content.ContentStr` set, the string is either dropped (if empty) or converted to a `ResponsesMessageContentBlock` with type `reasoning_text` (if non-empty). The reassignment operates on the local value copy to avoid mutating the caller's input. - Tests cover both the empty-string drop case (including a marshal check to ensure `"content":""` never appears in the serialized output) and the non-empty string promotion case. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/openai/... -run TestToOpenAIResponsesRequest_ReasoningStringContent -v ``` Expected: both subtests (`empty string content is dropped` and `non-empty string content becomes a reasoning_text block`) pass, and the marshalled output does not contain `"content":""` on any reasoning item. ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations No auth, secrets, or PII implications. The fix only affects how reasoning message content is serialized before being sent to the OpenAI API. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Bug Fixes** * Fixed handling of reasoning message content when formatted as strings in OpenAI responses * Fixed JSON serialization of empty content fields to ensure API compliance * **Chores** * Updated Go module dependencies across core, framework, and plugin packages for performance and security improvements * **Tests** * Added test coverage for reasoning content normalization and empty content marshaling <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary OpenAI's Responses API rejects requests containing a `summary` field on compaction input items with an "Unknown parameter" error. Because Bifrost has no dedicated compaction item model, `encrypted_content` is carried via the embedded `*ResponsesReasoning` struct, which re-injects `"summary": null` during marshaling due to the absence of `omitempty`. This PR strips the `summary` field from compaction items post-serialization while leaving it intact on reasoning items, where it is required by OpenAI. ## Changes - Added `ResponsesMessageTypeCompaction` constant to the `ResponsesMessageType` enum. - Introduced `stripCompactionItemSummary`, which uses `sjson.DeleteBytes` to remove the `summary` key from any serialized item whose type is `compaction`. - Wired `stripCompactionItemSummary` into both marshaling paths inside `OpenAIResponsesRequestInput.MarshalJSON` (the fast path and the `CacheControl` copy path). - Added `github.com/tidwall/sjson` as a dependency for targeted JSON key deletion without full re-deserialization. - Added `TestOpenAIResponsesRequest_MarshalJSON_CompactionSummaryStripped` to verify that compaction items have `summary` removed and `encrypted_content` retained, while sibling reasoning items keep their `summary` array. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/openai/... -run TestOpenAIResponsesRequest_MarshalJSON_CompactionSummaryStripped -v go test ./... ``` The new test asserts: - Index 0 (compaction item): no `summary` key present, `encrypted_content` key present. - Index 1 (reasoning item): `summary` key present with value `[]`. ## Breaking changes - [x] No ## Security considerations No auth, secrets, or PII implications. The change only affects JSON serialization of compaction items before they are sent to the OpenAI API. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
* azure dignotstic property strip for claude models * restrict fallbacks and provider selection to vk boundry * capture resolved provider from the loadbalancer for logging * logs adds support for rendering file attachments * Update logChatMessageView.tsx * openai integration content string handling * handles compaction message type * coderabbit yml changes --------- Signed-off-by: Akshay Deo <akshay@akshaydeo.com>
Add client_id, client_secret, tenant_id, and scopes to the azure_key_config object in values.schema.json. These fields exist in the Go AzureKeyConfig struct (core/schemas/account.go) but were missing from the Helm chart schema, causing schema validation to reject valid azure_key_config configurations. Fixes maximhq#3990
…bility plugins with wildcard support (maximhq#4012) ## Summary Observability plugins (OTel and Maxim) can now opt into capturing specific incoming request headers and attaching them to traces/spans as attributes or tags. Header capture is entirely opt-in and gated so there is zero overhead when no plugin requests it. ## Changes - Added `MatchHeaderPattern` and `FilterHeaders` helpers to `core/schemas/headers.go` supporting exact names, trailing wildcards (`x-custom-*`), and the bare wildcard (`*`). The local duplicate in the logging plugin was removed in favour of the shared implementation. - Added `RequestHeaders map[string]string` to `schemas.Trace`, with a thread-safe `SetRequestHeaders` setter and proper `Reset` clearing. - Added `SetRequestHeaders` to `TraceStore` and three new methods to `Tracer`: `ShouldCaptureRequestHeaders`, `CollectRequestHeaderPatterns`, and `SetTraceRequestHeaders`. These derive live state from the stored plugins so no separate flag needs to be kept in sync. - The HTTP tracing middleware now captures and lowercases all request headers onto the trace when `ShouldCaptureRequestHeaders` returns true, keeping the hot path free of allocation when no plugin opts in. - The OTel plugin gains a per-profile `request_headers` config field. `RequestHeaderPatterns` satisfies the new interface the tracer checks. At conversion time, `convertTraceToResourceSpan` filters the trace's captured headers to the profile's own patterns and emits them as `http.request.header.<name>` span attributes on the root span. - The Maxim plugin gains a `request_headers` config field. In `PostLLMHook`, matched headers are forwarded as `header.<name>` tags on both the generation and the trace. - UI forms for both OTel and Maxim expose a textarea for entering comma-separated header patterns, with inline documentation warning that `*` will capture sensitive headers such as `Authorization`. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh # Core/Transports go test ./core/schemas/... ./framework/tracing/... ./plugins/otel/... ./plugins/maxim/... ./plugins/logging/... # UI cd ui pnpm i pnpm build ``` **OTel:** Add `"request_headers": ["x-tenant-id", "x-custom-*"]` to an OTel profile config, send a request with those headers, and verify the root span contains `http.request.header.x-tenant-id` (and any `x-custom-*` matches) as attributes. **Maxim:** Add `"request_headers": ["x-tenant-id"]` to the Maxim config, send a request, and verify the generation and trace in Maxim carry a `header.x-tenant-id` tag. **No-op path:** With no `request_headers` configured on any plugin, confirm `ShouldCaptureRequestHeaders` returns false and no header iteration occurs in the middleware. ## Breaking changes - [ ] Yes - [x] No ## Security considerations The `*` wildcard pattern will capture all headers, including `Authorization` and other credential-bearing headers. This is documented in the UI form descriptions and in code comments. Users should configure patterns as narrowly as possible. Captured headers are stored in-memory on the trace object and forwarded only to the observability backends the user has explicitly configured. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes **New Features** - Added request header capture capability with pattern-based filtering (exact match and wildcard support) - Maxim plugin now supports configuring which request headers to capture and attach as trace tags - OTEL plugin now supports per-profile configuration for emitting request headers as span attributes - UI forms now include configurable request header patterns for both Maxim and OTEL observability plugins -⚠️ Warning: Wildcard (`*`) pattern includes sensitive headers like Authorization <!-- end of auto-generated comment: release notes by coderabbit.ai -->
* [docs] : google model armor as guardrail provider docs (maximhq#3660) Briefly explain the purpose of this PR and the problem it solves. - What was changed and why - Any notable design decisions or trade-offs - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Describe the steps to validate this change. Include commands and expected outcomes. ```sh go version go test ./... cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` If adding new configs or environment variables, document them here. If UI changes, add before/after screenshots or short clips. - [ ] Yes - [ ] No If yes, describe impact and migration instructions. Link related issues and discussions. Example: Closes maximhq#123 Note any security implications (auth, secrets, PII, sandboxing, etc.). - [ ] 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 * fix: removes manual setting of type custom for anthropic tools (maximhq#3652) Removes the hardcoded `type: "custom"` field that was being set by default for Anthropic tools during conversion. It is an optional field based on Anthropic docs and with this, can also support Deepseek as custom provider - Removed the automatic assignment of `AnthropicToolTypeCustom` when initializing `AnthropicTool` in `convertBifrostToolToAnthropic`, allowing the tool type to be determined by subsequent logic rather than being overridden at construction time. - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Send a request to the Anthropic provider with tools that are not of the custom type and verify they are correctly passed through without being overridden to `type: "custom"`. ```sh go test ./core/providers/anthropic/... ``` - [ ] Yes - [x] No None. - [ ] 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 * fix: fix ListModels for keyless providers (maximhq#3655) When performing keyless `ListModels` requests, provider implementations were passing an empty `schemas.Key{}`, which caused model filtering to behave incorrectly — returning no models instead of all available models. This fix ensures keyless requests use a wildcard whitelist so all models are returned as expected. - Replaced `schemas.Key{}` with `schemas.Key{Models: schemas.WhiteList{"*"}}` in the keyless `ListModels` path for Anthropic, Cohere, Gemini, HuggingFace, and OpenAI providers. - The wildcard `"*"` entry signals that all models should be allowed through the whitelist filter, matching the intended behavior for keyless configurations. - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Call `ListModels` against a provider configured with `IsKeyLess: true` and verify that the response includes the full list of available models rather than an empty result. ```sh go test ./... ``` - [ ] Yes - [x] No - Resolves maximhq#3607 No security implications. The wildcard whitelist only affects model listing behavior in explicitly keyless provider configurations. - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable * feat: preserve time filter params when navigating between sidebar items (maximhq#3647) When navigating between sidebar pages that support time filtering, the selected time range (start/end time or period) is lost. This PR preserves the active time filter parameters when clicking sidebar sub-items, so users don't have to re-select their time range after switching between time-filter-enabled pages. - When navigating from one `TimeFilterPages` page to another via a sidebar sub-item, the current `start_time`, `end_time`, and `period` query parameters are carried over to the destination URL. - If the current or destination page is not in `TimeFilterPages`, navigation behaves as before with no parameter forwarding. - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs 1. Navigate to a page that supports time filtering (e.g., a metrics or logs page). 2. Set a custom time range or period using the time filter. 3. Click a different sidebar sub-item that also supports time filtering. 4. Verify the time range is preserved in the URL and the view reflects the same time window. 5. Navigate to a sidebar sub-item that does **not** support time filtering and verify no time parameters are appended. ```sh cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` N/A - [ ] Yes - [x] No No security implications. Only query parameters already present in the current URL are forwarded. - [ ] 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 * refactor: move auth check from login component to route loader with redirect (maximhq#3648) Auth status checking on the login route was previously handled inside the `LoginView` component using a Redux query, causing a flash of "Checking authentication..." UI within the already-rendered login page. This moves the auth check to a TanStack Router route loader so the redirect to `/workspace` happens before the login page renders, and the pending state is handled cleanly by a dedicated `PendingComponent`. - Moved the `is-auth-enabled` auth check from `LoginView` into the `/login` route loader. If auth is disabled or the user already has a valid token, the loader throws a redirect to `/workspace` before the component mounts. - Removed `useIsAuthEnabledQuery`, the `isCheckingAuth` state, and the inline loading UI from `LoginView`, simplifying the component significantly. - Added a `PendingComponent` to the `/login` route that displays the "Checking authentication..." screen while the loader is in flight, with `pendingMs: 0` to show it immediately. - Added `providesTags: ["Sessions"]` to `useIsAuthEnabledQuery` and updated `login` to `invalidatesTags: ["Sessions"]` so session state is properly invalidated after login. Also added `"Sessions"` to the logout invalidation list. - [x] Refactor - [x] UI (React) 1. Navigate to `/login` while unauthenticated — the "Checking authentication..." pending screen should appear briefly, then the login form should render. 2. Navigate to `/login` while already authenticated (valid session cookie) — you should be immediately redirected to `/workspace` without seeing the login form. 3. Navigate to `/login` when auth is disabled — you should be redirected to `/workspace`. 4. Submit valid credentials on the login form — you should be redirected to `/workspace`. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` - [ ] Yes - [x] No maximhq#3546 The auth check now uses `credentials: "include"` in a plain `fetch` call within the route loader, ensuring the session cookie is sent. If the fetch fails, the login page is shown as a safe fallback rather than silently redirecting. - [ ] 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 * feat: add team and bu filter support for dashboard and logs (maximhq#3650) Briefly explain the purpose of this PR and the problem it solves. - What was changed and why - Any notable design decisions or trade-offs - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Describe the steps to validate this change. Include commands and expected outcomes. ```sh go version go test ./... cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` If adding new configs or environment variables, document them here. If UI changes, add before/after screenshots or short clips. - [ ] Yes - [ ] No If yes, describe impact and migration instructions. Link related issues and discussions. Example: Closes maximhq#123 Note any security implications (auth, secrets, PII, sandboxing, etc.). - [ ] 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 * fix: map vertex trrafic type to bifrost service tier (maximhq#3662) Adds support for Vertex AI's `trafficType` field in `usageMetadata` responses, mapping it to the Bifrost `ServiceTier` abstraction. Previously, only the `serviceTier` field was used, which is specific to the Gemini API. Vertex AI uses a separate `trafficType` field to indicate quota consumption (e.g., on-demand, provisioned throughput). This PR introduces proper handling for both fields and adds a new `provisioned` service tier value. - Introduced a typed `TrafficType` constant set covering `ON_DEMAND`, `ON_DEMAND_PRIORITY`, `ON_DEMAND_FLEX`, and `PROVISIONED_THROUGHPUT` values, replacing the previous untyped `string` field on `GenerateContentResponseUsageMetadata`. - Added `mapGeminiTrafficTypeToBifrost` to convert Vertex AI `trafficType` values to `BifrostServiceTier`, returning `nil` for unrecognised or empty values. - Added `mapBifrostServiceTierToVertexTrafficType` to convert `BifrostServiceTier` back to a Vertex AI `TrafficType` for round-trip serialisation. - Updated `ServiceTier` resolution in chat, responses, and streaming paths to prefer `trafficType` over `serviceTier`, falling back to `serviceTier` when `trafficType` is absent or unrecognised. - When serialising back to Gemini/Vertex format, the provider is now checked: Vertex responses use `trafficType`, while Gemini responses continue to use `serviceTier`. - Added `BifrostServiceTierProvisioned` as a new canonical service tier value. - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ```sh go test ./... ``` - Send a request through the Vertex AI provider and verify that the returned `ServiceTier` reflects the `trafficType` in the response metadata (e.g., `ON_DEMAND` → `default`, `PROVISIONED_THROUGHPUT` → `provisioned`). - Send a request through the standard Gemini provider and verify that `serviceTier` is still used when `trafficType` is absent. - Verify streaming responses also populate `ServiceTier` correctly on the final chunk. - [x] Yes - [ ] No `BifrostServiceTierProvisioned` is a new enum value. Consumers performing exhaustive switches over `BifrostServiceTier` should add a case for `"provisioned"`. None. - [ ] 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 * fix: fixes the start time setting for correct ttft metric value (maximhq#3668) `startTime` was being captured inside the goroutine that processes stream chunks, meaning it reflected the time after the HTTP connection was established rather than when the request was actually initiated. This caused time-to-first-chunk and inter-chunk latency metrics to be measured from an incorrect baseline. - Moved `startTime := time.Now()` to just before the `client.Do(req, resp)` call in every streaming handler across all providers (Anthropic, Azure, Bedrock, Cohere, Gemini, HuggingFace, Mistral, OpenAI, Replicate, vLLM). - `lastChunkTime` is initialized from `startTime` as before, so relative chunk-to-chunk latency calculations are unaffected — only the absolute start anchor is now correct. - [x] Bug fix - [x] Core (Go) - [x] Providers/Integrations Run the full test suite and exercise any streaming endpoint. Verify that reported time-to-first-chunk values now include network round-trip time to the upstream provider rather than starting the clock only after the connection is fully established. ```sh go test ./... ``` - [x] No None. - [ ] 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 * fix: preserve tool call stop reason in Anthropic streaming fallback (maximhq#3640) * Fix Anthropic tool-use stop reason in chat fallback streams * test: assert Anthropic message stop after tool use * feat(governance): add virtual key blocked models (maximhq#3653) Adds blocked model support for virtual key provider configurations. Provider keys already supported both allowed and blocked models, but virtual key provider configs only supported allowed models. This PR adds the missing blocked model flow for virtual keys, so specific models can be denied at the VK provider-config level. * Added `blacklisted_models` to virtual key provider configs. * Added a configstore migration for the new `blacklisted_models` column. * Updated virtual key create/update handlers to validate, persist, and return blocked models. * Added governance checks to reject virtual key requests when the requested model is blocked. * Made blocked models take priority over allowed models. * Updated virtual key model filtering to respect blocked models. * Added `Blocked Models` UI under provider configurations in the virtual key create/edit sheet. * Added blocked model display in the virtual key details sheet. * Updated frontend governance types for virtual key provider configs. This follows the existing provider-key blocked model behavior instead of introducing a separate flow. Behavior: * Empty `blacklisted_models` means no models are blocked. * `["*"]` blocks all models for that VK provider config. * If the same model exists in both allowed and blocked models, the blocked list wins. * [ ] Bug fix * [x] Feature * [ ] Refactor * [ ] Documentation * [ ] Chore/CI * [x] Core (Go) * [x] Transports (HTTP) * [ ] Providers/Integrations * [x] Plugins * [x] UI (React) * [ ] Docs Local UI flow: Start Bifrost locally with embedded UI on port `9090`, then open: `http://localhost:9090/workspace/governance/virtual-keys` Steps tested: 1. Open Virtual Keys. 2. Create or edit a virtual key. 3. Expand a provider config. 4. Confirm `Blocked Models` appears below `Allowed Models`. 5. Select a blocked model and save. 6. Reopen the virtual key and confirm the blocked model is still shown. 7. Refresh the page and confirm the value persists. Runtime validation: 1. Configure a VK provider config with `allowed_models: ["*"]` and `blacklisted_models: ["<model-to-block>"]`. 2. Send a request through that virtual key using the blocked model. Expected: request is rejected. 3. Send a request through the same virtual key using a model not present in `blacklisted_models`. Expected: request succeeds. 4. Configure the same model in both `allowed_models` and `blacklisted_models`. Expected: request is rejected because blocked models take priority. 5. Configure `blacklisted_models: []`. Expected: existing virtual key behavior remains unchanged. Sanity checks: `go test ./framework/configstore/... ./plugins/governance/... ./transports/bifrost-http/handlers/...` UI check: `cd ui && pnpm build` Added a recording showing the new `Blocked Models` field in the virtual key provider configuration flow. https://github.com/user-attachments/assets/64efca01-0366-491c-b9e7-95dfa08eb0bc * [ ] Yes * [x] No BF-896 This change improves virtual-key governance by allowing specific models to be denied for a VK provider config. No provider secrets, customer keys, auth tokens, or PII are exposed or stored by this change. Existing provider-key behavior is unchanged. * [x] I read `docs/contributing/README.md` and followed the guidelines * [ ] I added/updated tests where appropriate * [ ] I updated documentation where needed * [x] I verified builds succeed (Go and UI) * [x] I verified the CI pipeline passes locally if applicable. * table updates (maximhq#3665) UI updates - What was changed and why - Any notable design decisions or trade-offs - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Describe the steps to validate this change. Include commands and expected outcomes. ```sh go version go test ./... cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` If adding new configs or environment variables, document them here. If UI changes, add before/after screenshots or short clips. - [ ] Yes - [ ] No If yes, describe impact and migration instructions. Link related issues and discussions. Example: Closes maximhq#123 Note any security implications (auth, secrets, PII, sandboxing, etc.). - [ ] 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 * Revert "feat: add `access_profile_id` to virtual keys for direct access profile assignment (maximhq#3560)" (maximhq#3669) Briefly explain the purpose of this PR and the problem it solves. - What was changed and why - Any notable design decisions or trade-offs - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Describe the steps to validate this change. Include commands and expected outcomes. ```sh go version go test ./... cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` If adding new configs or environment variables, document them here. If UI changes, add before/after screenshots or short clips. - [ ] Yes - [ ] No If yes, describe impact and migration instructions. Link related issues and discussions. Example: Closes maximhq#123 Note any security implications (auth, secrets, PII, sandboxing, etc.). - [ ] 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 * chore: drop `access_profile_id` column from `governance_virtual_keys` (maximhq#3670) This PR removes the `access_profile_id` column and its associated index from the `governance_virtual_keys` table, reverting the previously applied `migrationAddVKAccessProfileIDColumn` migration. - Added a new migration `migrationDropVKAccessProfileIDColumn` that drops the `idx_governance_virtual_keys_access_profile_id` index and the `access_profile_id` column from `governance_virtual_keys`, if they exist. - Registered the new migration in `triggerMigrations` immediately after the migration that originally added the column, ensuring correct ordering. - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ```sh go test ./... ``` Verify that after running migrations, the `governance_virtual_keys` table no longer contains the `access_profile_id` column or its index. Confirm that the migration runs cleanly on both fresh and existing databases where the column may or may not already be present. N/A - [ ] Yes - [x] No None. This change removes an unused column and index with no impact on authentication, secrets, or PII handling. - [ ] 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 * test: add v1.5.3 migration test coverage for feature flags, temp tokens, OAuth schema refactor, and new columns (maximhq#3671) Extends the migration test script to cover v1.5.3 schema changes, including new tables (`feature_flags`, `temp_tokens`) and new columns added across config store and log store tables. Also refactors the per-user OAuth insert generation to handle both the legacy v1.5.0-prerelease4 schema and the v1.5.3 refactored schema, where `oauth_per_user_*` tables were dropped and `oauth_user_sessions`/`oauth_user_tokens` were restructured. - Added `generate_feature_flags_insert_postgres` and `generate_feature_flags_insert_sqlite` functions to seed the `feature_flags` table introduced in v1.5.3 via `migrationAddFeatureFlagsTable`. - Added `generate_temp_tokens_insert_postgres` and `generate_temp_tokens_insert_sqlite` functions to seed the `temp_tokens` table introduced in v1.5.3 via `migrationAddTempTokensTable`. - Both new insert generators are wired into `append_dynamic_mcp_clients_insert` for both PostgreSQL and SQLite paths. - Added v1.5.3 dynamic column UPDATE blocks for both PostgreSQL and SQLite covering: - `config_client.metadata_json` - `framework_configs.model_parameters_url` and `config_hash` - `governance_teams.source_id` and `calendar_aligned` - `governance_virtual_keys.access_profile_id` - `logs.cluster_node_id`, `budget_ids`, and `rate_limit_ids` - `mcp_tool_logs.user_id`, `team_id`, `customer_id`, and `business_unit_id` - Refactored `generate_per_user_oauth_tables_insert_postgres` and extracted a new `generate_per_user_oauth_tables_insert_sqlite` function. Both now branch on schema version: if `oauth_per_user_clients` exists, the prerelease4 schema is used; if `oauth_user_sessions.session_id` exists, the v1.5.3 refactored schema (using `session_id` + `flow_mode` instead of `session_token`/`gateway_session_id`) is used instead. - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Run the migration test workflow against a deployment that includes v1.5.3 migrations and verify that the test script seeds all new tables and columns without errors. Also run against a pre-v1.5.3 schema to confirm the conditional guards correctly skip missing tables and columns. ```sh bash .github/workflows/scripts/run-migration-tests.sh ``` - [ ] Yes - [x] No Covers migration test coverage for v1.5.3 schema additions. No new secrets or auth flows are introduced. Test data uses placeholder tokens and hashes that are not used in production. - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [x] I verified the CI pipeline passes locally if applicable * adds created_by for virtual keys (maximhq#3672) This PR addresses two independent improvements: preventing reads on already-closed streaming connections, and tracking which user created a virtual key. - Added a `ctx` field to `idleTimeoutReader` so that it can check the `BifrostContextKeyConnectionClosed` flag before attempting a `Read()`. If the connection is already marked as closed, the read returns immediately with `(0, nil)` instead of blocking or erroring. - Added a `CreatedBy` field (`*string`) to `TableVirtualKey` with a database index (`idx_virtual_key_created_by`) to record the creator of each virtual key. - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ```sh go version go test ./... ``` - To validate the idle timeout reader fix: establish a streaming connection, close it, and confirm no further reads are attempted on the closed stream. - To validate the `CreatedBy` field: create a virtual key and confirm the `created_by` column is populated and indexed in the database. N/A - [ ] Yes - [x] No N/A The `CreatedBy` field stores a user identifier on virtual keys. Ensure that this value is not populated with sensitive PII beyond what is already stored in the system, and that access controls on virtual key records remain enforced. - [ ] 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 * fix: ensure toasts remain clickable above modal overlays (maximhq#3674) Fixes an issue where toast notifications were unclickable when a modal was open. Radix UI's `react-remove-scroll` sets `pointer-events: none` on elements outside the modal, which inadvertently blocked interaction with Sonner toasts. - Added a CSS rule to force `pointer-events: auto` on `[data-sonner-toaster]`, ensuring toasts remain interactive even when a modal overlay is active. - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs 1. Open any modal dialog in the UI. 2. Trigger a toast notification while the modal is open. 3. Verify the toast is visible and can be clicked/dismissed without closing the modal first. Before: Toasts displayed behind/blocked by modal overlay and could not be clicked. After: Toasts remain fully interactive while a modal is open. - [ ] Yes - [x] No None. - [ ] 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 * fix: remove save/cancel icons and fix sheet layout growth in routing rule and virtual key sheets (maximhq#3675) Cleans up the routing rule sheet UI by removing icon decorations from action buttons and fixing layout issues where the form content doesn't grow to fill available space in both the routing rule and virtual key sheets. - Removed the `X` and `Save` icons from the Cancel and Save/Update buttons in the routing rule sheet, leaving text-only labels - Added `grow` and `flex flex-col` classes to the routing rule sheet form and its inner container so the form expands to fill the sheet height correctly - Added `grow` to the virtual key sheet's inner content div for consistent layout behavior - Moved the `RbacOperation`, `RbacResource`, and `useRbac` import to be grouped with other non-local imports - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs 1. Open the routing rules sheet (create or edit a rule) and verify the form content fills the full height of the sheet without collapsing. 2. Confirm the Cancel and Save/Update buttons display text only, without icons. 3. Open the virtual key sheet and verify the form content similarly fills the available height. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` Before/after screenshots showing the button label changes and corrected sheet layout are recommended. - [ ] Yes - [x] No None. - [ ] 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 * fix: make virtual keys table fill available height with sticky header and scrollable body (maximhq#3676) Fixes the Virtual Keys table layout so it fills the available viewport height and scrolls internally, rather than causing the entire page to scroll. The table header remains sticky at the top while the body scrolls, and the pinned action column z-indices are corrected to prevent overlap issues. - Converted the outer container to a flex column layout with `grow` and `overflow-hidden` so the table section expands to fill remaining space without overflowing the page. - Added `shrink-0` to the header/toolbar rows so they don't compress when space is constrained. - Made the table container use `min-h-0 grow overflow-hidden` and passed `containerClassName="h-full overflow-auto"` so scrolling is scoped to the table body. - Made `TableHeader` sticky (`sticky top-0 z-20`) with a background so column headers remain visible during vertical scroll. - Adjusted z-index on the pinned right-side `TableHead` to `z-30` (above the sticky header row) and the pinned `TableCell` to `z-20` to maintain correct stacking order. - Reduced pagination text to `text-xs` for visual consistency. - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs 1. Navigate to the Virtual Keys page with enough keys to require scrolling. 2. Verify the page itself does not scroll — only the table body scrolls. 3. Verify the column headers remain visible (sticky) as you scroll down. 4. Verify the pinned actions column on the right does not disappear behind the sticky header. 5. Verify row hover states on the pinned actions cell render correctly. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` Before/after screenshots showing the table scrolling within its container rather than the full page scrolling are recommended. - [ ] Yes - [x] No None. - [ ] 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 * v1.5.4 cut (maximhq#3680) * fix idle timeout panic (maximhq#3677) `idleTimeoutReader` had several correctness issues: the cleanup function could return before an in-flight timer callback finished closing the body stream, panics from the underlying reader during a timeout-triggered close were unhandled, a nil context caused a panic, and a closed connection returned `nil` instead of a meaningful error. - Added a `timerDone` channel and `timerDoneOnce`/`cleanupOnce` guards so that `cleanup()` blocks until any concurrently running timer callback has fully completed, preventing races between cleanup and the idle timeout close path. - Added a `recover()` deferred in `Read()` that catches panics from the underlying reader (e.g. reads on a closed pipe after timeout) and converts them into `ErrStreamIdleTimeout` or `ErrStreamClosed` rather than crashing. - Extracted `connectionClosed()` and `closedReadError()` helpers to centralise nil-context safety and consistent error selection logic. - Changed the connection-closed early-return in `Read()` to return `ErrStreamClosed` instead of `(0, nil)`, giving callers a clear signal. - Introduced `ErrStreamClosed` as a named sentinel error for streams closed by cancellation or cleanup before a read begins. - Added four new tests covering: nil context safety, closed-context returning `ErrStreamClosed`, panic recovery after timeout, and cleanup blocking until the timer callback finishes. - [x] Bug fix - [x] Core (Go) ```sh go test ./core/providers/utils/... -v -race ``` All four new tests should pass, including `TestIdleTimeoutReader_CleanupWaitsForRunningTimerCallback` which validates the synchronisation behaviour under the race detector. - [ ] Yes - [x] No None. The changes are scoped to internal stream lifecycle management with no impact on auth, secrets, or PII handling. - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable * mcp log fingerprinting (maximhq#3678) MCP tool log entries were not being stamped with DAC (Data Access Control) governance ownership fields (`user_id`, `team_id`, `customer_id`, `business_unit_id`) from the request context. This meant MCP logs could not be attributed to the correct organizational entities for governance and auditing purposes. - Introduced `applyMCPGovernanceFieldsToEntry`, a helper that reads governance identity fields from the `BifrostContext` and stamps them onto an `MCPToolLog` entry. - Called this helper in both `PreMCPHook` and `PostMCPHook` so that governance fields are applied regardless of whether the log entry originates from a normal pre/post flow or the post-hook fallback path (where no pending pre-hook entry exists). - Added `assertMCPLogGovernanceFields` as a shared test helper to validate all four governance fields on a log entry. - Extended `TestMCPHooksDeferDBWriteUntilPostHookBatch` to set governance context values and assert they are persisted correctly. - Added `TestPostMCPHookFallbackStampsGovernanceFields` to verify that fallback-created MCP log entries (post-hook only, no prior pre-hook) also carry the correct governance fields. - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ```sh go test ./plugins/logging/... -run TestMCPHooksDeferDBWriteUntilPostHookBatch go test ./plugins/logging/... -run TestPostMCPHookFallbackStampsGovernanceFields go test ./plugins/logging/... ``` Both tests should pass. Verify that after a `PreMCPHook` or `PostMCPHook` call with governance context values set, the resulting `MCPToolLog` entry in the store has non-nil `UserID`, `TeamID`, `CustomerID`, and `BusinessUnitID` matching the values placed in the context. N/A - [ ] Yes - [x] No N/A Governance ownership fields (`user_id`, `team_id`, `customer_id`, `business_unit_id`) are sourced exclusively from the authenticated request context and are only written when non-empty, ensuring no unintended data leakage or field overwriting occurs. - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] 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 * fix: update e2e ui tests (maximhq#3687) Improves E2E test stability for virtual key editing by handling a budget reset dialog that can appear after saving, and marks a known flaky bulk-rotate test as `fixme` until the underlying UI bug is resolved. - Added `preserveBudgetUsageIfPrompted()` helper that detects the `vk-budget-reset-dialog` and clicks the preserve button if it appears after saving a virtual key. This prevents test failures caused by an unexpected dialog interrupting the save flow. - Marked `should bulk rotate selected virtual keys only` as `test.fixme` due to a UI bug where the checkbox selection state resets when the search input filters out a previously selected row. When `bulkRotateVirtualKeys` searches by name to select each key, the first key becomes deselected as the search narrows to the second, resulting in only the last key being rotated. - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Run the virtual keys E2E suite and confirm no failures occur on the save flow due to the budget reset dialog: ```sh cd tests/e2e npx playwright test features/virtual-keys/virtual-keys.spec.ts ``` The bulk rotate test will be skipped (`fixme`) and should not cause CI failures. N/A - [ ] Yes - [x] No N/A None. - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [x] I verified the CI pipeline passes locally if applicable * fix: updates mcp oauth api tests (maximhq#3693) Consolidates the Per User OAuth Postman coverage probes to align with the updated API surface, replacing the old register/authorize/token/consent/upstream endpoints with the new flow-based endpoints (`/api/oauth/per-user/flows/:flowId` and `/api/oauth/per-user/flows/:flowId/start`). - Removed coverage probe requests for `Per User OAuth Register`, `Per User OAuth Authorize`, `Per User OAuth Token`, `Per User OAuth Upstream Authorize`, `Per User Consent VK`, `Per User Consent User ID`, `Per User Consent Skip`, and `Per User Consent Submit` - Added coverage probe requests for `Per User OAuth Flow Detail` (`GET /api/oauth/per-user/flows/coverage-probe-flow`) and `Per User OAuth Flow Start` (`GET /api/oauth/per-user/flows/coverage-probe-flow/start`) - Added `OAuth Callback (Coverage Probe)` to the raw text shapes validation map, replacing the three previously tracked OAuth probe entries - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI - [ ] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs Run the updated Postman collection against a running Bifrost instance and verify that the new flow-based coverage probe requests return expected responses and that the response structure validation passes. - [ ] Yes - [x] No No security implications. These are test coverage probes only. - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [x] I verified the CI pipeline passes locally if applicable * [StepSecurity] Apply security best practices Signed-off-by: StepSecurity Bot <bot@stepsecurity.io> --------- Signed-off-by: StepSecurity Bot <bot@stepsecurity.io> Signed-off-by: Akshay Deo <akshay@akshaydeo.com> Co-authored-by: Madhu Shantan <madhushantangot@gmail.com> Co-authored-by: roroghost17 <roroghost17@gmail.com> Co-authored-by: Suresh Chaudhary <83772622+impoiler@users.noreply.github.com> Co-authored-by: Tejas Ghatte <64637256+TejasGhatte@users.noreply.github.com> Co-authored-by: Nicholas Dunzelman <139033898+dicnunz@users.noreply.github.com> Co-authored-by: Vaibhav Mittal <mittal.shaluatul@gmail.com> Co-authored-by: Akshay Deo <akshay@akshaydeo.com> Co-authored-by: Anuj Parihar <anujparihar@yahoo.com> Co-authored-by: Samyabrata Maji <samyabratamaji334@gmail.com> Co-authored-by: stepsecurity-app[bot] <188008098+stepsecurity-app[bot]@users.noreply.github.com>
…fixes (maximhq#4024) ## Summary Passthrough endpoints (`Passthrough` and `PassthroughStream`) were stripping `Content-Type` from provider response headers before forwarding them to callers. Since passthrough is meant to transparently relay provider responses, `Content-Type` must be preserved so clients can correctly interpret the response body. ## Changes - Introduced `ExtractPassthroughProviderResponseHeaders`, a variant of `ExtractProviderResponseHeaders` that retains `Content-Type` while still filtering out transport-level headers (e.g., `content-encoding`, `transfer-encoding`, `connection`). - Added `content-type` to the `providerResponseFilterHeaders` blocklist used by the standard `ExtractProviderResponseHeaders`, so non-passthrough paths continue to strip it. - Switched all `Passthrough` and `PassthroughStream` implementations across Anthropic, Azure, Gemini, OpenAI, and Vertex providers to use the new `ExtractPassthroughProviderResponseHeaders`. - Updated the `ErrConnectionClosed` retry test expectation to `wantRetry: true` to correctly reflect intended retry behavior. - Replaced deprecated `gemini-2.0-flash` and `gemini-2.0-flash-lite` test harness entries with `gemini-2.5-flash` and `gemini-2.5-flash-lite`, and fixed a copy-paste error in the Azure embedding test path. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/utils/... go test ./... ``` Send a passthrough request to any supported provider and verify that the `Content-Type` header (e.g., `application/json`) is present in the response forwarded by Bifrost. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No security implications. This change only affects which response headers are forwarded to the caller on passthrough paths. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Passthrough responses now consistently preserve Content-Type and forward appropriate response headers across all AI providers, improving downstream compatibility. * **Tests** * Updated test collections with latest Gemini/Vertex model identifiers and corrected Azure embeddings model path. * Added regression tests for passthrough header forwarding and adjusted connection-retry expectations. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/4024?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…t at minimum sync interval (maximhq#4023) ## Summary The sync worker ticker period was set to 1 hour, which created a subtle scheduling bug: when `pricingSyncInterval` is set near the minimum supported value, the few seconds a sync takes to complete causes the next ticker wake-up to land just under the elapsed-time threshold, effectively doubling the actual sync cadence. Reducing the ticker period to 5 minutes ensures the check granularity stays well below the minimum supported `pricingSyncInterval`, preventing ticker drift from defeating the threshold check. ## Changes - Reduced `syncWorkerTickerPeriod` from 1 hour to 5 minutes so that ticker drift (caused by sync execution time) does not push the next wake-up just under the `pricingSyncInterval` threshold and inadvertently double the effective sync interval. - Updated the scheduling model comment to accurately describe the relationship between the ticker period and `pricingSyncInterval`, removing the outdated note that implied the 1-hour ticker was a hard lower bound on sync frequency. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./framework/modelcatalog/... ``` Set `pricingSyncInterval` to a value near `MinimumPricingSyncIntervalSec` and verify that syncs occur at the expected cadence without doubling. ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations None. ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Increased frequency of pricing synchronization checks from hourly intervals to 5-minute intervals, improving update timeliness and overall system reliability across different configurations. * **Documentation** * Updated internal documentation clarifying the pricing synchronization scheduling mechanism and how timing parameters influence sync behavior. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/4023?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
* fix(gemini): accept numeric schema integer constraints Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) * fix(gemini): address schema review feedback Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) * fix(gemini): simplify schema integer parsing
…nsaction support (maximhq#4039) ## Summary `UpdateBudgetUsage` did not support transactional execution, making it impossible to include budget usage updates as part of a larger atomic database operation. This PR adds optional transaction support to bring it in line with other store methods. ## Changes - Added an optional variadic `tx ...*gorm.DB` parameter to `UpdateBudgetUsage` in the `ConfigStore` interface, the `RDBConfigStore` implementation, and the `MockConfigStore` in tests. - When a transaction is provided, the method uses it instead of the default DB connection. ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./... ``` ## Screenshots/Recordings N/A ## Breaking changes - [x] Yes - [ ] No Any code calling `UpdateBudgetUsage` through the `ConfigStore` interface will need to be recompiled. The method signature has changed, though existing call sites that pass no transaction argument will continue to work without modification. ## Related issues N/A ## Security considerations No security implications. This change only affects how the database operation is scoped within a transaction. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved transaction handling in the configuration storage layer to support optional transactional updates for budget usage. * Aligned test mocks with the updated storage interface to ensure consistent behavior during testing. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
d0d91d4 to
37e910f
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
core/network/multipart_test.go (1)
223-240: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAdd a regression test for duplicate-field reconstruction behavior.
Please add a focused case covering
ReconstructMultipartBody’s new duplicate-skip path (Line 97–Line 100 incore/network/multipart.go) to assert payload-backed fields are written once even when the original multipart contains repeated field names.As per coding guidelines, behavior changes in Go should include deterministic test coverage (preferably table-driven).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/network/multipart_test.go` around lines 223 - 240, Add a deterministic unit test (table-driven style) in multipart_test.go that exercises ReconstructMultipartBody’s duplicate-skip path by creating an original multipart with repeated field names where one occurrence is payload-backed (e.g., a file/part with payload metadata) and asserting that after calling ReconstructMultipartBody the reconstructed body contains only a single written instance of that payload-backed field (and other duplicate non-payload fields are preserved or handled as expected); locate helper functions like WriteMultipartField and ParseMultipartFormFields in the test to build the original multipart, call ReconstructMultipartBody, and validate the parsed output contains exactly one entry for the payload-backed field name.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@core/network/multipart_test.go`:
- Around line 223-240: Add a deterministic unit test (table-driven style) in
multipart_test.go that exercises ReconstructMultipartBody’s duplicate-skip path
by creating an original multipart with repeated field names where one occurrence
is payload-backed (e.g., a file/part with payload metadata) and asserting that
after calling ReconstructMultipartBody the reconstructed body contains only a
single written instance of that payload-backed field (and other duplicate
non-payload fields are preserved or handled as expected); locate helper
functions like WriteMultipartField and ParseMultipartFormFields in the test to
build the original multipart, call ReconstructMultipartBody, and validate the
parsed output contains exactly one entry for the payload-backed field name.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: dc1b8bce-51e5-49a8-a8c1-cc15acd36d9f
📒 Files selected for processing (3)
core/network/multipart.gocore/network/multipart_test.gotransports/bifrost-http/handlers/inference.go
💤 Files with no reviewable changes (1)
- transports/bifrost-http/handlers/inference.go
e389df7 to
a65fce4
Compare
fa15f50 to
ca190fc
Compare
ac30a53 to
7c66b20
Compare
44564de to
493bff0
Compare
|
Hi @mmelvin0 — thanks for the contribution! This PR is currently blocked because our CLA bot shows the Contributor License Agreement as not yet signed. Could you sign it here so we can move this forward: https://cla-assistant.io/maximhq/bifrost?pullRequest=4011 Let us know if you run into any issues signing. |
244a01d to
ce1b2a6
Compare
Summary
This fixes an issue where the
fallbacksparameter ignored by transcription endpoints.This affects transcription requests and governance routing rules fallback behavior.
It seems reading the
fallbacksfield was missed when internally preparing a transcription request. It explicitly added by governance/routing rules here and here and implicitly allowed as a form field here.Additionally, there's an impedance mismatch between JSON requests
map[string]anyand multipart/form-datamap[string][]string. Because multiplefallbacksget serialized as a JSON array by WriteMultipartField(), parseFallbacks() doesn't work as intended.Changes
ParseMultipartFormFields()now extracts multiple fields values with the same name to[]stringinstead of only the last one asstring.WriteMultipartField()now encodes[]stringas multiple form values under the same name instead of as JSON.prepareTranscriptionRequest()no longer ignores thefallbacks.Type of change
Affected areas
How to test
I tested this manually with both request-driven (e.g.
curl -F fallback=provider/modeland governance-drive and every combination I could think of for my use cases.Open to guidance as to how to add good tests for this. Current Go unit tests have some failures on clean
devbranch for me.Breaking changes
If you happened to have a transcription endpoint using the fallback feature, it wasn't working before and will start working now.
Related issues
Closes #4005
Checklist
docs/contributing/README.mdand followed the guidelinesSummary by CodeRabbit
Bug Fixes
New Features