Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
|
|
|
…l resolution (#3656) ## Summary Replaces the scattered `oauth2Provider` field and ad-hoc `MCPClientConfig.HttpHeaders()` method with a unified `MCPCredentialStore` interface and a concrete `credstore` package. Previously, credential resolution for MCP tool execution was split across `utils.ResolvePerUserOAuthToken`, `BuildPerUserOAuthHeaders`, `MCPClientConfig.HttpHeaders`, and inline `AuthType` switch statements spread across `toolmanager.go`, `clientmanager.go`, and the Starlark code mode. This made it difficult to add new auth types and caused the per-user OAuth path to be inconsistently handled depending on whether a persistent connection existed. ## Changes - Introduced `schemas.MCPCredentialStore` interface with three methods: `ConnectionHeaders`, `RequestHeaders`, and `RequiresPerCallConnection`. This replaces all direct `AuthType` comparisons and the `oauth2Provider` field throughout the MCP stack. - Created `core/mcp/credstore` package with a `CredStore` dispatcher and four auth-type-specific resolvers: `noneResolver`, `staticHeadersResolver`, `serverOAuthResolver`, and `perUserOAuthResolver`. Each resolver encapsulates the credential logic previously inlined at call sites. - Removed `MCPClientConfig.HttpHeaders()` from `schemas/mcp.go` and replaced all call sites with `credStore.ConnectionHeaders()`. - Removed `utils.ResolvePerUserOAuthToken`, `BuildPerUserOAuthHeaders`, and `identityForMCPAuthMode` from `core/mcp/utils/utils.go`; this logic now lives in `credstore/per_user_oauth.go`. - Renamed `ExecuteToolWithUserToken` to `OpenConnectionAndExecuteTool` and changed its signature to accept `http.Header` instead of a raw access token string, decoupling it from OAuth specifics. - Added `utils.FlattenHeaders` to convert `http.Header` to `map[string]string` for mcp-go transport APIs, and `utils.ExtractFilteredExtras` to isolate the per-request extras path used by `RequestHeaders`. - Replaced `oauth2Provider` fields in `MCPManager`, `ToolsManager`, `StarlarkCodeMode`, and `CodeModeDependencies` with `credStore`/`CredentialStore`. - `NewMCPManager` now defaults to an OAuth-less `CredStore` when `nil` is passed, so tests and callers that don't wire OAuth still get a functional store for static/headers/none auth types. - Connection-time header resolution in `clientmanager.go` now wraps the lifecycle context into a synthetic `BifrostContext` so `CredentialStore` can be invoked uniformly at both connection time and per-call time. ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go version go test ./... ``` Verify that MCP tool execution works end-to-end for all four auth types (`none`, `headers`, `oauth`, `per_user_oauth`). Confirm that per-user OAuth clients still surface `MCPUserOAuthRequiredError` when no token exists, and that shared-connection clients (none, headers, server OAuth) continue to connect and execute tools without regression. ## Breaking changes - [x] Yes - [ ] No `MCPClientConfig.HttpHeaders()` has been removed. Any code calling this method directly must be updated to use `MCPCredentialStore.ConnectionHeaders()` instead. The `NewMCPManager`, `NewToolsManager`, and `NewToolsManagerWithCodeMode` signatures now accept `schemas.MCPCredentialStore` in place of `schemas.OAuth2Provider`. `ExecuteToolWithUserToken` has been renamed to `OpenConnectionAndExecuteTool` with a different signature. ## Security considerations Per-user OAuth token resolution and flow initiation are now fully contained within `credstore/per_user_oauth.go`. The `serverOAuthResolver` preserves the existing token validation (whitespace trimming, control character rejection) from the removed `HttpHeaders` method. No new credential surfaces are introduced; the `RequiresPerCallConnection` predicate ensures per-user credentials are never placed on a shared persistent transport. ## 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
…` and decouple credentials from plugin gate (#3702) ## Summary This PR refactors how MCP client connections are acquired and how credentials are composed for tool execution. The core problem was that the `Authorization` header (and other credentials) were being assembled too early — before the connect-plugin gate ran — meaning plugins could observe or interfere with auth tokens. Additionally, per-user OAuth clients used a separate `OpenConnectionAndExecuteTool` code path that bypassed the plugin pipeline entirely. ## Changes - Introduced `AcquireClientConn` on `MCPManager` and the `ClientManager` interface. This method returns a live upstream connection plus a release function. For shared-connection auth types (none, headers, server OAuth), it returns the persistent `state.Conn` with a no-op release. For per-user OAuth, it opens a fresh ephemeral transport per call, running it through the connect-plugin gate (`runConnectWithPluginPipeline`) for parity with shared connections. - Removed `OpenConnectionAndExecuteTool` (the standalone ephemeral connection helper). All connection lifecycle is now routed through `AcquireClientConn`, eliminating the divergent per-user code path in `ToolsManager` and `StarlarkCodeMode`. - Restructured credential composition so that static config headers (minus `Authorization`) are exposed to plugins via `StaticConfigHeaders`, and auth credentials are layered on top *after* the plugin gate runs. This is a structural guarantee: plugins can mutate static headers but never observe bearer tokens or signing headers. - Moved tool availability and permission checks (client lifecycle, allow-lists, `ToolsToExecute`, request-context filters) into a new `prepareToolExecution` method on `MCPManager`. `ToolsManager.executeToolInternal` no longer performs redundant tool lookups — the resolved connection, config, and tool name mapping are passed in directly. - Removed `ExecuteToolCall` from `MCPManagerInterface` and `MCPManager`. The plugin-wrapped `ExecuteChatTool` path is now the canonical entry point for tool execution; tests updated accordingly. - Introduced `MCPToolExecutor` as a named function type for the agent loop's tool executor, replacing the anonymous `func(...)` signature. - `CredStore.resolverFor` now normalizes empty `AuthType` to `MCPAuthTypeHeaders`, matching the DB column default and `UpdateClient`'s existing normalization. Programmatically constructed configs with a blank auth type no longer return an error. - `staticHeadersResolver`, `noneResolver`, `serverOAuthResolver`, and `perUserOAuthResolver` `ConnectionHeaders` implementations now return only the auth-specific header (e.g. `Authorization`). Static config headers are no longer bundled here — they are layered separately by the caller. - Removed `GetHeadersForToolExecution` from `utils` (no longer needed). Added `StaticConfigHeaders` to `utils` which returns config headers excluding `Authorization`. - `ToolsManager.ExecuteAgentForChatRequest` and `ExecuteAgentForResponsesRequest` now return an error if `executeTool` is nil, rather than silently falling back to the un-hooked path. ## Type of change - [ ] Bug fix - [ ] Feature - [x] 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 ./core/... go test ./core/internal/mcptests/... go test ./core/mcp/... go test ./core/mcp/codemode/starlark/... ``` Validate that: - Tool filtering tests pass and exercise `ExecuteChatTool` rather than the removed `ExecuteToolCall`. - Per-user OAuth tool calls open an ephemeral connection through the plugin gate and close it after execution. - Shared-connection clients continue to use their persistent `state.Conn` with no additional connection overhead. - Agent mode returns an explicit error when no `executeTool` function is provided. ## Breaking changes - [x] Yes - [ ] No `ExecuteToolCall` has been removed from `MCPManagerInterface`. Any custom `MCPManagerInterface` implementation must remove this method. Callers that previously invoked `ExecuteToolCall` directly should use the plugin-wrapped `ExecuteChatTool` path instead. `ToolsManager.ExecuteTool` now requires `clientConn`, `executionConfig`, and `toolNameMapping` arguments; direct callers must be updated. ## Security considerations The primary motivation for this refactor is a security boundary improvement: credentials (bearer tokens, signing headers) are now guaranteed to be invisible to MCP connect-plugins. Plugins operate only on admin-configured static headers (excluding `Authorization`). Auth headers are composed after the plugin gate returns, on the wire transport, and are never present in the `BifrostMCPConnectRequest` object that plugins receive in `PreConnectionHook` or `PostConnectionHook`. ## 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
…submission flow (#3703) ## Summary Adds `MCPAuthTypePerUserHeaders` — a new per-user MCP authentication type where each caller submits their own API keys or signed-token header values (e.g. `Authorization`, `X-Api-Key`) rather than going through an OAuth dance. The admin declares the required header names (`per_user_header_keys`) at MCP client creation time; end users supply values on first tool use via an inline-401 submission flow that mirrors the existing per-user OAuth surface. ## Changes - **New `MCPAuthTypePerUserHeaders` auth type**: Added to `MCPAuthType` constants, `MCPClientConfig`, and all validation paths. Requires a non-empty `PerUserHeaderKeys` list; `oauth_config_id` must not be set. - **Unified `MCPAuthRequiredError`**: Replaced `MCPUserOAuthRequiredError` with `MCPAuthRequiredError` (with a `Kind` field: `"oauth"` or `"headers"`). `MCPUserOAuthRequiredError` is retained as a type alias for backward compatibility. - **`perUserHeadersResolver`**: New credstore resolver that looks up per-user header credentials by `(auth_mode, identity, mcp_client_id)`. On miss or stale schema, initiates a submission flow and returns an `MCPAuthRequiredError` with `Kind="headers"` and a `SubmitURL`. - **`MCPHeadersProvider` interface and `mcp_headers.Provider`**: Storage backend for per-user header credentials and pending submission flow rows. Mirrors `OAuth2Provider` structurally. Includes `InitiateUserSubmissionFlow` which mints a `mcp_headers_auth` temp token embedded in the auth-page URL fragment. - **`VerifyHeadersConnection`**: New method on `MCPManager` and `Bifrost` that opens a temporary MCP connection using caller-supplied header values, runs the Initialize handshake, and discovers tools. Used during admin MCP client creation (sample values) and user submission (validate before persisting). - **Database migrations**: Two new migrations — `add_mcp_per_user_header_credentials_table` (creates `mcp_per_user_header_credentials`, adds `per_user_header_keys_json` to `config_mcp_clients`, and creates partial unique indexes per auth mode) and `add_mcp_per_user_header_flows_table` (creates `mcp_per_user_header_flows`). - **`StaticConfigHeaders` updated**: Now strips any header whose name appears in `PerUserHeaderKeys` from the plugin-visible static header set, preventing admin-set static values from leaking through the connect-plugin gate for per-user-headers clients. - **`BifrostContextKeyMCPCallbackBaseURL`**: Replaces `BifrostContextKeyOAuthRedirectURI`. The base URL is now set once; OAuth resolver appends `/api/oauth/callback`, headers resolver appends the workspace submit path. - **`GovernancePlugin.PreMCPConnectionHook`**: New hook that resolves the caller's VK identity onto the `BifrostContext` before the credential-store resolver runs, so per-user auth types can key stored credentials by VK row ID. - **HTTP handlers**: - `POST /api/mcp/client` extended to handle `per_user_headers` auth type: validates `per_user_header_keys`, runs `VerifyHeadersConnection` with admin sample values, persists discovered tools, and discards the sample values. - New `MCPPerUserHeadersHandler` with routes: `GET /api/mcp/per-user-headers/flows/{id}` (flow detail), `PUT /api/mcp/per-user-headers/flows/{id}` (submit), `DELETE /api/mcp/per-user-headers/credential/{id}` (revoke). - `MCPSessionsHandler` extended to list, reauth, and revoke header credential and header flow rows alongside OAuth rows. Added `auth_kind` field to `mcpSessionRow` to disambiguate OAuth vs headers rows on the wire. - **`mcpHeadersAuthScope` temp token scope**: Grants `GET` and `PUT` access to the per-user-headers flow endpoints, bound to the flow ID. Registered at server startup alongside `mcpAuthScope`. - **`CredentialSweepWorker`**: Background worker that reaps orphaned credential rows (24h cadence, 30-day retention) and expired pending flow rows (15-min cadence). Started and stopped alongside the OAuth sweep worker. - **`identityForMCPAuthMode`** moved to its own file (`credstore/identity.go`) so both `perUserOAuthResolver` and `perUserHeadersResolver` share it without duplication. - **Cascade deletes**: `DeleteMCPClientConfig` and `DeleteVirtualKey` now also delete `mcp_per_user_header_credentials` and `mcp_per_user_header_flows` rows for the affected client/VK. - **`MarkMCPPerUserHeaderCredentialsNeedsUpdate`**: Called by `updateMCPClient` when `PerUserHeaderKeys` changes, flipping existing active credential rows to `needs_update` so callers are forced to resubmit on next tool use. ## 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 ./... ``` 1. Create an MCP client with `auth_type: per_user_headers` and `per_user_header_keys: ["Authorization"]`, supplying a sample `user_headers` map in the request body. Verify the client is created with discovered tools and the sample values are not persisted. 2. Make a tool call through the client without submitting credentials. Confirm the response contains `extra_fields.mcp_auth_required` with `kind: "headers"` and a `submit_url`. 3. Visit the `submit_url`, call `GET /api/mcp/per-user-headers/flows/{id}` to confirm the form schema, then `PUT` with valid header values. Confirm the credential row is created and the flow row is deleted. 4. Retry the tool call — it should succeed using the stored credential. 5. Call `DELETE /api/mcp/per-user-headers/credential/{id}` and confirm the credential and any pending flow rows are removed. 6. Update the MCP client's `per_user_header_keys` and confirm existing credential rows flip to `needs_update`, triggering the inline-401 on next tool use. 7. Delete the MCP client and confirm all associated credential and flow rows are removed. ## Breaking changes - [ ] Yes - [x] No `MCPUserOAuthRequiredError` is retained as a type alias for `MCPAuthRequiredError`, so existing callers that reference the old type continue to compile. The `BifrostContextKeyOAuthRedirectURI` context key is replaced by `BifrostContextKeyMCPCallbackBaseURL`; any code outside this repository that sets the old key directly will need to be updated. ## Security considerations - Admin-supplied sample header values used during MCP client creation are never persisted — they are used once for upstream verification and discarded. - Per-user header values are stored encrypted at rest using the same encryption key as OAuth tokens (`BIFROST_ENCRYPTION_KEY`). - `PerUserHeaderKeys` entries are stripped from the plugin-visible static header set so connect-plugin hooks cannot read or rewrite per-user credential values. - Temp tokens for the headers submission flow are embedded as URL fragments (`#t=<token>`), which are not sent to servers in `Referer` headers and do not appear in server access logs. - Flow rows are bound to a single `(mode, identity, mcp_client_id)` triple; the submit endpoint validates the caller's values against the upstream before persisting. ## Checklist - [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
## Summary
Adds a **per-user headers** authentication type for MCP clients, mirroring the existing per-user OAuth flow. Admins declare a set of required header key names on the MCP client config; each end user then submits their own values (API keys, tokens, etc.) via a dedicated auth landing page. The backend verifies upstream connectivity and stores credentials encrypted per-user. This enables MCP servers that require caller-specific API keys without sharing a single set of credentials across all users.
## Changes
- **New `per_user_headers` auth type** added to `MCPAuthType`, `MCPClientConfig`, `CreateMCPClientRequest`, and `UpdateMCPClientRequest`. Admins declare required header key names via `per_user_header_keys`; user-submitted values are never stored on the client config.
- **`MCPHeadersAuthorizer` dialog** (`mcpHeadersAuthorizer.tsx`): mirrors `OAuth2Authorizer`'s state machine (confirm → input → testing → success/failed). On Create, the admin supplies sample values; the server verifies upstream, discovers tools, and persists atomically in a single POST. Nothing is committed if the user cancels or verification fails.
- **`HeadersForm` component** (`headersForm.tsx`): reusable secret-input form used by both the admin test panel and the end-user submission page. Renders one password input per required key, supports show/hide toggle, previously-submitted key badges, and optional read-only display of admin-static header names.
- **Auth landing page** (`mcp-sessions/auth/page.tsx`): split into `OAuthAuthView` and `HeadersAuthView`. The `kind=headers` query param routes to the headers branch. `HeadersAuthView` fetches the pending flow row and schema, renders `HeadersForm`, and PUTs values back to the flow endpoint. Handles 401/404/410 error states and a post-submit success card.
- **Sessions table** (`sessionsTable.tsx`): adds a `Type` column with `OAuth`, `Headers`, and `Pending` badges. Adds `needs_update` status badge for header rows whose schema has changed. Header rows show an "Edit values" / "Update values" action instead of "Re-authenticate". Reconnect is disabled for all per-user auth types (`isPerUserAuth` replaces `isPerUserOAuth`). Header rows display `—` in the access token expiry column.
- **RTK Query API** (`mcpPerUserHeadersApi.ts`): `getMCPPerUserHeadersFlow`, `submitMCPPerUserHeadersFlow`, and `revokeMCPPerUserHeaders` endpoints targeting `/api/mcp/per-user-headers/flows/{id}`.
- **Type definitions** (`mcpPerUserHeaders.ts`, `mcpSessions.ts`): `MCPHeadersFlowDetail`, `MCPPerUserHeadersSubmitRequest/Response`, `MCPHeadersUserCredentialStatus`, `MCPSessionKind` extended with `"header"`, `MCPSessionStatus` extended with `"needs_update"`, and `auth_kind` discriminator on `MCPSessionRow`.
- **MCP clients table**: `per_user_headers` auth type renders as "Per-user Headers" in the auth type display column.
- Minor copy fix: "MCP tool groups" heading capitalised to "MCP Tool Groups".
## 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
```sh
cd ui
pnpm i
pnpm build
pnpm test
```
1. Navigate to **MCP Registry → Add Client**.
2. Select **Per-User Headers** as the auth type.
3. Enter comma-separated header key names (e.g. `X-API-Key, X-Tenant-ID`) in the Required Headers textarea.
4. Click **Create** — the `MCPHeadersAuthorizer` dialog opens.
5. Enter sample values and click **Run Test**. Verify the server connects, discovers tools, and the client appears in the registry.
6. As an end user, trigger a tool call that requires per-user headers. Confirm the auth landing page (`/workspace/mcp-sessions/auth?flow=...&kind=headers`) renders the submission form with the correct required keys.
7. Submit values and confirm the sessions table shows a `Headers` type row with `Active` status.
8. In the admin, change the `per_user_header_keys` schema. Confirm the existing credential row flips to `Needs update` and the "Update values" action appears.
## Screenshots/Recordings
_Add before/after screenshots of the MCP client form auth type selector, the `MCPHeadersAuthorizer` dialog, the auth landing page headers form, and the sessions table Type/Status columns._
## Breaking changes
- [x] No
`isPerUserOAuth` prop on `MCPClientActionsMenu` renamed to `isPerUserAuth` — internal component only, no external API surface affected.
## Related issues
## Security considerations
- Per-user header values (API keys, tokens) are submitted directly to the backend and stored encrypted in the credential store. Values are never round-tripped to the client after submission.
- Admin sample values supplied during the create-time verification step are discarded after the upstream connectivity check and are never persisted.
- The auth landing page accepts a temp token in the URL fragment (`#t=`) to bind anonymous browser visitors to a specific flow ID without requiring a dashboard session.
- Extra keys in user submissions are dropped server-side against the live `PerUserHeaderKeys` schema, preventing stale UI submissions from persisting deprecated keys.
## 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
…#3705) ## Summary When a Virtual Key's MCP allowlist changes (via dashboard edit, AP propagation, or SCIM auto-assign) or when an MCP client's access configuration changes (VK configs diff or `AllowOnAllVirtualKeys` toggle), per-user credentials that are no longer valid were previously left stale. This PR introduces a reconciliation layer that orphans vk-keyed OAuth tokens and header credentials whose MCP grant was revoked, reactivates them if the grant returns, and hard-deletes any in-flight pending flow rows that can no longer complete. ## Changes - Added `DeleteVirtualKey` now also hard-deletes `TableMCPPerUserHeaderFlow` rows tied to the deleted VK, consistent with how other credential rows are cleaned up on VK deletion. - Added `vkEffectiveMCPClientIDs` helper that computes the union of a VK's explicit per-VK MCP allowlist and MCPs with `AllowOnAllVirtualKeys=true`, mirroring the runtime grant check. - Added `reconcileVKDirectTokensDB` and `reconcileVKDirectHeaderRowsDB` — transactional DB helpers that orphan active credentials outside the effective allowlist, reactivate orphaned credentials that regained access, and hard-delete pending flow rows for lost grants. - Added `readVKsHoldingOauthCredsForMCP` and `readVKsHoldingHeaderCredsForMCP` to identify which VKs need re-evaluation when a change originates on the MCP side. - Exposed four new `ConfigStore` interface methods: `ReconcileOauthAfterVKChange`, `ReconcileMCPHeadersAfterVKChange`, `ReconcileOauthAfterMCPChange`, and `ReconcileMCPHeadersAfterMCPChange`. - Called the VK-side reconcile methods in `updateVirtualKey` when `MCPConfigs` is present in the request. - Called the MCP-side reconcile methods in `updateMCPClient` when `VKConfigs` changed or `AllowOnAllVirtualKeys` was toggled. - Added no-op stubs for all four new interface methods to `MockConfigStore` in tests. - Reconciliation errors are logged but non-fatal so the primary update response is not blocked. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test 1. Create a VK with an explicit MCP allowlist and establish an active OAuth token and a header credential for one of the allowed MCPs. 2. Edit the VK to remove that MCP from its allowlist — verify the token and credential rows transition to `status='orphaned'` and any pending flow rows for that MCP are deleted. 3. Re-add the MCP to the VK's allowlist — verify the orphaned rows return to `status='active'`. 4. Toggle `AllowOnAllVirtualKeys` on an MCP client — verify all VKs holding credentials for that MCP are re-evaluated accordingly. 5. Delete a VK — verify `mcp_per_user_header_flows` rows for that VK are removed alongside other credential rows. ```sh go test ./framework/configstore/... go test ./transports/bifrost-http/... ``` ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations Orphaned credentials are invisible to runtime grant checks (`status='active'` filter), so a user whose VK loses MCP access can no longer use stale credentials to reach that MCP. Pending in-flight flows for revoked grants are hard-deleted immediately, preventing completion of an auth flow that would produce an unusable credential. ## 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
…model (#3706) ## Summary Introduces a new **MCP Sessions** documentation page and rewrites the per-user OAuth docs to reflect the current lazy-auth model, replacing the older consent-screen-based flow description. ## Changes - Added `docs/mcp/sessions.mdx` — a new reference page covering the MCP Sessions table, token states (`active`, `needs_reauth`, `orphaned`), pending flow rows, re-authenticate and revoke actions, identity scoping, and a troubleshooting section. - Rewrote `docs/mcp/per-user-oauth.mdx` to document the unified lazy-auth pattern used by both the MCP Gateway and LLM Gateway. Removed the old three-phase consent flow (discovery → consent screen → session token) and replaced it with the current model: identity is asserted via headers, and auth happens on the first tool call that needs an upstream token via an inline `authorize_url`. - Replaced the two-gateway identity table with a four-mode table (`user`, `vk`, `session`, `none`) that documents priority order, cross-gateway portability, and persistence behavior. Clarified that `X-Bf-User-Id` is not a public input and that `x-bf-mcp-session-id` is the correct header for session-mode identity. - Updated `docs/mcp/gateway-url.mdx` to remove the description of Bifrost acting as an OAuth 2.1 Authorization Server with `.well-known` discovery endpoints, replacing it with the current header-based identity model and a note about Claude Code's DCR probe behavior. - Updated `docs/mcp/connecting-to-servers.mdx` to reflect that the same caller identity is honored across both gateways and that auth is lazy. - Added the MCP Sessions page to the sidebar (`docs/docs.json`) and to the overview card grid (`docs/mcp/overview.mdx`). - Added a warning about `mcp_external_client_url` changes breaking already-registered upstream OAuth clients, and a note that MCP client names cannot contain hyphens. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test Navigate the updated docs locally and verify: 1. The MCP Sessions page renders at `mcp/sessions` and appears in the sidebar between Per-User OAuth and Tool Execution. 2. The Per-User OAuth page no longer references a consent screen, `.well-known` discovery, or Bifrost-issued session tokens. 3. The gateway URL page no longer describes a `WWW-Authenticate` 401 flow. 4. All cross-links between `per-user-oauth`, `sessions`, `gateway-url`, and `connecting-to-servers` resolve correctly. ## Screenshots/Recordings Placeholder image references are noted inline in the new and updated pages; screenshots need to be captured and added before final publication. ## Breaking changes - [ ] Yes - [x] No ## Related issues Reflects the behavioral changes shipped in Bifrost v1.5.0-prerelease2. ## Security considerations The sessions page documents that Bifrost does not call upstream `/revoke` endpoints on local revocation, and that session IDs are treated as secrets (length-only in logs, never echoed). The identity priority order (`user` > `vk` > `session`) and the scoping rules that prevent one caller from completing or revoking another caller's flow are explicitly documented. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [x] I updated documentation where needed - [ ] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
## Summary
Introduces `per_user_headers` as a new MCP authentication type, allowing admins to declare a schema of header names that each end-user must supply individually. This mirrors the existing `per_user_oauth` pattern but for header-based credentials instead of OAuth tokens. Alongside this, the OpenAPI spec is reorganized to expose a unified MCP sessions API covering OAuth tokens, header credentials, and pending flows, while removing the legacy OAuth Authorization Server surface (RFC 7591/8414 endpoints, consent flow HTML pages, and well-known discovery endpoints).
## Changes
- Added `per_user_headers` to the `MCPAuthType` enum across all MCP client create, update, and config schemas.
- Added `per_user_header_keys` field to MCP client create/update/config schemas — declares which header names end-users must submit. Updating this list on an existing client flips all active per-user credentials to `needs_update`.
- Added `user_headers` field to MCP client create request — a one-time admin-supplied sample used only at create time for upstream verification and tool discovery; never persisted.
- Added new `/api/mcp/sessions` endpoints: `GET` to list all per-user auth artifacts (OAuth tokens, header credentials, pending flows) scoped to the caller's identity; `DELETE /{id}` to revoke any row kind; `POST /{id}/reauth` to mint a fresh auth flow against the same binding.
- Added `/api/mcp/per-user-headers/flows/{id}` endpoints: `GET` to retrieve a pending submission flow with the required header schema; `PUT` to submit header values, verify them upstream, and persist the credential.
- Added `/api/mcp/per-user-headers/credential/{id}` `DELETE` endpoint for typed revocation of header credential rows.
- Added `/api/oauth/per-user/flows/{id}` `GET` endpoint returning OAuth flow metadata (binding, active token status) for the consent UI.
- Added `/api/oauth/per-user/flows/{id}/start` `GET` endpoint that reconstructs the upstream provider's authorize URL for a pending flow.
- Moved the `revokeOAuthConfig` DELETE operation to its own `/api/oauth/config/{id}` path entry (`oauth-config-by-id`), separating it from the GET status endpoint.
- Removed the OAuth Authorization Server endpoints (RFC 7591 dynamic registration, RFC 7636 PKCE authorize/token, upstream authorize proxy, consent HTML pages, `/.well-known/oauth-protected-resource`, `/.well-known/oauth-authorization-server`). Bifrost no longer acts as an OAuth AS; MCP client identity is asserted via request headers.
- Added new schemas: `MCPSessionRow`, `MCPSessionsListResponse`, `MCPSessionReauthResponse`, `MCPHeadersFlowDetail`, `MCPHeadersSubmitRequest`, `MCPHeadersSubmitResponse`, `MCPOauthFlowDetail`, `MCPClientSummary`, `MCPVirtualKeySummary`, `MCPUserSummary`.
- Added a shared `Unauthorized` response component reused across the new endpoints.
- Reorganized the `openapi.yaml` path registry with clearer section comments separating client management, per-user sessions, per-user-headers flows, per-user OAuth flows, and server-level OAuth admin endpoints.
## Type of change
- [ ] Bug fix
- [x] Feature
- [x] Refactor
- [x] Documentation
- [ ] Chore/CI
## Affected areas
- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [x] Docs
## How to test
Validate that the OpenAPI spec is valid and that the compiled `openapi.json` matches the YAML sources:
```sh
# Lint/validate the OpenAPI spec
npx @redocly/cli lint docs/openapi/openapi.yaml
# Confirm the compiled JSON is in sync
npx @redocly/cli bundle docs/openapi/openapi.yaml -o /tmp/openapi-built.json
diff /tmp/openapi-built.json docs/openapi/openapi.json
```
Verify the new `per_user_headers` auth type is accepted on MCP client create/update requests and that `per_user_header_keys` is required when that type is set. Confirm that the removed OAuth AS endpoints (`/api/oauth/per-user/register`, `/api/oauth/per-user/authorize`, `/api/oauth/per-user/token`, `/oauth/consent`, etc.) are no longer present in the spec.
## Breaking changes
- [x] Yes
- [ ] No
The following endpoints have been removed from the spec: `/api/oauth/per-user/register`, `/api/oauth/per-user/authorize`, `/api/oauth/per-user/token`, `/api/oauth/per-user/upstream/authorize`, `/oauth/consent`, `/oauth/consent/mcps`, `/api/oauth/per-user/consent/vk`, `/api/oauth/per-user/consent/user-id`, `/api/oauth/per-user/consent/skip`, `/api/oauth/per-user/consent/submit`, `/.well-known/oauth-protected-resource`, `/.well-known/oauth-authorization-server`. Any clients relying on Bifrost acting as an OAuth Authorization Server must migrate to the new per-user flow endpoints.
The `revokeOAuthConfig` DELETE operation has moved from `/api/oauth/config/{id}/status` to `/api/oauth/config/{id}`.
## Related issues
## Security considerations
`user_headers` values submitted at MCP client create time are explicitly not persisted — they are used only for a one-time upstream verification call and then discarded, consistent with how temporary admin OAuth tokens are handled for `per_user_oauth` setup. Per-user header values are stored per-user in a separate table and are never returned via the API (only key names are surfaced). The new session endpoints enforce identity scoping server-side so callers can only access credentials bound to their own identity.
## Checklist
- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…xample (#3723) ## Summary Adds documentation and a working example for the four MCP plugin hooks introduced in v1.5.x: `PreMCPConnectionHook`, `PostMCPConnectionHook`, `PreMCPHook`, and `PostMCPHook`. Previously, the Go plugin writing guide only covered LLM and HTTP transport hooks, leaving the MCP gateway hooks undocumented. The `mcp-only` example plugin is also extended to implement all four hooks rather than just the envelope pair. ## Changes - Added an "MCP plugin hooks overview" section to `docs/plugins/writing-go-plugin.mdx` explaining the two lifecycle stages (Connect and Envelope), their respective hook pairs, request types, and when each fires - Added per-hook reference sections with signature docs, key behavioral notes (mutable vs. observe-only fields, short-circuit types, ordering), and annotated code examples for all four MCP hooks - Added a `<Note>` callout to the plugin skeleton pointing readers to the new MCP hooks section - Clarified the "symbol not found" troubleshooting entry to note that all MCP hooks are optional and a typo silently disables the hook rather than failing the load - Updated the `go tool nm` debug snippet to include MCP hook symbol names - Extended `examples/plugins/mcp-only/main.go` to export `PreMCPConnectionHook` and `PostMCPConnectionHook`, implementing client blocklisting and audit header injection for HTTP/SSE transports - Added `blocked_clients` and `audit_header` config options to the example plugin and its README - Updated `go.mod`/`go.sum` in the example to use the published module version rather than a local `replace` directive, and bumped several transitive dependencies Notable design decisions: - Connect short-circuits (`*MCPConnectionShortCircuit`) and envelope short-circuits (`*MCPPluginShortCircuit`) are explicitly called out as non-interchangeable — Connect does not go through the envelope path - `ConnectionType` and `AuthType` are documented as observe-only in `PreMCPConnectionHook`; mutating them mid-flight would break the connect codepath - Header injection in `PreMCPConnectionHook` is silently a no-op for STDIO and InProcess transports; the docs and example both guard on `ConnectionType` before injecting ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [x] Docs ## How to test Build the updated example plugin and verify all four symbols are exported: ```sh cd examples/plugins/mcp-only go build -buildmode=plugin -o mcp-only.so . go tool nm mcp-only.so | grep -E 'PreMCPHook|PostMCPHook|PreMCPConnectionHook|PostMCPConnectionHook' ``` Load the plugin in a Bifrost instance configured with at least one MCP client and confirm: - A client whose name appears in `blocked_clients` is refused at connect time with a 403 - An HTTP/SSE client not in the blocklist receives the injected audit header during transport setup - Tool calls to names in `blocked_tools` are blocked at the envelope level - `PostMCPConnectionHook` logs server name, version, and protocol after a successful handshake ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations The `PreMCPConnectionHook` example demonstrates client-name-based connection refusal and audit header injection. Operators should treat `ClientName` as an identifier sourced from Bifrost configuration, not from the upstream server, and should avoid injecting secrets via `AuditHeader` values that may appear in logs. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [x] I updated documentation where needed - [ ] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
## Summary `AddMCPClient` and `connectToMCPClient` previously used the manager's background context when running connection hooks, which meant request-scoped values (such as HTTP headers extracted by the transport layer) were invisible to MCP plugins during the connect phase. This PR threads the caller's `context.Context` through `AddMCPClient` so that connect-time hooks can read request-scoped values while keeping persistent transport lifetimes bound to the manager context. ## Changes - `MCPManager.AddClient`, `Bifrost.AddMCPClient`, and the internal `connectToMCPClient` now accept a `context.Context` parameter. The `BifrostContext` passed to connect/list-tools hooks is derived from the caller's context rather than the manager's background context. - `ReconnectClient`, `EnableClient`, and `UpdateClientConnection` continue to use the manager context (`m.ctx`) since they are infrastructure-initiated and have no caller request context. - `NewMCPManager` passes `manager.ctx` when calling `AddClient` during startup initialization, preserving existing behavior. - The HTTP transport's `addMCPClient`, `completeMCPClientOAuth`, and `flowSubmit` handlers now convert the incoming `fasthttp.RequestCtx` to a `BifrostContext` before calling `AddMCPClient` and related verification methods, so HTTP request headers are available to MCP plugins. - `MCPManagerInterface` updated to reflect the new `AddClient` signature. - The `mcp-only` plugin example logs request headers received in `PreMCPConnectionHook` to demonstrate the new capability. ## 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 ./core/... go test ./transports/... ``` To verify that request headers are visible in a connect hook, configure the `mcp-only` plugin example with `EnableLogging: true` and call the `POST /mcp/clients` endpoint with custom headers. The plugin's `PreMCPConnectionHook` log line will print the headers extracted from the incoming request. ## Breaking changes - [x] Yes - [ ] No `MCPManagerInterface.AddClient` and `Bifrost.AddMCPClient` now require a `context.Context` as the first argument. Any callers implementing or calling these interfaces directly must add a context argument (e.g. `context.Background()` as a minimal migration). ## Related issues ## Security considerations Request headers passed through the context may contain credentials or tokens. MCP plugin authors should treat values read from `BifrostContextKeyRequestHeaders` as sensitive and avoid logging them in production. ## 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
… Starlark nested tool calls through canonical plugin gate (#3794) ## Summary Starlark codemode nested tool calls previously duplicated the plugin gate logic inline, diverging from the canonical `RunWithPluginPipeline` path used by the gateway. This PR promotes `runWithPluginPipeline` to an exported method on `MCPManager`, adds it to the `ClientManager` interface, and routes Starlark nested tool calls through it — making codemode tool execution observationally identical to gateway-routed calls (tracing, pre/post hooks, short-circuit semantics, plugin log draining). A secondary fix corrects the logging plugin's `PreMCPHook` to also skip codemode meta-tools when they arrive with a client prefix (e.g. `myclient-executeToolCode`), not just bare names. Previously, `PreMCPHook` would insert a pending log row for the prefixed name while `PostMCPHook` would skip on the stripped bare name, leaving an orphaned row to expire as a fake TTL error. ## Changes - `runWithPluginPipeline` renamed to `RunWithPluginPipeline` and added to the `ClientManager` interface so any call site outside the gateway (e.g. Starlark codemode) can use the canonical plugin gate. - `callMCPTool` in the Starlark codemode executor replaced its inline pre/post hook orchestration with a single `RunWithPluginPipeline` call. Connection acquisition still happens outside the gate, mirroring the gateway's `exec.go` ordering. - `BifrostMCPRequest.ClientName` is now set explicitly before the gate so plugins can attribute short-circuit responses without re-parsing the prefixed tool name. - Logging plugin's `PreMCPHook` now checks both the full tool name and the suffix after the client prefix for codemode meta-tools, preventing orphaned pending rows. - All mock `ClientManager` implementations in tests implement the new `RunWithPluginPipeline` method with a pass-through that wraps plain errors into `BifrostError`. - New test `TestPreMCPHookSkipsPrefixedCodemodeTool` verifies that `PreMCPHook` does not create a pending row for a client-prefixed codemode tool name. ## Type of change - [x] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/mcp/... go test ./core/mcp/codemode/starlark/... go test ./plugins/logging/... ``` Verify that: - Starlark nested tool calls flow through pre/post hooks identically to gateway-routed calls. - A codemode meta-tool invoked with a client prefix (e.g. `myclient-executeToolCode`) does not produce a pending log row in the logging plugin. ## Breaking changes - [x] Yes - [ ] No `ClientManager` interface gains a new `RunWithPluginPipeline` method. Any external implementation of `ClientManager` must add this method. All in-repo mocks have been updated. ## Related issues ## Security considerations No new auth, secrets, or PII surface area introduced. The gate's short-circuit and credential-error paths are preserved unchanged. ## Checklist - [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
## Summary Updates the Code Mode documentation to reflect real benchmark results and replaces the hypothetical e-commerce scenario with measured data. The previous claims of "50%+ token reduction" are replaced with benchmark-backed figures showing up to 92.8% fewer input tokens and 92.2% lower estimated cost at scale. The UI label for the Code Mode toggle is also corrected from "Code Mode Client" to "Code Mode Server", and a help icon with a tooltip link is added to the edit sheet to match the existing form. ## Changes - Replaced the estimated "50% cost reduction" claim in `code-mode.mdx` and `overview.mdx` with benchmark results from three controlled rounds (96 tools / 6 servers through 508 tools / 16 servers) - Added a benchmark results table showing pass rate, input token counts, and estimated cost for classic MCP vs. Code Mode across all three rounds - Replaced the ASCII-art turn-by-turn comparison with flow diagram images (`mcp-classic-flow.png`, `mcp-codemode-flow.png`) and added token/cost comparison charts (`mcp-codemode-tokens-diff.png`, `mcp-codemode-cost-diff.png`) - Removed the hypothetical e-commerce scenario section and replaced it with a "Why Savings Grow with Tool Count" section grounded in the benchmark data - Renamed the "Code Mode Client" toggle label to "Code Mode Server" in both `mcpClientSheet.tsx` and the docs step instruction - Added an info icon with a tooltip and link to the Code Mode docs in the `mcpClientSheet.tsx` edit view, consistent with the existing `mcpClientForm.tsx` pattern - Fixed minor formatting: comma placement in a key insight sentence, and indentation of chained array method calls ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [x] Docs ## How to test ```sh # UI cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` Verify the MCP client edit sheet displays "Code Mode Server" as the toggle label with an info icon that links to the Code Mode docs page. ## Screenshots/Recordings Verify the following in the MCP client edit sheet: - Toggle label reads "Code Mode Server" (not "Code Mode Client") - An info icon appears next to the label - Hovering the icon shows "Click to learn more about Code Mode" - Clicking the icon opens `https://docs.getbifrost.ai/mcp/code-mode` in a new tab ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. Changes are limited to documentation content, static image assets, and a UI label correction. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [x] I updated documentation where needed - [ ] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
…s and accordion OAuth settings (#3799) ## Summary Improves the MCP client creation and management UI by splitting the single `auth_type` dropdown into separate "Authentication Type" and "Auth Scope" selectors, making the distinction between shared and per-user auth more intuitive. Also improves the MCP clients table with better column organization and replaces the clickable row pattern with an explicit Edit action in the actions menu. ## Changes - The `auth_type` field (which encodes both kind and scope, e.g. `per_user_oauth`) is now represented in the form as two independent dropdowns: **Authentication Type** (`none` / `headers` / `oauth`) and **Auth Scope** (`shared` / `per-user`). These recombine into the existing wire format so the backend contract is unchanged. - OAuth advanced settings (client ID, client secret, authorize URL, token URL, registration URL, scopes) are collapsed into an `Accordion` component to reduce visual noise. - The Connection URL field's tooltip explaining `env.<VAR>` syntax was removed from the label area. - A read-only connection summary block is shown in the edit sheet, since connection type and target cannot be changed after creation. A helper note to that effect is also added to the creation form. - The MCP clients table replaces the "Connection Info" column with a **VK Access** column showing whether the server is available to all virtual keys or a specific count. Auth is now split across two columns: **Auth Type** and **Auth Scope**. - Connection type badges are now rendered with a monospace `Badge` component. - Clicking a table row no longer opens the edit sheet; an explicit **Edit** item (with pencil icon) is added to the row actions dropdown menu. - A tooltip with a link to Agent Mode docs is added to the "Auto-execute" column header in the tools table, clarifying that the setting only applies in Agent Mode. - `getConnectionDisplay` helper removed from the table since connection info is no longer shown as a column. - `authScope` state is reset to `"shared"` when the form is closed/reset. ## Type of change - [ ] Bug fix - [x] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Open the MCP Registry and click **Add Server**. 2. Select connection type **SSE** or **HTTP**. 3. Verify the **Authentication Type** dropdown shows `None`, `Headers`, and `OAuth 2.0` (no per-user variants). 4. Select `Headers` or `OAuth 2.0` and confirm an **Auth Scope** dropdown appears with `Shared` and `Per-User` options. 5. Confirm that toggling Auth Scope correctly maps to the underlying `auth_type` value (e.g. `per_user_oauth` when OAuth + Per-User). 6. Select `OAuth 2.0` and verify the advanced settings are hidden behind an accordion. 7. Save a client and confirm the table shows separate **Auth Type** and **Auth Scope** columns with correct values. 8. Confirm the **VK Access** column correctly shows `All`, `N VKs`, or `None`. 9. Confirm clicking a table row no longer opens the sheet; use the **⋯** menu → **Edit** instead. 10. Open an existing client's edit sheet and verify the read-only connection summary is displayed. ```sh cd ui pnpm i pnpm build ``` ## Screenshots/Recordings _Before/after screenshots recommended for the form auth dropdowns, the accordion, and the updated table columns._ ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations The `per_user_*` auth types store credentials per user rather than in the shared server config. The refactored UI preserves this behavior — the split dropdowns recombine into the same wire values, so no change to how credentials are stored or transmitted. ## 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
## Summary Bumps the Go toolchain version from `1.26.2` to `1.26.3` across all modules and Docker build images, and upgrades the Alpine runtime base image from `3.21.7` to `3.23.4` in the transport Dockerfiles. ## Changes - Updated all `go.mod` files across core, CLI, transports, plugins, examples, framework, and test modules to require Go `1.26.3` - Updated Docker build stages in `Dockerfile`, `Dockerfile.local`, and `Dockerfile.redhat` to use `golang:1.26.3-alpine3.23` with the corresponding new digest - Updated the runtime stage in `Dockerfile` and `Dockerfile.local` from `alpine:3.21.7` to `alpine:3.23.4` with the corresponding new digest - Updated `Makefile` targets (root and `examples/plugins/hello-world`) to use `golang:1.26.3-alpine3.23` for Docker-based cross-compilation ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go version go test ./... ``` Verify Docker builds succeed: ```sh docker build -f transports/Dockerfile . docker build -f transports/Dockerfile.local . ``` ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations The Alpine runtime base image upgrade from `3.21.7` to `3.23.4` incorporates upstream security patches available in the newer Alpine release. ## 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 PR releases Bifrost OSS `v1.5.5` and Enterprise `v1.4.4`, bumping all module pins from `v1.5.12`/`v1.3.12` to `v1.5.13`/`v1.3.13` across core, framework, and all plugins. It also hardens the Docker manifest shell scripts, expands CI egress allowlists, and updates documentation to reflect the new SCIM-based user provisioning feature.
- **Module version bumps**: All `go.mod`/`go.sum` files updated from `core v1.5.12` → `v1.5.13`, `framework v1.3.12` → `v1.3.13`, and all plugin versions incremented accordingly (`compat`, `governance`, `jsonparser`, `logging`, `maxim`, `mocker`, `otel`, `prompts`, `semanticcache`, `telemetry`).
- **Docker manifest scripts**: Added `#!/usr/bin/env bash` shebang and `set -euo pipefail` to `create-docker-manifest.sh` and `create-docker-manifest-ubi9.sh`; quoted all variable expansions and switched `jq -r` to `jq -er` to fail on null digests.
- **CI egress allowlist**: Added `production.cloudfront.docker.com:443` to Docker-related job allowlists, and added `_https._tcp.dl.google.com:443` and `motd.ubuntu.com:443` to the Ubuntu package job allowlist.
- **Changelog files**: Cleared per-module `changelog.md` files (content moved into the new versioned docs). Added `docs/changelogs/v1.5.5.mdx` and `docs/changelogs/ent-v1.4.4.mdx` with full release notes, and registered both in `docs/docs.json`.
- **Documentation**: Replaced the SSO Integration link with a User Provisioning (SCIM) link in both `README.md` and `transports/README.md`.
- **Enterprise v1.4.4 highlights** (documented): Kafka and Google Cloud Pub/Sub observability sinks, chunked streaming with a 100 MB inter-node message ceiling, BigQuery custom labels via env vars using the new `ConfigMarshallerPlugin` interface, temporary access token expiry extensions, and a multi-node cluster integration harness.
- **OSS v1.5.5 highlights** (documented): Azure v1 API migration, env-var support for OTel/Prometheus configs, OTel extra-header forwarding and semantic-convention alignment, virtual key quota including provider configs, Responses API streaming in `jsonparser`, and a batch of Bedrock, Gemini, Anthropic, Azure, and logging plugin fixes.
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [x] Documentation
- [x] Chore/CI
- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [ ] UI (React)
- [x] Docs
```sh
go version
go test ./...
bash -n .github/workflows/scripts/create-docker-manifest.sh
bash -n .github/workflows/scripts/create-docker-manifest-ubi9.sh
```
Validate that the new changelog pages (`changelogs/v1.5.5` and `changelogs/ent-v1.4.4`) render correctly in the docs site.
N/A
- [x] Yes
- [ ] No
The Azure provider no longer accepts `api_version` in `AzureKeyConfig` and has migrated to the `/openai/v1/{operation}` URL pattern. See the [v1.4.0 Migration Guide](https://docs.getbifrost.ai/enterprise/migration-guides/v1.4.0) for full details.
- The `ConfigMarshallerPlugin` interface redacts secrets (OTel collector URLs, Prometheus push gateway credentials, BigQuery labels) at config storage time and rehydrates them at load time, preventing plaintext secret persistence.
- Docker manifest scripts now use `set -euo pipefail`, preventing silent failures that could result in malformed or missing image manifests being pushed.
- [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
## Summary The "Allow Temp Token Auth Links" toggle in the MCP settings view was previously gated behind a SCIM/SSO enterprise check. This PR removes that gate so the setting is visible and configurable for all users, regardless of enterprise tier or SSO configuration. ## Changes - Removed the `isSCIMEnabled` conditional that wrapped the Temp Token Auth UI section, making it always visible in the MCP settings view. - Removed the unused `IS_ENTERPRISE` import and `useGetAuthTypeQuery` hook from `mcpView.tsx` since they were only used to compute `isSCIMEnabled`. - Minor formatting cleanup: removed a blank line at the start of `InitiateUserOAuthFlow` and reformatted a single-line mock method in the config test file. ## 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 1. Navigate to the MCP settings view in the Bifrost dashboard on a non-enterprise or non-SSO instance. 2. Confirm the "Allow Temp Token Auth Links" toggle is now visible and functional. 3. Toggle the setting and verify it saves correctly. ```sh # UI cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` ## Screenshots/Recordings The "Allow Temp Token Auth Links" section should now appear unconditionally in the MCP settings view, rather than only when SCIM/SSO is enabled. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations The Temp Token Auth feature issues short-lived scoped tokens to allow unauthenticated users to complete MCP OAuth flows. Exposing this toggle to all users does not change the underlying token security model, but operators should be aware of the implications of enabling this setting in their environment. ## 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
## Summary Adds a log message when the config store initializes a database connection, making it easier to observe which database backend is being used at startup. ## Changes - A log line is emitted at the `Info` level before the database type switch, reporting the configured store type (e.g., SQLite) when a connection is being established. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./... ``` Start the application with a configured config store and verify that a log line similar to the following appears on startup: ``` connecting to sqlite database ``` ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations The log message only exposes the database type (e.g., `sqlite`), not any connection credentials or sensitive configuration values. ## 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
…create/edit (#3726) ## Summary Replaces the `CustomerDialog` modal with a `CustomerSheet` slide-over panel for creating and editing customers in the governance view. This improves the UX by using a side panel that keeps context visible while editing. ## Changes - Removed `customerDialog.tsx` and replaced it with `customerSheet.tsx`, which uses the `Sheet` component instead of `Dialog` - The sheet resets form state when opened, allowing it to remain mounted in the DOM rather than conditionally rendered - Replaced the `FormFooter` component with an inline `SheetFooter` containing a tooltip-wrapped submit button that surfaces validation and permission errors on hover - `CustomerSheet` accepts `open`/`onOpenChange` props for controlled visibility, replacing the previous `onSave`/`onCancel` callback pattern - `customerTable.tsx` updated to always render `CustomerSheet` (always mounted) instead of conditionally rendering `CustomerDialog`, with `editingCustomer` cleared on sheet close ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Navigate to the Governance > Customers view 2. Click **Add Customer** — a sheet should slide in from the right 3. Fill in customer name, budget, and rate limit fields and submit — verify the customer is created 4. Click the edit action on an existing customer — the sheet should open pre-populated with the customer's data 5. Modify a field and save — verify the customer is updated 6. Close the sheet without saving — verify no changes are persisted and the form resets on next open 7. Verify that tooltip messages appear on the disabled submit button when validation errors exist or permissions are insufficient ## Screenshots/Recordings _Add before/after screenshots showing the dialog → sheet transition._ ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No changes to auth, data handling, or API surface. ## 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
…onent (#3739) ## Summary Introduces reusable keyboard-driven sheet navigation, allowing users to move between items in a sheet panel using arrow keys or vim-style `j`/`k` bindings. ## Changes - Added a `useSheetNavigation` hook that registers `up`/`k` (previous) and `down`/`j` (next) hotkeys via `react-hotkeys-hook`, conditionally enabled based on whether adjacent items exist. The hook returns shortcut key metadata for display in the UI. - Added a `SheetNavigationButtons` component that renders up/down chevron buttons with tooltips showing the associated keyboard shortcuts. Shortcuts are rendered as styled `<kbd>` elements, supporting both icon and label representations. ## 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 ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` Integrate `useSheetNavigation` and `SheetNavigationButtons` into a sheet component with a navigable list. Verify that: - The up/down buttons appear and are disabled when no previous/next item exists. - Pressing `↑`/`k` navigates to the previous item and `↓`/`j` navigates to the next. - Tooltips display the correct keyboard shortcut icons and labels. ## Screenshots/Recordings _Add before/after screenshots or clips of the navigation buttons and tooltips in action._ ## Breaking changes - [ ] Yes - [x] No ## Related issues _Link related issues here._ ## 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
…eet (#3740) ## Summary Adds keyboard and button-based navigation between virtual keys in the detail sheet, with support for navigating across page boundaries. The selected virtual key is now tracked in the URL via `selected_vk`, enabling deep-linking and preserving state on refresh. This mirrors the existing navigation pattern already present in the log details sheet. ## Changes - `selected_vk` is now stored as a URL query parameter, replacing the local `useState` that previously tracked the selected virtual key and sheet visibility. - `handleSelectedVkChange` propagates selection and optional offset changes together, allowing cross-page navigation to update both the selected key and the current page in a single URL update. - `handleDetailNavigate` in `VirtualKeysTable` handles prev/next navigation: within the current page it selects adjacent rows; at page boundaries it fetches the adjacent page and selects the last or first key from the result. - `VirtualKeyDetailSheet` now accepts `onNavigate`, `hasPrev`, and `hasNext` props and renders `SheetNavigationButtons` alongside the sheet title, consistent with the log detail sheet. - The log detail sheet's inline navigation buttons and `useHotkeys` calls were replaced with the shared `useSheetNavigation` hook and `SheetNavigationButtons` component, reducing duplication. - Pagination controls in `VirtualKeysTable` were restyled to use ghost buttons with icon-only chevrons and a "Page X of Y" label, with entry counts formatted with `toLocaleString`. ## Type of change - [ ] Bug fix - [x] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Navigate to the Virtual Keys table. 2. Click a row to open the detail sheet — the URL should update with `selected_vk=<id>`. 3. Use the up/down navigation buttons or keyboard arrow keys to move between keys. 4. At the last key on a page, pressing next should load the next page and open the first key's detail sheet automatically. 5. At the first key on a page, pressing prev should load the previous page and open the last key's detail sheet. 6. Reload the page with `selected_vk` in the URL — the sheet should reopen for that key. 7. Verify the same keyboard navigation works in the log detail sheet. ```sh cd ui pnpm i pnpm build ``` ## Screenshots/Recordings _Add before/after screenshots of the virtual key detail sheet navigation buttons and the updated pagination controls._ ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. No auth, secrets, or PII are involved in this change. ## 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
## Summary Adds keyboard-navigable prev/next navigation to the MCP client detail sheet, allowing users to move between MCP servers without closing and reopening the sheet. ## Changes - Added `onNavigate`, `hasPrev`, and `hasNext` props to `MCPClientSheet` to support directional navigation - Integrated `useSheetNavigation` hook and `SheetNavigationButtons` component into the sheet header - Computed the selected client's index within the table list and wired up `handleDetailNavigate` to update the selected client when navigating ## 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 1. Navigate to the MCP Registry page with multiple MCP servers registered. 2. Click on any server to open the detail sheet. 3. Verify that prev/next navigation buttons appear in the sheet header. 4. Click the buttons (or use the keyboard shortcuts) to navigate between servers and confirm the sheet content updates correctly. 5. Verify that the prev button is disabled on the first server and the next button is disabled on the last server. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings If UI changes, add before/after screenshots or short clips. ## Breaking changes - [ ] Yes - [x] No ## Related issues Link related issues and discussions. ## Security considerations No security implications. ## 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
## Summary Adds prev/next navigation to the Routing Rule info sheet, allowing users to move between rules without closing and reopening the sheet. ## Changes - Added `onNavigate`, `hasPrev`, and `hasNext` props to `RoutingRuleInfoSheet` to support directional navigation between rules. - Integrated `useSheetNavigation` hook and `SheetNavigationButtons` component into the sheet header, providing both keyboard shortcut and button-based navigation. - In `RoutingRulesView`, rules are sorted by priority and the current rule's index is tracked so that prev/next state and navigation handler can be derived and passed down to the sheet. - Restructured the sheet header layout from a single column to a row with a left-side title/badge group and right-side navigation buttons. ## 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 1. Navigate to the Routing Rules page. 2. Click on any routing rule to open the info sheet. 3. Use the prev/next navigation buttons in the sheet header to move between rules (ordered by priority). 4. Verify keyboard shortcuts (as provided by `useSheetNavigation`) also cycle through rules correctly. 5. Confirm the prev button is disabled on the first rule and the next button is disabled on the last rule. ```sh cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` ## Screenshots/Recordings _Add before/after screenshots or a short clip showing the navigation buttons in the sheet header._ ## 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
…le layout (#3751) ## Summary Improves the layout of governance pages (Customers, Virtual Keys, Access Profiles, RBAC) so that tables fill the available viewport height without causing the full page to scroll. Also migrates the Customers page search and pagination state into URL query parameters so that filters and page position are preserved in browser history. ## Changes - Applied `h-[calc(100vh_-_50px)] flex flex-col` to governance page wrappers so content fills the viewport and inner tables can grow to fill remaining space. - Replaced `useState` for `search` and `offset` on the Customers page with `nuqs` `useQueryStates`, syncing both values to the URL with `history: "push"`. Resetting search now also resets offset to 0 in a single state update. - Added `isFetching` prop to `CustomersTable` and `VirtualKeysTable` to prevent the empty state from flashing while a fetch is in progress. - Refactored `CustomersTable` layout to use `flex flex-col grow` so the table container expands to fill available space and the pagination bar stays anchored at the bottom. - Redesigned the customers pagination controls to use ghost icon-only prev/next buttons with a "Page X of Y" label, and formatted entry counts with `toLocaleString`. - Removed the `Save` icon from the customer sheet submit button. ## Type of change - [ ] Bug fix - [x] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Navigate to the Customers governance page and verify the table fills the viewport without a full-page scrollbar. 2. Enter a search term and paginate — confirm the search and page offset are reflected in the URL and survive a browser back/forward navigation. 3. Clear the search and confirm the offset resets to 0. 4. Delete the last item on the last page and confirm the offset snaps back correctly. 5. Verify no empty-state flash occurs while data is loading on the Customers and Virtual Keys pages. ```sh cd ui pnpm i pnpm build ``` ## Screenshots/Recordings _Add before/after screenshots of the governance table pages showing the full-height layout and updated pagination controls._ ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. URL state contains only non-sensitive pagination and search values. ## 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
## Summary Introduces a new reusable `SearchSelect` component that renders a popover-based search input with a filterable list of selectable options. It supports both synchronous (client-side filtered) and asynchronous (server-driven search) modes. ## Changes - Added `SearchSelect` component built on top of `cmdk` and the existing `Popover`, `Skeleton`, and utility primitives. - Supports controlled and uncontrolled open state via optional `open`/`onOpenChange` props. - Async mode exposes `onSearchChange`, `isSearching`, `isLoading`, `isError`, and `errorMessage` props; when async, the `cmdk` filter is bypassed so results are fully controlled externally. - Provides a default entry view rendering a label, optional description, and a `Plus` icon, with an `entryView` render prop for custom item rendering. - Loading state renders skeleton placeholders; error state renders a destructive message; empty state uses `CommandPrimitive.Empty`. - Accepts a `footer` slot rendered below the list, separated by a border. - Exported `SearchSelect`, `SearchSelectOption`, and `SearchSelectProps` types for external use. ## 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 ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` Render the component with a static options array and verify: 1. The popover opens on trigger click and the search input is auto-focused. 2. Typing filters the list (sync mode). 3. Selecting an item calls `onValueSelect` with the correct option object. 4. In async mode, `onSearchChange` is called on input and loading/error/empty states render correctly. ## Screenshots/Recordings _Add before/after screenshots or a short clip demonstrating the component in use._ ## Breaking changes - [ ] Yes - [x] No ## Related issues _Link related issues and discussions._ ## Security considerations No auth, secrets, or PII involved. Options and search values are UI-local. ## 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
…le layout (#3757) ## Summary Replaces the team create/edit `Dialog` with a `Sheet` (slide-over panel) to provide a more spacious, scrollable editing experience. Also improves the teams table layout to fill the viewport height and updates the pagination controls to a more compact style. ## Changes - Renamed `teamDialog.tsx` → `teamSheet.tsx` and replaced the `Dialog` component with a `Sheet`, giving the form a full-height side panel with a sticky header and sticky footer action bar. - Replaced the generic `FormFooter` component with inline `Cancel` and `Submit` buttons inside the sheet footer, adding a `Tooltip` to surface validation errors and permission warnings directly on the disabled submit button. - Added `isFetching` from `useGetTeamsQuery` and passed it down as `isLoading` to `TeamsTable`, preventing a premature empty state render while data is still loading. - Updated the outer container in `TeamsView` to use `h-[calc(100vh_-_50px)] flex flex-col overflow-y-auto` so the table fills the available viewport height. - Made the teams table layout flex/grow so the table body expands to fill available space, with a sticky `TableHeader` and a `grow` table container. - Reworked pagination into a compact style using ghost icon-only prev/next buttons and a "Page X of Y" indicator with localized entry counts. ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` 1. Navigate to the Governance → Teams page. 2. Verify the teams table fills the viewport height with a sticky header and compact pagination footer. 3. Click **Create Team** — confirm a sheet slides in from the right instead of a modal dialog. 4. Attempt to submit with invalid data — confirm the tooltip on the disabled submit button shows the relevant validation error. 5. Click outside the sheet — confirm it does not close (interaction outside is prevented). 6. Press Escape or click Cancel — confirm the sheet closes correctly. 7. Edit an existing team and save — confirm the sheet closes and the table refreshes. ## Screenshots/Recordings Before/after screenshots recommended showing the dialog → sheet transition and the updated table layout. ## Breaking changes - [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
…tomer, BU, and user rankings (#3766) ## Summary Adds a generic `GetDimensionRankings` API that returns usage rankings (requests, tokens, cost) grouped by a configurable dimension — `team`, `customer`, `business_unit`, or `user` — with period-over-period trend comparison. This replaces the previous enterprise-only `UserRankingsTab` with a unified, reusable rankings component that powers four new dashboard tabs. ## Changes - Added `RankingDimension` type and `DimensionColumnDef` helper mapping each dimension to its underlying log table columns (`team_id`/`team_name`, `customer_id`/`customer_name`, `business_unit_id`/`business_unit_name`, `user_id`) - Implemented `GetDimensionRankings` on `RDBLogStore` with matview acceleration for Postgres when filters are compatible, falling back to direct log table queries otherwise - Added `getDimensionRankingsFromMatView` to query `mv_logs_hourly` and resolve display names from the logs table in a secondary lookup - Both paths compute a previous-period comparison window and attach `RequestsTrend`, `TokensTrend`, and `CostTrend` percentage changes to each result - Wired `GetDimensionRankings` through `HybridLogStore`, the `LogStore` interface, `LoggerPlugin`, and `PluginLogManager` - Registered `GET /api/logs/rankings/by-dimension?dimension=<value>` with input validation against `ValidRankingDimensions` - Extracted shared UI utilities (`TrendBadge`, `SortableHeader`, `formatCost`) from `modelRankingsTab.tsx` into a new `rankingsShared.tsx` module - Added `DimensionRankingsTab` React component with a horizontal bar chart of the top 10 entities and a sortable table with trend indicators - Replaced the enterprise `UserRankingsTab` with four dashboard tabs (Team, Customer, BU, User) each backed by `DimensionRankingsTab` - Each tab uses the existing lazy-load + generation-counter pattern to fetch only on first visit per filter change and warm in the background after 150 ms - Added `dimensionRankingsToCSV` and included all four dimension ranking datasets in CSV/PDF export ## 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 ./framework/logstore/... ./plugins/logging/... ./transports/bifrost-http/... # Verify the endpoint with each dimension curl "http://localhost:8080/api/logs/rankings/by-dimension?dimension=team" curl "http://localhost:8080/api/logs/rankings/by-dimension?dimension=customer" curl "http://localhost:8080/api/logs/rankings/by-dimension?dimension=business_unit" curl "http://localhost:8080/api/logs/rankings/by-dimension?dimension=user" # Verify invalid dimension returns 400 curl "http://localhost:8080/api/logs/rankings/by-dimension?dimension=invalid" # UI cd ui pnpm i pnpm build ``` Navigate to the dashboard and verify the Team Rankings, Customer Rankings, BU Rankings, and User Rankings tabs each load data, display the bar chart and sortable table, and show trend badges. Confirm CSV export includes all four dimension sheets. ## Screenshots/Recordings _Add before/after screenshots of the new dashboard tabs._ ## Breaking changes - [x] No The previous enterprise `UserRankingsTab` is replaced by the new `DimensionRankingsTab` backed by the standard API. Existing model rankings and all other endpoints are unaffected. ## Related issues _Link related issues here._ ## Security considerations The `dimension` query parameter is validated against an explicit allowlist (`ValidRankingDimensions`) before being interpolated into SQL column references. Column names are resolved through a static map (`dimensionColumns`) rather than passed directly from user input, preventing SQL injection. ## 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
…` components (#3797) ## Summary Refactors the dashboard page by extracting per-tab data fetching logic into dedicated `*TabView` wrapper components, replacing the large collection of manual state variables, lazy query hooks, and `ensure*DataLoaded` ref-tracking functions that previously lived directly in `page.tsx`. ## Changes - Introduced five new `forwardRef` tab view components (`OverviewTabView`, `ProviderUsageTabView`, `MCPTabView`, `ModelRankingsTabView`, `DimensionRankingsTabView`), each owning its own RTK Query subscriptions, loading state, and `getData`/`loadData` imperative handle. - Replaced ~300 lines of manual state, lazy hooks, fetch functions, and generation-counter deduplication logic in `page.tsx` with refs to the new tab view components. Export data aggregation now iterates over those refs rather than a large `useMemo` object. - Each tab view uses an `active` prop (driven by the current tab value or `pdfMode`) to skip fetching when the tab is not visible, delegating the skip logic to RTK Query's built-in `skip` option instead of manual `fetchedRef`/`loadingRef` guards. - Exported `useGetModelRankingsQuery`, `useGetDimensionRankingsQuery`, `useGetMCPCostHistogramQuery`, and `useGetMCPTopToolsQuery` non-lazy hooks from the store APIs to support the new subscription-based approach. - Moved `sanitizeSeriesLabels` into the tab views that need it (`OverviewTabView`, `ProviderUsageTabView`) rather than keeping it in the page. - Reordered the "User Rankings" tab trigger to appear before "Customer Rankings" and "BU Rankings" in the tab list. - Removed the background warm-up `setTimeout` effect and the filter-change `useEffect` that reset all fetch flags, as RTK Query cache invalidation now handles re-fetching automatically. ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` 1. Open the dashboard and verify each tab loads its data correctly when first visited. 2. Change a filter (e.g., time range or provider) and confirm all visible and previously loaded tabs refresh. 3. Trigger a CSV and PDF export and confirm all tab data is included. 4. Verify PDF export correctly force-mounts all tabs and captures each section. ## Screenshots/Recordings No visual changes expected; this is a pure refactor of data-fetching logic. ## 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
## Summary Fixes missing `user_name` column mapping for the `RankingDimensionUser` dimension, ensuring user-based rankings can resolve display names alongside user IDs. ## Changes - Added `user_name` as the `NameCol` for `RankingDimensionUser` in the `dimensionColumns` map. Previously this was an empty string, meaning user dimension queries would not retrieve a name column, leaving user rankings without a human-readable name. ## 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 Verify that ranking queries grouped by the user dimension now return a populated `user_name` field alongside `user_id`. ```sh go test ./framework/logstore/... ``` ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues N/A ## Security considerations No security implications. This change only affects which column name is used when querying user dimension data. ## 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** * Fixed an issue where user names were not properly displayed in dimension ranking queries. User dimension data now correctly references the user name field for improved data visualization. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3869?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 -->
…uncated labels (#3877) ## Summary Extracts the "Assigned To" cell logic in the Virtual Keys table into a dedicated `VKAssignedToCell` component, and adds tooltip support so truncated labels are fully readable on hover. ## Changes - Introduced `VKAssignedToCell` component that handles display logic for team, customer, and user assignments, including pulling the assigned user from `useVirtualKeyUsage` - Added a `Tooltip` wrapping the `Badge` so that when the label is truncated, hovering reveals the full text - Replaced the inline conditional rendering in the table row with the new component ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test Navigate to the Virtual Keys table and verify: 1. Keys assigned to a team show `Team: <name>` badge with a tooltip on hover 2. Keys assigned to a customer show `Customer: <name>` badge with a tooltip on hover 3. Keys assigned to a user show `User: <name or email>` badge with a tooltip on hover 4. Unassigned keys show `-` as before ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings _Add before/after screenshots showing the tooltip appearing on hover over a truncated assignment badge._ ## 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 * **Improvements** * Enhanced the Virtual Keys table "Assigned To" column with improved display formatting. Assignment information (team, customer, or assigned user) now appears with interactive tooltips for additional context. When no assignment is configured, a clear placeholder indicator is displayed instead. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3877?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 -->
## Summary JSON Schema `$defs` (and legacy `definitions`) were being silently dropped when MCP tools were converted to Bifrost's internal schema representation and when Bifrost tools were cloned or forwarded to providers. This left `$ref` pointers inside `properties` dangling, causing providers such as Vertex Gemini to reject the tool schema with `INVALID_ARGUMENT`. ## Changes - **MCP → Bifrost conversion** (`core/mcp/utils.go`): `$defs` from `mcp.ToolInputSchema.Defs` are now preserved and carried through to `ToolFunctionParameters.Defs`, with the same array-schema normalization applied to definitions as to properties. - **Deep copy** (`core/schemas/utils.go`): Extracted a standalone `DeepCopyToolFunctionParameters` function that copies every JSON Schema field (`$defs`, `definitions`, `$ref`, `items`, `minItems`, `maxItems`, `anyOf`, `oneOf`, `allOf`, `format`, `pattern`, `minLength`, `maxLength`, `minimum`, `maximum`, `title`, `default`, `nullable`). The previous implementation only copied a small subset of fields. Helper functions `deepCopyOrderedMap`, `deepCopyOrderedMapSlice`, and `deepCopySchemaValue` were added to support recursive deep copying of `OrderedMap` values. - **Anthropic provider** (`core/providers/anthropic/chat.go`): Replaced the manual field-by-field struct copy with a call to `DeepCopyToolFunctionParameters`, ensuring all schema fields are forwarded. - **MCP server handler** (`transports/bifrost-http/handlers/mcpserver.go`): Extracted `convertToolFunctionParametersToMCPInputSchema`, which maps `Defs` (and falls back to `Definitions`) back onto `mcp.ToolInputSchema.Defs` so that round-tripped tools retain their definitions. ## 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/mcp/... go test ./core/schemas/... go test ./core/providers/gemini/... go test ./transports/bifrost-http/handlers/... ``` New tests cover: - `TestConvertMCPToolToBifrostSchema_PreservesDefs` — verifies `$defs` survive MCP → Bifrost conversion and appear in marshalled output. - `TestSonic_ChatTool_DeepCopy_PreservesFullParameterSchema` — verifies all schema fields are deep-copied independently (mutation of the copy does not affect the original). - `TestConvertBifrostToolsToGemini_WirePayloadPreservesDefs` — verifies `$defs` and `$ref` appear in the Gemini wire payload. - `TestConvertToolFunctionParametersToMCPInputSchemaPreservesDefs` / `...PreservesLegacyDefinitionsAsDefs` — verifies both `Defs` and `Definitions` are mapped correctly when converting back to MCP input schema. ## Breaking changes - [ ] Yes - [x] No ## Related issues Fixes Vertex Gemini `INVALID_ARGUMENT` errors caused by dangling `$ref` pointers in tool schemas. ## Security considerations No auth, secrets, PII, or sandboxing changes. The fix is limited to schema field propagation during tool conversion and cloning. ## 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
## Summary `output_text.done`, `content_part.done`, and `output_item.done` stream events were being emitted with empty text content instead of the full accumulated text. This PR fixes that by introducing a `TextBuffers` map in each provider's stream state to accumulate text deltas as they arrive, then populating the done events with the complete text. Additionally, tools with a `nil` or empty name are now skipped before being sent to Anthropic, which previously caused Anthropic to reject the request. ## Changes - Added `TextBuffers map[int]string` to the stream state structs for Anthropic, Bedrock, and Cohere providers, accumulating text deltas keyed by output index - Updated `output_text.done`, `content_part.done`, and `output_item.done` events across all four providers (Anthropic, Bedrock, Cohere, Gemini) to include the full accumulated text in their payloads rather than empty strings - Populated `ContentBlocks` in `output_item.done` messages with the actual text content block instead of an empty slice - Cleaned up `TextBuffers` entries via `delete` after emitting done events to avoid stale state - Ensured `TextBuffers` is properly initialized and cleared in pool acquire/flush paths - Skipped Anthropic tool conversion when `tool.Name` is `nil` or empty to prevent Anthropic API rejections ## Type of change - [x] Bug fix ## Affected areas - [x] Core (Go) - [x] Providers/Integrations ## How to test ```sh go test ./... ``` Stream a response from each affected provider (Anthropic, Bedrock, Cohere, Gemini) using the Responses API and verify that: - `output_text.done` events contain the full assembled text - `content_part.done` events include a `Part` with the full text - `output_item.done` events include a `Content.ContentBlocks` array with the complete text block - Sending a tool with no name to Anthropic no longer causes a request rejection ## Breaking changes - [ ] Yes - [x] No ## 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** * Streaming responses now accumulate per-output text and include full text in final completion events (avoids empty text/content blocks) across provider integrations. * Tool entries with missing or empty names are skipped during processing. * Stream state pooling lifecycle fixed to prevent cross-request text reuse by allocating, clearing, and releasing per-output text buffers between requests. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3838?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 -->
…nt (#3880) ## Summary Anthropic's API requires the `input` field to always be present on `tool_use` blocks. When a tool takes no arguments, the field was previously left unset, causing API errors. This PR ensures `input` defaults to an empty JSON object (`{}`) in those cases. ## Changes - In `convertBifrostFunctionCallToAnthropicToolUse`, `convertBifrostMCPCallToAnthropicToolUse`, and `convertBifrostMCPApprovalToAnthropicToolUse`, added an `else` branch that sets `toolUseBlock.Input` to `json.RawMessage("{}")` when no arguments are provided. ## 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 Send a tool call to the Anthropic provider where the tool accepts no arguments (i.e., arguments are `nil` or an empty string). Verify the request succeeds and the resulting `tool_use` block contains `"input": {}` rather than an absent or null `input` field. ```sh go test ./... ``` ## 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
## Summary
This PR adds full guardrail support to the Bedrock Responses API path. Previously, guardrail-related fields (`guardrailConfig`, `performanceConfig`, `promptVariables`, `requestMetadata`) passed via `ExtraParams` were not extracted into the typed Bedrock request struct, and guardrail trace data returned by Bedrock was silently dropped rather than being surfaced to callers.
## Changes
- `ToBedrockResponsesRequest` now extracts `guardrailConfig`, `performanceConfig`, `promptVariables`, and `requestMetadata` from `ExtraParams` into their respective typed fields on `BedrockConverseRequest`, removing them from `ExtraParams` to prevent double-sending. `ExtraParams` is set to `nil` when emptied.
- `BedrockConverseResponse.ToBifrostResponsesResponse` now stores the Bedrock `Trace` field in `ProviderExtraFields["trace"]` so it is visible to callers.
- `ToBedrockConverseResponse` and `ToBedrockConverseStreamResponse` restore the guardrail trace from `ProviderExtraFields["trace"]` back onto the Bedrock response struct, enabling round-trip fidelity.
- `FinalizeBedrockStream` accepts a new `trace *BedrockConverseTrace` parameter. When a `Trace` event is received mid-stream, it is captured and attached to the `response.completed` event's `ProviderExtraFields`.
- `BifrostResponsesResponse` gains a `ProviderExtraFields map[string]interface{}` field for carrying provider-specific metadata that does not fit the standard schema.
- `NewBedrockResponsesStreamState` is exported to allow stream state construction in tests.
- Tests are added covering guardrail config extraction, trace round-tripping through non-streaming and streaming responses, and `FinalizeBedrockStream` trace propagation.
## Type of change
- [x] Bug fix
- [x] Feature
## Affected areas
- [x] Core (Go)
- [x] Providers/Integrations
## How to test
```sh
go test ./core/providers/bedrock/... -v -run "TestToBedrockResponsesRequest_GuardrailConfig|TestBedrockToBifrostResponse_TraceStoredInProviderExtraFields|TestBifrostToBedrockResponse_TraceRestoredFromProviderExtraFields|TestFinalizeBedrockStream_WithTrace"
```
To validate end-to-end, invoke a Bedrock model with a guardrail configured via `ExtraParams`:
```json
{
"guardrailConfig": {
"guardrailIdentifier": "<your-guardrail-id>",
"guardrailVersion": "DRAFT",
"trace": "enabled"
}
}
```
Expect the response to include a `provider_extra_fields.trace` object containing the guardrail evaluation result, and confirm `ExtraParams` is not forwarded to the Bedrock API.
## Breaking changes
- [x] Yes
`FinalizeBedrockStream` has a new required `trace` parameter. Any external callers of this function must be updated to pass `nil` if no trace is available.
## Related issues
## Security considerations
Guardrail trace data may contain information about blocked content or policy evaluations. `ProviderExtraFields` is included in the serialized response (`json:"provider_extra_fields,omitempty"`); ensure downstream consumers handle this field appropriately if responses are logged or forwarded.
## Checklist
- [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
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Preserve guardrail trace data across streaming and finalized responses; include trace metadata in stream completion events.
* Allow provider-specific extra fields in Responses payloads and forward guardrail configuration from request parameters.
* **Tests**
* Added unit, integration, and e2e tests verifying guardrail config forwarding, trace persistence/restoration, and finalization of streamed responses with trace data.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3862?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 -->
## Summary Adds support for mid-conversation `role:"system"` messages in the Anthropic messages array, a feature available on the Anthropic API with Claude Opus 4.8+. Previously, any system message encountered after the first user/assistant turn was either silently dropped or incorrectly handled. This PR introduces provider+model-aware routing so that mid-conversation system messages are emitted natively where supported, and gracefully merged into the top-level `system` field as a fallback where they are not. ## Changes - Added `AnthropicMessageRoleSystem` constant and updated `AnthropicMessage.Role` docs to reflect the new valid value. - Added `SupportsMidConversationSystem(provider, model)` helper that returns `true` only for `provider=Anthropic` + a model name containing `opus` and `4-8`/`4.8`. Bedrock, Vertex, and all other model families return `false`. - Added `appendToSystemContent` helper that normalises two `AnthropicContent` values to content-block form and concatenates them, used when a mid-conversation system message must be folded into the top-level `system` field without losing data. - Updated `ToAnthropicChatRequest` to track a `seenConversation` flag. System messages encountered before any user/assistant turn continue to populate the top-level `system` field. After the first turn, they are either emitted as `role:"system"` in the messages array (supported path) or appended to the top-level `system` field (fallback path). - Applied the same three-way logic (`emit`, `append-to-system`, `initial-system`) to `ConvertBifrostMessagesToAnthropicMessages` in the Responses path, with `provider` and `model` threaded through as new parameters. - Updated all call sites of `ConvertBifrostMessagesToAnthropicMessages` to pass provider/model; response-conversion call sites pass empty strings, disabling mid-conversation system emission for output messages. - Added unit tests covering `SupportsMidConversationSystem`, mid-conversation system handling for Opus 4.8 (native), Bedrock (fallback), and Opus 4.7 (fallback). - Added a full round-trip test suite (`roundtrip_test.go`) covering eight scenarios: top-level system only, top-level + mid-conv on supported/unsupported provider/model, no top-level system with mid-conv only, multiple mid-conv messages, and content-block variants. - Added E2E harness entries for mid-conversation system message scenarios across Anthropic, Bedrock, Vertex, and Opus 4.7 fallback paths. ## Type of change - [ ] Bug fix - [x] 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/... -v -run "TestSupportsMidConversationSystem|TestToAnthropicChatRequest_MidConversation|TestRoundTrip" ``` Expected: all new tests pass. The round-trip tests validate that: - Anthropic + Opus 4.8 preserves mid-conversation system messages as `role:"system"` entries in the messages array at their original positions. - Bedrock, Vertex, and Opus 4.7 merge mid-conversation system content into the top-level `system` field in order, with no `role:"system"` entries appearing in the messages array. - Multiple mid-conversation system messages are handled correctly in both paths. For E2E validation, run the updated `provider-harness.json` collection against a running instance. The "Cross-Cut Round 29: Mid-Conversation System Message Matrix" folder covers all provider/model combinations. ## Breaking changes - [x] Yes - [ ] No `ConvertBifrostMessagesToAnthropicMessages` now requires two additional parameters (`provider schemas.ModelProvider`, `model string`). Any external callers of this function must be updated to pass the provider and model, or pass empty strings to opt out of mid-conversation system support. ## Related issues ## Security considerations None. No new auth flows, secrets handling, or PII processing introduced. ## 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 * **New Features** * Anthropic Opus 4.8+ now preserves mid‑conversation system messages as explicit role:"system" entries; unsupported providers/models gracefully merge such system content into top‑level system blocks. * **Tests** * Added unit, round‑trip, and end‑to‑end validations covering mid‑conversation system handling across providers, model versions, and content formats (including content blocks and fallback cases). <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3878?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 -->
## Summary The default materialized view refresh interval for the PostgreSQL log store has been changed from 30 seconds to 1 minute. This reduces the frequency of `REFRESH MATERIALIZED VIEW CONCURRENTLY` operations, which are expensive and can be too aggressive on smaller or CPU-constrained database instances. Additionally, `ensureMatViews` (startup create/repair) and `refreshMatViews` (periodic refresh) have been consolidated to share a single advisory lock key (`matviewRefreshAdvisoryLockKey`), eliminating the separate `matviewEnsureAdvisoryLockKey`. This prevents startup maintenance from overlapping with a periodic refresh in multi-replica deployments. ## Changes - Default `matview_refresh_interval` changed from `30s` to `1m` in code, config schema, and documentation. - Removed the separate `matviewEnsureAdvisoryLockKey` (`1000006`); `ensureMatViews` now uses the same advisory lock as `refreshMatViews` (`1000005`) so the two operations are mutually exclusive. - Updated `filterDataCacheTTL` comment in the logging handler to remove the hardcoded reference to the 30s cadence. - Added `matviews_lock_test.go` with tests covering advisory lock lifecycle for both `refreshMatViews` and `ensureMatViews`, including: normal lock acquisition and release, skipping when the lock is held, recovery after a session closes, and context cancellation behavior for the migration lock. ## Type of change - [ ] Bug fix - [x] Feature - [x] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test ```sh go test ./framework/logstore/... -run TestResolveMatViewRefreshIntervalDefaults go test ./framework/logstore/... -run TestRefreshMatViewsAdvisoryLockLifecycle go test ./framework/logstore/... -run TestEnsureMatViewsSharesRefreshAdvisoryLock go test ./framework/logstore/... -run TestMigrationLockContextCancellationAndSessionRelease ``` These tests require a running PostgreSQL instance. Verify that: - The default refresh interval resolves to `1m`. - A held advisory lock causes `refreshMatViews` to skip without blocking. - `ensureMatViews` skips materialized view creation while the refresh lock is held, and proceeds once released. - Context cancellation on `acquireMigrationLock` returns an error and the lock is acquirable after the blocking session closes. If deploying to an existing instance, note that the effective refresh cadence will double from 30s to 1m. Dashboard stats and histograms will have up to 1 minute of lag instead of 30 seconds. ## Breaking changes - [x] Yes - [ ] No Existing deployments will see the materialized view refresh cadence change from 30 seconds to 1 minute. Dashboard stats freshness lag increases accordingly. Operators who require sub-minute freshness should explicitly set `matview_refresh_interval: "30s"` in their config. ## Related issues ## Security considerations None. This change affects only internal database maintenance scheduling and advisory lock coordination. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] 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 * **Documentation** * Updated PostgreSQL logs_store materialized view refresh interval default from 30 seconds to 1 minute in configuration documentation and schema. * **Tests** * Added comprehensive test coverage for materialized view refresh advisory lock behavior, interval defaults, and migration locking mechanisms. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3886?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 -->
…ver tool manager overrides (#3870) ## Summary This PR clarifies how identity mode (user/vk/session) is stamped onto MCP auth flows at mint time and what that means for who can open and complete the resulting URL. It also documents the `mcp_enable_temp_token_auth` toggle, which controls whether VK/session-mode flows carry a short-lived `#t=<temp-token>` URL fragment allowing anonymous browser visitors to complete them without a dashboard session. User-mode flows — including those triggered by user-owned VKs that auto-promote to user-mode — never mint a temp token and always require SSO login. Additionally, per-MCP-server `tool_manager_config` overrides are documented. ## Changes - **Identity mode table** (`overview.mdx`): Expanded the `user` and `vk` mode descriptions to clarify that user-owned VKs auto-promote to `user` mode, and that `vk` mode only applies to VKs not owned by a user. - **Flow mode and access rules section** (`overview.mdx`): New section added explaining that the identity mode is frozen onto the flow row at mint time, with a table covering who can open the URL, whether a temp token is included, and whether a dashboard login is required per mode. - **`mcp_enable_temp_token_auth` toggle** (`overview.mdx`): New subsection documenting the toggle with Web UI, API, and `config.json` configuration examples. Clarifies that user-mode flows ignore the toggle entirely. - **Per-user OAuth and per-user headers docs**: Updated example auth URLs to omit the `#t=…` fragment by default, replacing the old blanket description with references to the new flow mode rules and toggle docs. - **Gateway docs** (`gateway.mdx`): Added a brief callout explaining who can open and complete a minted auth URL, with a link to the full flow mode rules. - **Sessions docs** (`sessions.mdx`): Updated identity scoping description and the `"This authentication flow isn't yours"` accordion (renamed to match the actual error message) to distinguish user-mode vs. VK/session-mode behavior. - **Per-MCP-server `tool_manager_config`** (`connecting-to-servers.mdx`): Documented the ability to override global tool-manager knobs (`tool_execution_timeout`, `max_agent_depth`, `code_mode_binding_level`, `disable_auto_tool_inject`) on a per-server basis. - **`MCPEnableTempTokenAuth` comments** (`clientconfig.go`, `tables/clientconfig.go`, `config.schema.json`): Updated inline comments and JSON schema description to reflect that the toggle applies to both per-user OAuth and per-user-headers flows, and that user-mode flows never mint regardless. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test 1. Configure a VK owned by a user and trigger an MCP tool call requiring per-user auth — confirm the resulting flow is in `user` mode and the auth URL carries no `#t=…` fragment. 2. Configure a VK not owned by a user and trigger the same flow — confirm it lands in `vk` mode. 3. With `mcp_enable_temp_token_auth: false` (default), confirm VK/session-mode auth URLs have no `#t=…` fragment and require a dashboard session to complete. 4. Enable `mcp_enable_temp_token_auth: true` and repeat — confirm VK/session-mode URLs now carry a `#t=…` fragment and can be completed without a dashboard session. 5. Attempt to open a user-mode flow URL as a different SSO user — confirm a `403` is returned. 6. Configure a per-server `tool_manager_config` block and confirm it overrides the global `mcp_*` values only for that server. ```sh go test ./... ``` ## Breaking changes - [x] No ## Security considerations User-mode flows (including those triggered by user-owned VKs) are explicitly excluded from temp token minting regardless of the `mcp_enable_temp_token_auth` setting. This ensures SSO-bound credentials cannot be completed by an anonymous or unrelated browser visitor. The `#t=…` fragment is intentionally placed in the URL fragment so it is never transmitted in server request logs. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [x] 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 * **Documentation** * Clarified identity modes and user>vk>session priority; who may open/complete auth flows and mismatched-user behavior. * Added “Flow mode and access rules” and detailed temp-token behavior plus the temp-token toggle with Web UI/API/config examples. * Scoped when `#t` fragments appear for per-user OAuth and headers and effects on anonymous completion. * Added global tool-manager settings and expanded TLS client-config descriptions. * Minor UI screenshot and troubleshooting wording updates. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3870?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 -->
…tibility notes, and model name updates (#3882) ## Summary Expands the Claude Code integration docs to cover non-Anthropic model pinning, MCP gateway usage, and provider compatibility caveats. Also corrects Haiku model identifiers across all provider examples and fixes minor typos in the MCP auth and gateway pages. ## Changes - Added explanatory paragraphs to the "Using alias" and "Using provider-specific model pinning" sections clarifying how each approach works under the hood (dynamic vs. static aliasing) and that any Bifrost-configured provider can be targeted, not just Claude-family models. - Added a new "Other providers (OpenAI, Gemini, etc.)" subsection under provider-specific pinning with a JSON example and a warning about tool-calling compatibility. - Corrected `ANTHROPIC_DEFAULT_HAIKU_MODEL` values from `claude-haiku-4-6` to `claude-haiku-4-5` across Anthropic, Bedrock, Vertex, and Azure examples. - Updated `--model` flag and `/model` command examples to use current model identifiers and added non-Anthropic provider examples (`openai/gpt-5.5`, `vertex/gemini-3.1-pro`). - Rewrote the Provider Compatibility section from a warning block into a structured prose section covering Claude-specific server-side tools, streaming tool-call argument issues (OpenRouter), and Azure verification requirements. - Added a full "Using Bifrost as an MCP Gateway" section covering `claude mcp add` CLI usage, `.mcp.json` / `~/.claude.json` config, identity header modes (user/vk/session), the auto tool injection deduplication caveat, verification steps, and an FAQ accordion group addressing common errors (`405` re-authenticate, reconnect failures, missing tools, per-user OAuth prompts). - Fixed "Iff" → "If" typos in the MCP auth overview flow-mode table. - Updated UI navigation label from "Settings → MCP" to "MCP Gateway → MCP Settings" and button label from "Save" to "Save Changes" in the temp token auth toggle instructions; added a screenshot. - Added `docs/media/ui-mcp-toggle-temp-token.png` screenshot asset. - Removed the `mcp_external_server_url` config entry from the reverse proxy section and the "Claude Desktop not connecting" troubleshooting accordion from the gateway page. - Fixed a garbled sentence in the gateway.mdx OAuth probe note. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test Review the rendered docs for the following pages: - `docs/cli-agents/claude-code.mdx` — verify alias, provider pinning, MCP gateway, and provider compatibility sections render correctly including the new FAQ accordions and screenshot. - `docs/mcp/auth/overview.mdx` — verify the flow-mode table and toggle instructions render correctly with the new screenshot. - `docs/mcp/gateway.mdx` — verify the OAuth probe note and reverse proxy section are coherent after edits. ## Screenshots/Recordings Added `docs/media/ui-mcp-toggle-temp-token.png` showing the MCP Settings toggle for Allow Temp Token Auth Links. ## Breaking changes - [ ] Yes - [x] No ## Related issues See upstream Claude Code MCP re-authenticate bug: anthropics/claude-code#46640 ## Security considerations No auth, secrets, or PII changes. The identity mode table and session-mode warning clarify that `enforce_auth_on_inference=false` is required for session-only callers, which is an existing behavior being documented rather than a new capability. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [ ] I added/updated tests where appropriate - [x] 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 * **Documentation** * Expanded Claude Code documentation with guidance on Bifrost dynamic aliasing and model pinning for Anthropic and third-party providers. * Added comprehensive MCP Gateway setup instructions, including MCP server configuration and identity header usage for per-user scenarios. * Clarified OAuth configuration variables and updated authentication flow documentation. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3882?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 -->
## Summary Re-enables HTTP request logging in the CORS middleware that was previously commented out. Each completed request is now logged with method, URI, status code, duration, remote address, user agent, and trace ID (when available). ## Changes - Uncommented the `startTime` initialization and the deferred logging block in `CorsMiddleware` - Log level is set dynamically based on response status: `error` for 5xx, `warn` for 4xx, and `info` for all others - Trace ID is included in the log entry when present in the request context - Requests matching `loggingSkipPaths` (e.g. `/health`) continue to bypass logging ## 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 Send requests to the HTTP transport and verify log output appears for non-health-check endpoints. ```sh go test ./... ``` - Make a successful request and confirm an `info`-level log entry is emitted with correct fields - Make a request that returns a 4xx and confirm a `warn`-level log is emitted - Make a request that returns a 5xx and confirm an `error`-level log is emitted - Hit `/health` and confirm no log entry is produced ## Breaking changes - [ ] Yes - [x] No ## Security considerations Logged fields include remote address and user agent. Ensure these are acceptable to log in your deployment environment, particularly in contexts with strict PII or data residency requirements. ## 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 * **Chores** * Enabled HTTP request logging that records method, request URI, response status, processing duration (ms), remote address, user agent, and optional trace identifier. * Logging is skipped for health and internal asset/dev endpoints. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3885?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 -->
… refresh migration and update schema with new fields (#3883) ## Summary Fixes a migration ordering bug where `migrationReAddAllowDirectKeysColumn` was running after `migrationRefreshConfigHashAfterMCPExternalServerURLRemoval`, causing a `"no such column: allow_direct_keys"` failure on databases where the earlier drop migration had already run. The fix moves `migrationReAddAllowDirectKeysColumn` to execute before the config hash refresh migration. Additionally, several schema additions are included to keep the config schema in sync with current struct definitions. ## Changes - Moved `migrationReAddAllowDirectKeysColumn` to run before `migrationRefreshConfigHashAfterMCPExternalServerURLRemoval` in the migration chain, since the hash refresh migration SELECTs `config_client` using the `TableClientConfig` struct which still declares `allow_direct_keys` - Added `allow_direct_keys` to the config schema under the client config section - Added `source_id` field to the team schema for optional external source identifier (e.g. SCIM group ID) mapping - Added `blacklisted_models` array field to the provider config schema for blocking specific models even when matched by `allowed_models` - Added `per_user_headers` as a valid `auth_type` enum value for MCP connections - Added `per_user_header_keys` array field to MCP connection config for specifying required caller-supplied headers when using `per_user_headers` auth - Added `governance.virtual_keys` exclusion for `access_profile_id` in the schema field test, as it is an enterprise-only field not present on the OSS `TableVirtualKey` ## Type of change - [x] Bug fix - [x] Feature ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) ## How to test ```sh go test ./framework/configstore/... go test ./transports/bifrost-http/lib/... ``` Verify that on a database where `drop_allow_direct_keys_column_ddl` has previously run, the full migration chain completes without a `"no such column: allow_direct_keys"` error. Confirm the config schema validates correctly against the updated `config.schema.json`. ## Breaking changes - [ ] Yes - [x] No ## Related issues The migration ordering issue would cause startup failures on any deployment that had previously run the column-drop migration before the config hash refresh migration was introduced. ## Security considerations The `allow_direct_keys` feature permits callers to bypass the registered key pool by supplying a raw provider API key via `x-bf-direct-key`. Ensure this field defaults to `false` and is only enabled intentionally, as it bypasses key management controls. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [ ] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
…utils (#3844) ## Summary The `isModelRequired` method on `BudgetResolver` was only accessible internally, limiting its reuse across the governance package. This PR promotes it to an exported utility function so it can be used in other contexts beyond the resolver. ## Changes - Removed the private `isModelRequired` method from `BudgetResolver` in `resolver.go` - Added an equivalent exported function `IsModelRequiredForRequest` in `utils.go` - Updated the call site in `EvaluateVirtualKeyRequest` to use the new exported function ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./plugins/governance/... ``` Verify that model filtering behavior for virtual key evaluation remains unchanged — requests such as batch, file, container, video, passthrough, list models, and MCP tool execution should bypass model requirement checks, while all other request types should still enforce model filtering. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No security implications. This is a refactor of an existing internal check with no behavioral changes. ## 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 * **Refactor** * Consolidated model requirement decision logic into a centralized utility function for improved consistency across request handling. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3844?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 -->
…` with `awk` for column-order-safe snapshot comparison (#3889) ## Summary Adds migration test support for the new `mcp_enable_temp_token_auth` config column and fixes a column-ordering bug in the Postgres snapshot comparison logic that caused false failures when columns were dropped and re-added via `ALTER TABLE ADD COLUMN`. ## Changes - Added `mcp_enable_temp_token_auth` to the dynamic column append logic for both Postgres and SQLite migration tests, setting it to `false`/`0` when the column exists. - Replaced `cut -f` with `awk` in `compare_postgres_snapshots` for extracting columns during before/after snapshot comparison. `cut` always emits fields in ascending positional order regardless of the column spec, which causes row misalignment when a column's physical position in the after-schema differs from its logical position (e.g. a column dropped and re-added ends up at the end of the table). `awk` respects the specified field order, producing correct alignment. ## Type of change - [x] Bug fix - [x] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test Run the migration test suite and verify that snapshot comparisons pass correctly, including for tables where columns have been dropped and re-added. ## Breaking changes - [x] No ## 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
## Summary
Updates the provider harness test suite to use correct and available Azure model names, adds support for passing AWS Bedrock Guardrail identifiers and versions into the Newman test runner, and pins the Bedrock performance config test to a model that supports it.
## Changes
- Added `BEDROCK_GUARDRAIL_IDENTIFIER` and `BEDROCK_GUARDRAIL_VERSION` environment variable passthrough to the Newman invocations in the `Makefile`, allowing guardrail-aware Bedrock tests to be run from the harness
- Replaced `azure/text-embedding-2-ada` with the correct model name `azure/text-embedding-ada-002` across all embedding test entries (OpenAI, OpenAI-compat, and GenAI endpoints)
- Replaced `azure/whisper-1` with `azure/gpt-4o-transcribe` for audio transcription tests
- Replaced `azure/tts-1` with `azure/gpt-4o-mini-tts` for text-to-speech tests
- Changed the "Bedrock Converse: performance config optimized" test to target `us.amazon.nova-pro-v1:0` directly instead of the generic `{{bedrockModel}}` variable, since `performanceConfig` is only supported on specific models
- Replaced `openai/gpt-5` with `openai/gpt-4o-mini` in the stop sequences cross-cut test
## Type of change
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [x] Chore/CI
## Affected areas
- [ ] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs
## How to test
Run the provider harness with optional Bedrock guardrail variables:
```sh
# Without guardrails
make run-provider-harness-test
# With guardrails
BEDROCK_GUARDRAIL_IDENTIFIER=my-guardrail-id \
BEDROCK_GUARDRAIL_VERSION=1 \
make run-provider-harness-test
```
Verify that:
- Azure embedding, transcription, and TTS tests pass with the updated model names
- The Bedrock performance config test passes when targeting `us.amazon.nova-pro-v1:0`
- The stop sequences cross-cut test passes with `openai/gpt-4o-mini`
- Guardrail env vars are forwarded to Newman when set
## Breaking changes
- [ ] Yes
- [x] No
## Related issues
## Security considerations
`BEDROCK_GUARDRAIL_IDENTIFIER` and `BEDROCK_GUARDRAIL_VERSION` are passed as Newman environment variables. These values are not secrets but should be treated as infrastructure configuration and kept out of public logs if they reference sensitive guardrail resources.
## 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
* **Chores**
* Updated test harnesses to use newer Azure model identifiers for embeddings and audio services, including GPT-4o variants.
* Enhanced test execution to support Bedrock guardrail configuration parameters.
* Updated test matrices with latest model versions for improved compatibility testing.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3887?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 -->
## Summary Renames the model catalog API endpoint from `/api/model-catalog` to `/api/models/catalog` to align with the existing `/api/models/*` route namespace convention. ## Changes - Updated the route registration in `providers.go` from `PUT /api/model-catalog` to `PUT /api/models/catalog` - Updated the corresponding UI API client URL from `/model-catalog` to `/models/catalog` - Updated comments and documentation strings to reflect the new endpoint path ## Type of change - [ ] Bug fix - [ ] Feature - [x] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [x] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh # Core/Transports go test ./transports/bifrost-http/... # UI cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` Verify that a `PUT` request to `/api/models/catalog` with a valid `ModelPricingAttributesEntry` payload succeeds, and that the old `/api/model-catalog` path returns a 404. ## Screenshots/Recordings N/A ## Breaking changes - [x] Yes - [ ] No Any clients calling `PUT /api/model-catalog` directly must update to `PUT /api/models/catalog`. The UI client has been updated accordingly. ## Related issues N/A ## Security considerations None. This is a route rename with no changes to authentication, authorization, or data handling. ## 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 * **Chores** * Standardized API endpoint path for model catalog management operations to follow naming conventions. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3893?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 -->
#3896) ## Summary Fixes a UI flash where the dashboard sidebar would briefly collapse to a single tab and the active route would momentarily render `NoPermissionView` on initial page load. This happened because RBAC permissions are restored asynchronously from `sessionStorage` before being refreshed from the API, causing `useRbac()` to return `false` for all permissions during that first frame. ## Changes - Exposed `isLoading` from `useRbacContext` in `AppContent` to detect when RBAC permissions have not yet resolved. - Gates the full dashboard chrome behind the RBAC loading state, rendering a `FullPageLoader` instead until permissions are available. Since the cached read from `sessionStorage` resolves in a single frame, this is imperceptible to users. - Minimal and public shells are unaffected, as they do not rely on RBAC and are handled by early returns before this gate. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test 1. Log in and navigate to the dashboard. 2. Observe that the sidebar renders fully on load without collapsing or flashing `NoPermissionView`. 3. Hard-refresh the page and confirm the same behavior. ```sh cd ui pnpm i || npm i pnpm build || npm run build ``` ## Screenshots/Recordings Before: Sidebar briefly collapses to a single tab and the active route flashes `NoPermissionView` on load. After: A `FullPageLoader` is shown for a single frame while RBAC resolves, then the full dashboard renders correctly. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No security implications. This change only affects rendering timing and does not alter permission enforcement logic. ## 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
## Summary Metadata stored on a log entry was not being included in the object storage payload, meaning it was lost when a log was reconstructed from object storage. This PR ensures metadata is copied into the object payload and correctly restored on read, while intentionally remaining in the database so that metadata-based filtering, ranking, and list display continue to work. ## Changes - Added `"metadata"` to the `payloadFields` list so it is recognized as a payload field. - Updated `ExtractPayload` to include the serialized `Metadata` string in the payload map. - Updated `MergePayloadFromJSON` to restore `Metadata` (and trigger `DeserializeFields` to repopulate `MetadataParsed`) when merging a payload back into a log. - Added a no-op case for `"metadata"` in `clearPayloadField` with an explicit comment explaining that metadata is intentionally not cleared from the DB, unlike other payload fields that are offloaded to object storage. - Added `TestHybrid_MetadataIsCopiedToObjectPayloadAndRetainedInDB` to verify end-to-end that metadata appears in the object store payload and is retrievable via `FindByID` with the correct parsed values. - Extended `TestExtractPayload_RoundTrip` to cover metadata extraction, preservation through `ClearPayload`, and restoration via `MergePayloadFromJSON`. ## Type of change - [x] Bug fix ## Affected areas - [x] Core (Go) ## How to test ```sh go test ./framework/logstore/... ``` The new test `TestHybrid_MetadataIsCopiedToObjectPayloadAndRetainedInDB` creates a log entry with metadata, waits for the object store upload, then asserts: 1. The DB record retains the metadata field. 2. The object store payload contains a `"metadata"` key with the correct JSON. 3. `FindByID` returns the log with `MetadataParsed` correctly populated. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations Metadata may contain user-identifying information (e.g. `cortex-user-id`). No new exposure surface is introduced — metadata was already stored in the database; this change ensures it is also present in object storage payloads, which should be subject to the same access controls as other payload data. ## 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 * **Improvements** * Improved metadata handling in hybrid log storage so metadata is always included in object payloads and remains synchronized with the database. * **Tests** * Added end-to-end test to verify metadata is copied into stored object payloads and restored on retrieval. * Enhanced payload round-trip tests to validate metadata serialization, deserialization, and preservation across storage layers. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3888?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 -->
## Summary
Bedrock enforces a strict tool name format: names must match `[A-Za-z0-9_-]{1,64}`. MCP tool names (e.g. `mcp__plugin_chrome-devtools-mcp_chrome-devtools__list_network_requests`) violate this constraint, causing API errors. This PR introduces transparent aliasing so that long or unsafe tool names are automatically shortened to a safe alias before being sent to Bedrock, and then restored to their original names in the response.
## Issue
closes #3788
## Changes
- Added `bedrockAliasToolName` which, for any tool name that doesn't satisfy Bedrock's naming rules, generates a deterministic alias of the form `<8-char sha1 hash>_<semantic suffix>` (≤64 chars total). The alias-to-original mapping is stored in the `BifrostContext` using a typed context key.
- Added `bedrockRestoreToolName` which looks up the alias map in the context and returns the original name, used when converting Bedrock responses back to Bifrost format.
- Aliasing is applied consistently across all code paths: tool definitions, `toolChoice.tool.name`, tool calls in assistant messages, and tools extracted from conversation history.
- Name restoration is applied in both non-streaming (`ToBifrostChatResponse`) and streaming (`ToBifrostChatCompletionStream`) response conversion paths.
- `BedrockStreamState` now carries a `context.Context`, populated via `NewBedrockStreamStateWithContext`, so the streaming path has access to the alias map.
- Added two tests: one verifying that long MCP tool names are aliased correctly on the request side, and one verifying that aliased names are restored to their originals in the response.
## Type of change
- [x] Bug fix
## Affected areas
- [x] Core (Go)
- [x] Providers/Integrations
## How to test
```sh
go test ./core/providers/bedrock/... -run "TestToBedrockChatCompletionRequest_AliasesLongMCPToolNames"
go test ./core/providers/bedrock/... -run "TestBedrockToBifrostChatResponse_RestoresAliasedToolName"
go test ./core/providers/bedrock/...
```
Pass a tool with a name longer than 64 characters or containing characters outside `[A-Za-z0-9_-]` (such as an MCP-style name with `__` and `.` segments) to a Bedrock-backed model. Verify that the request succeeds and that the tool name in the response matches the original name provided.
## Breaking changes
- [x] No
## Security considerations
The alias map is scoped to a single `BifrostContext` per request and is never persisted or shared across requests. Tool names are hashed with SHA-1 solely for collision-resistant shortening; no sensitive data is derived from the hash.
## Checklist
- [x] I added/updated tests where appropriate
- [x] I verified builds succeed (Go and UI)
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Enhanced Bedrock provider with improved tool name handling across chat and responses APIs
* Updated code editor UI with better code folding controls
* **Tests**
* Added comprehensive test coverage for Bedrock tool handling in chat completion and responses APIs
* **Chores**
* Updated dependencies for internal tooling
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/maximhq/bifrost/pull/3890?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 -->
## Summary This PR releases **core v1.5.14**, **framework v1.3.14**, **transports v1.5.6**, and bumps all dependent plugins to their respective `.14` patch versions. It delivers a broad set of new capabilities across MCP authentication, key rotation, OTel metrics, Bedrock/Anthropic compatibility, and UI improvements, alongside a number of targeted bug fixes and refactors. ## Changes - **Direct API Key Header** — Providers can now receive an API key passed directly via a request header (#3817) - **MCP Per-User Auth** — Introduced `MCPCredentialStore` abstraction, per-user MCP credential reconciliation, and a new per-user header auth type with lazy-auth submission flow (#3656, #3702, #3703, #3704, #3705) - **MCP TLS Configuration** — Added configurable TLS (`insecureSkipVerify`, `caCertPem`) for HTTP/SSE MCP client connections (#3779, #3783) - **MCP Sessions Management** — Filter, search, and pagination on the MCP sessions list API and table, plus a `can_reauth` identity gate (#3823, #3824, #3825) - **Key Rotation** — Keys now rotate on 401/402/403 responses; returns `502 upstream_credentials_exhausted` when all keys are permanently exhausted. Added `triggered_rotation` to `KeyAttemptRecord` and tightened `bifrost_key_rotation_events_total` semantics (#3430, #3491) - **OTel Metrics** — Added OTel spec-compatible metrics (backward compatible) with provider cache and semantic cache attributes in metrics export (#3865, #3816) - **Opus 4.8 Support** — System message handling and general compatibility for Opus 4.8 (#3868, #3878) - **Dimension Rankings** — New `GetDimensionRankings` API and dashboard tabs for team, customer, BU, and user rankings (#3766) - **Model Pricing Attributes** — `additional_attributes` field on model pricing rows with management API and UI editor (#3829) - **Prompt Cache Retention** — Added prompt cache retention parameter on responses requests (#3810) - **Tool Call Execution UI** — Inline tool-call execution, stop streaming, bulk execute/submit, and a redesigned tool-call UI (#3837, #3843) - **Sheet Navigation** — Prev/next keyboard navigation and URL state across virtual key, MCP client, and routing rule sheets (#3739, #3740, #3744, #3745) - **Bedrock Tool Name Truncation** — Truncate Bedrock function/tool names to the provider length limit - **Bedrock Guardrails** — Set guardrail config in Bedrock requests built from responses (#3862) - **Anthropic Tool Use** — Default `tool_use` input to `{}` when arguments are absent (#3880) - **Responses Streaming** — Fixed responses stream events (#3838) - **Compat Flow** — Fixed missing parameter parsing on the compat flow (#3881) - **Passthrough API Version** — Set a default API version in passthrough requests as a fallback (#3853) - **Virtual Key Updates** — Avoid overriding optional fields during virtual key update (#3855) - **User-Mode Flows** — Gate user-mode flows on caller `user_id`, skip temp token mint, and unify flow/credential kind filtering for pending flows (#3841, #3859) - **Partial Tool Calls** — Handle partial tool call execution failures and return successful results (#3849) - **URL Query Escaping** — Support escaped characters in URL query parameters (#3826) - **MCP Auth Errors** — Inline banner and retry support for MCP auth-required errors (#3856) - **Renamed Resolvers** — `staticHeadersResolver`/`serverOAuthResolver` renamed to `sharedHeadersResolver`/`sharedOAuthResolver` (#3840) - **Starlark Nested Tool Calls** — Exposed `RunWithPluginPipeline` on `ClientManager` and routed Starlark nested tool calls through the canonical plugin gate (#3794) - **Deferred-Fill OAuth Removed** — Removed deferred-fill user-mode OAuth flow support (#3839) - **Go 1.26.3** — Upgraded toolchain to Go 1.26.3 (#3782) ## Type of change - [x] Bug fix - [x] Feature - [x] Refactor - [ ] Documentation - [x] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [x] Providers/Integrations - [x] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh # Core/Transports go version # should report go1.26.3 go test ./... # UI cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` - Validate MCP per-user auth by configuring a per-user header auth type and confirming credentials are stored and reconciled on virtual key and MCP client changes. - Validate key rotation by triggering a 401/402/403 from an upstream provider and confirming rotation occurs; exhaust all keys and confirm a `502 upstream_credentials_exhausted` is returned. - Validate OTel metrics output includes `provider_cache` and `semantic_cache` attributes. - Validate Bedrock requests with tool names exceeding the provider limit are truncated correctly. - Validate Opus 4.8 system message handling by sending a request with a system message to an Opus 4.8 endpoint. ## Breaking changes - [x] Yes - [ ] No The deferred-fill user-mode OAuth flow has been removed (#3839). Any integrations relying on that flow must migrate to the new per-user credential store approach. The `staticHeadersResolver` and `serverOAuthResolver` identifiers have been renamed to `sharedHeadersResolver` and `sharedOAuthResolver` respectively (#3840); any direct references must be updated. ## Related issues #3817, #3656, #3702, #3703, #3704, #3705, #3779, #3783, #3823, #3824, #3825, #3430, #3491, #3865, #3816, #3868, #3878, #3766, #3829, #3810, #3837, #3843, #3739, #3740, #3744, #3745, #3862, #3880, #3838, #3881, #3853, #3855, #3841, #3859, #3849, #3826, #3856, #3840, #3794, #3839, #3782, #3724, #3814, #3836, #3869, #3886 ## Security considerations - MCP per-user credentials are stored via the new `MCPCredentialStore` abstraction; ensure the backing store is appropriately access-controlled and that credential values are encrypted at rest. - The direct API key header feature passes provider secrets via HTTP headers; ensure TLS is enforced on all ingress paths and that headers are not logged in plaintext. - User-mode flows are now gated on `caller user_id` and temp token minting is skipped where appropriate, reducing the surface for privilege escalation. - TLS configuration for MCP HTTP/SSE connections supports `insecureSkipVerify`; this should only be enabled in controlled environments. ## Checklist - [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
## ✨ Features - **Direct API Key Header** - Pass a provider API key directly via request header (maximhq#3817) - **MCP Per-User Authentication** - New per-user header auth type with credential storage and lazy-auth submission flow (maximhq#3703, maximhq#3704, maximhq#3705) - **MCP TLS Configuration** - Configurable TLS (insecureSkipVerify, caCertPem) for HTTP/SSE MCP client connections (maximhq#3779, maximhq#3783) - **MCP Sessions Management** - Filter, search, and pagination on the MCP sessions list API and table, plus a can_reauth identity gate (maximhq#3823, maximhq#3824, maximhq#3825) - **Tool Call Execution UI** - Inline tool-call execution, stop streaming, bulk execute/submit, and a redesigned tool-call UI (maximhq#3837, maximhq#3843) - **Dimension Rankings Dashboard** - New dashboard tabs for team, customer, BU, and user rankings, backed by a GetDimensionRankings API (maximhq#3766) - **Model Pricing Attributes** - additional_attributes on model pricing rows with management API and UI editor (maximhq#3829) - **Prompt Cache Retention** - Prompt cache retention parameter on responses requests (maximhq#3810) - **Opus 4.8 Support** - System message handling and compatibility for Opus 4.8 (maximhq#3878, maximhq#3868) - **Key Rotation** - Rotate keys on 401/402/403 and return 502 upstream_credentials_exhausted when all keys are permanently dead (maximhq#3491) - **OTel Metrics** - OTel spec compatible metrics plus provider and semantic cache attributes in metrics export (maximhq#3865, maximhq#3816) - **Sheet Navigation** - Prev/next keyboard navigation and URL state across virtual key, MCP client, and routing rule sheets (maximhq#3739, maximhq#3740, maximhq#3744, maximhq#3745) - **Go 1.26.3** - Upgraded toolchain to Go 1.26.3 (maximhq#3782) ## 🐞 Fixed - **Bedrock Tool Names** - Truncate Bedrock function/tool names to the provider length limit - **Bedrock Guardrails** - Set guardrail config in Bedrock request built from responses (maximhq#3862) - **Anthropic Tool Use** - Default Anthropic tool_use input to {} when arguments are absent (maximhq#3880) - **Responses Streaming** - Fixed responses stream events (maximhq#3838) - **Compat Flow** - Fixed missing parameter parsing on the compat flow (maximhq#3881) - **Passthrough API Version** - Set a default API version in passthrough requests as a fallback (maximhq#3853) - **Virtual Key Updates** - Avoid overriding optional fields during virtual key update (maximhq#3855) - **User-Mode Flows** - Gate user-mode flows on caller user_id, skip temp token mint, and unify flow/credential kind filtering for pending flows (maximhq#3841, maximhq#3859) - **Partial Tool Calls** - Handle partial tool call execution failures and return successful results (maximhq#3849) - **URL Query Escaping** - Support escaped characters in URL query parameters (maximhq#3826) - **MCP Auth Errors** - Inline banner and retry support for MCP auth-required errors (maximhq#3856) - **JSON Editor Height** - Cap JSON editor max height at 400px in message views (maximhq#3842)
## ✨ Features - **Direct API Key Header** - Pass a provider API key directly via request header (maximhq#3817) - **MCP Per-User Authentication** - New per-user header auth type with credential storage and lazy-auth submission flow (maximhq#3703, maximhq#3704, maximhq#3705) - **MCP TLS Configuration** - Configurable TLS (insecureSkipVerify, caCertPem) for HTTP/SSE MCP client connections (maximhq#3779, maximhq#3783) - **MCP Sessions Management** - Filter, search, and pagination on the MCP sessions list API and table, plus a can_reauth identity gate (maximhq#3823, maximhq#3824, maximhq#3825) - **Tool Call Execution UI** - Inline tool-call execution, stop streaming, bulk execute/submit, and a redesigned tool-call UI (maximhq#3837, maximhq#3843) - **Dimension Rankings Dashboard** - New dashboard tabs for team, customer, BU, and user rankings, backed by a GetDimensionRankings API (maximhq#3766) - **Model Pricing Attributes** - additional_attributes on model pricing rows with management API and UI editor (maximhq#3829) - **Prompt Cache Retention** - Prompt cache retention parameter on responses requests (maximhq#3810) - **Opus 4.8 Support** - System message handling and compatibility for Opus 4.8 (maximhq#3878, maximhq#3868) - **Key Rotation** - Rotate keys on 401/402/403 and return 502 upstream_credentials_exhausted when all keys are permanently dead (maximhq#3491) - **OTel Metrics** - OTel spec compatible metrics plus provider and semantic cache attributes in metrics export (maximhq#3865, maximhq#3816) - **Sheet Navigation** - Prev/next keyboard navigation and URL state across virtual key, MCP client, and routing rule sheets (maximhq#3739, maximhq#3740, maximhq#3744, maximhq#3745) - **Go 1.26.3** - Upgraded toolchain to Go 1.26.3 (maximhq#3782) ## 🐞 Fixed - **Bedrock Tool Names** - Truncate Bedrock function/tool names to the provider length limit - **Bedrock Guardrails** - Set guardrail config in Bedrock request built from responses (maximhq#3862) - **Anthropic Tool Use** - Default Anthropic tool_use input to {} when arguments are absent (maximhq#3880) - **Responses Streaming** - Fixed responses stream events (maximhq#3838) - **Compat Flow** - Fixed missing parameter parsing on the compat flow (maximhq#3881) - **Passthrough API Version** - Set a default API version in passthrough requests as a fallback (maximhq#3853) - **Virtual Key Updates** - Avoid overriding optional fields during virtual key update (maximhq#3855) - **User-Mode Flows** - Gate user-mode flows on caller user_id, skip temp token mint, and unify flow/credential kind filtering for pending flows (maximhq#3841, maximhq#3859) - **Partial Tool Calls** - Handle partial tool call execution failures and return successful results (maximhq#3849) - **URL Query Escaping** - Support escaped characters in URL query parameters (maximhq#3826) - **MCP Auth Errors** - Inline banner and retry support for MCP auth-required errors (maximhq#3856) - **JSON Editor Height** - Cap JSON editor max height at 400px in message views (maximhq#3842)
✨ Features
and lazy-auth submission flow (feat: add mcp per-user headers auth type with credential storage and submission flow #3703, feat: add mcp per-user headers auth flow ui wiring #3704, feat: reconcile per-user MCP credentials on VK and MCP client changes #3705)
MCP client connections (feat: add TLS configuration support for MCP HTTP/SSE client connections #3779, feat: add
tlsConfig(insecureSkipVerify, caCertPem) for HTTP/SSE MCP client connections in Bifrost Helm chart #3783)and table, plus a can_reauth identity gate (feat: add
can_reauthidentity gate for user-mode MCP session rows #3823, feat: add filter/search/pagination to MCP sessions list API #3824, feat: add filtering and pagination to MCP sessions table #3825)execute/submit, and a redesigned tool-call UI (feat: add tool call execution, stop streaming, and redesign tool call UI #3837, feat: add bulk execute/submit support for multiple pending tool calls #3843)
rankings, backed by a GetDimensionRankings API (feat: add
GetDimensionRankingsAPI and dashboard tabs for team, customer, BU, and user rankings #3766)API and UI editor (feat: add
additional_attributesto model pricing rows with management API and UI editor #3829)(fix: add prompt cache retention parameter on responses request #3810)
fix: opus 4.8 compatibility #3868)
upstream_credentials_exhausted when all keys are permanently dead (feat: rotate keys on 401/402/403 and return
502 upstream_credentials_exhaustedwhen all keys are permanently dead #3491)attributes in metrics export (adds otel spec compatible metrics (backward compatible) #3865, feat: adds provider cache and semantic cache attributes in metrics export #3816)
client, and routing rule sheets (feat: add
useSheetNavigationhook andSheetNavigationButtonscomponent #3739, feat: add keyboard navigation and URL state for virtual key detail sheet #3740, feat: add prev/next navigation toMCPClientSheet#3744, feat: add prev/next navigation toRoutingRuleInfoSheet#3745)🐞 Fixed
(fix: set guardrail config in bedrock request from responses #3862)
(fix: default Anthropic tool_use input to
{}when arguments are absent #3880)fallback (fix: set default api version in passthrough requests as a fallback #3853)
(avoid overriding optional fields in virtual key update #3855)
unify flow/credential kind filtering for pending flows (fix: gate user-mode flows on caller user_id and skip temp token mint #3841, fix: unify flow/credential kind filtering so pending flows follow their auth kind #3859)
results (fix: handle partial tool call execution failures and return successful results #3849)