v2.3.0
Changelog
v2.3.0 moves the enterprise gateway onto OSS transports v2.3.0. Teams, business units and customers can now hold an access profile that governs every member and key under them. Adaptive routing now holds provider keys that a provider refuses and rechecks them, and it records a routing history with an Incidents page. Alerting adds business unit and user scopes, plus rules that watch every entity of a scope and send one digest per channel. Identity sync adds reconcile with preview, one directory sync job that also deprovisions users, and attribute-to-project rules. The OSS release adds the A2A Agent Gateway, GPT Live sessions, the Cloudflare Workers AI provider, and provider-injected MCP tools.✨ Features
-
Access Profiles on Teams, Business Units and Customers - A team, business unit or customer can hold an access profile (
GET/POST/DELETE /api/governance/{teams|business-units|customers}/{id}/access-profile). Members’ requests and the keys the entity owns are then governed and charged by that profile. An entity profile adds to a member’s own profiles and never removes access. Attaching to an entity that still has its own limits returns 409entity_has_legacy_limitswith a migration plan.POST .../access-profile/migrate(dry run supported) builds a profile from the old limits, carries spend over on the same reset window and adopts the entity’s keys. Assign Existing adopts a key into the entity profile. config.json acceptsaccess_profileongovernance.teams,governance.customersandgovernance.business_units. The entity sheets have Attach, Detach and Migrate actions, a migration wizard and a Usage tab. Docs -
Business Unit Ownership and Limits - A virtual key can be owned by a business unit (
business_unit_id). That key spends the unit’s budget and rate limit and those of the customers the unit serves. Business units have their own budget and rate limit (/api/governance/business-units/{id}/governance), and like teams they use either their own limits or a profile, never both. Deleting a business unit unassigns its keys in the database, in memory and on peers. -
Business Unit and Customer Data Scopes - Roles can use two new data scopes.
business-unit-datacovers the caller’s business units, their members and keys owned by those units.customer-datacovers every team and business unit under the caller’s customers, plus keys owned by those customers. Both scopes can be selected in the role editor and set in config.json. -
Agent Access Grants - Access profiles and projects can grant Agent Gateway agents by name with
agent_grants. On project update, omitting the field keeps the current grants, and an empty list clears them. Blank, duplicate and unregistered names are rejected. A2A bearer calls resolve the user through the IdP, and the agent log records the user with their team, customer and business unit. New RBAC resources areAgentGatewayandAgentLogs, and agent log reads are DAC-scoped. Agents also appear in the Home, user detail and Activity views. -
Home Page - Each user gets a Home page with:
- spend, requests, top model, the budget closest to its limit, and spend rank;
- cost and model charts, app usage, and a budget burn chart with a projection;
- their keys and access. My Access shows disabled MCP servers and folds long tool lists.
GET /api/governance/users/meandGET /api/governance/users/me/rank. A weeklytoken_monsterbadge goes to the top 10 spenders. -
Budget Increase Requests - Users can request more budget on a virtual key or access-profile budget they own (
/api/governance/users/me/budget-requests). Approvers withVirtualKeys:Updateapprove or deny requests under/api/governance/budget-requests, and a deny needs a note. On approval,override_strategysets how the amount is applied:add(default),replace, oradd_keep_lifetime. Approvers are notified, and each budget can have only one pending request. Home splits decided requests into Approved and Denied tabs. -
Org Chart - New Governance page. It shows business units, teams and users, or customers, business units and teams, as a drill-down tree. Each level shows its top five children by spend, tokens, requests, budget or name. Nodes show a budget meter for the current cycle or a strip of the last 3, 6 or 12 cycles, and
/jumps to any node. Every list is DAC-scoped (/api/governance/org-chart/*). - Activity Tab on Entity Sheets - Every entity detail sheet has an Activity tab. It shows spend against the previous period, tokens, requests, budget left, per-cycle budget history, spend by model, and models and MCP tools tables. Team sheets also rank members by spend.
-
Provider Key Holds in Adaptive Routing - When a provider refuses a key for a reason that will repeat (credential, model_access, quota, model_gone, region_blocked, rate_limit), that key is taken out of rotation for the affected route. The whole key is held only for a rejected credential or an org-wide quota refusal. After the wait, exactly one request goes through as a recheck. A clean answer releases the key. A failure moves it up a doubling backoff that starts at 30s, with caps from 5m to 30m by reason. A 429 holds the key for the provider’s
Retry-After, which replaces the TPM circuit breaker. Holds are shared with cluster peers, survive restarts, and are fetched by joining nodes.GET /api/adaptive-routing/conditionslists holds, andPOST /api/adaptive-routing/conditions/clearreleases them across the cluster for one key, one provider, or all keys. Docs -
Adaptive Routing History and Incidents - Each node records routing frames and events: health changes, weight changes, holds, settings edits, key edits and node boots. Storage is SQLite, Postgres or ClickHouse, with its own
history_retention_days(1-30, default 7) and ahistory_enabledswitch. The Adaptive Routing dashboard is rebuilt on this history:- provider, model, region and node filters, and a Live toggle;
- a paged health timeline with a routing score breakdown;
- held-keys and state sheets.
/workspace/adaptive-routing/incidents) lists issues merged across nodes. Each issue shows its status, the recent config changes around it, nodes whose hold came from a peer, and whether an operator is needed. Read APIs are under/api/adaptive-routing/history/. The dashboard needs a Postgres or ClickHouse log store. -
Routing Decision Metadata on Logs - Each attempt writes
bifrost_alb_*metadata to its log: decision, requested provider and model, reroute target, excluded providers, key decision and skip reasons, failure class and region. An Adaptive Routing card on the log’s Routing tab shows these values, and the Logs sidebar has an Adaptive Routing filter group. -
Adaptive Routing Settings - New
reroute_target(pool, the default, orfallbacks). Withfallbacks, a failed pinned request moves to its own first healthy fallback. A direction where only some keys fail is nowDegradedand stays in rotation.snapshot_persist_interval_secondsis configurable, and its default changes from 30s to 5 minutes. A circuit breaker now follows a chain of open circuits to the first healthy target, with loop protection. Config and conditions routes move to/api/adaptive-routing/, and/api/load-balancer-configstays as a deprecated alias. UI labels are renamed: Reroute is now Redirect, and Prune Failed Fallbacks is now Skip Failing Fallbacks. -
Identity Reconcile with Preview -
POST /api/scim/provision/reconcilereplays stored login claims or SCIM state, so a mapping edit reaches existing users. It accepts an optionaluser_idssubset. The preview reports per-user changes without writing anything: role, teams, business units, projects, access profiles, and keys revoked or created..../reconcile/preview/usershows the plan for one user. After you save a mapping, the provider wizard offers to reconcile. The provisioning dashboard’s Re-verify action becomes “Reconcile users”. -
Unified Directory Sync with Deprovisioning - The Sync users button,
/api/scim/provision/syncand the scheduled run now execute one job. It creates or restores listed users and reconciles teams, business units, projects, roles and access profiles. After a complete listing, it deprovisions users the IdP no longer lists, and where the provider supports it, it first confirms the user is inactive. Service accounts and manual users are never touched.bulkSyncInterval(1h-30d, default 24h) applies without a restart. With SCIM provisioning on, bulk import and team or business-unit pulls return 403. -
Attribute-to-Project Mapping - New
attributeProjectMappingsrules add users to existing projects from IdP attributes on login, refresh, directory sync and SCIM pushes. A sync removes only the members its rules added, and members a rule adds show a “Synced from IdP” badge. -
Identity Mapping Rules - Several changes to how mapping rules work:
- A glob rule value can contain more than one
${*}. - Role and access-profile rules are stored by entity ID, so renaming a role or profile no longer breaks them. A rule that names a missing entity is reported in
skipped_mappings. - An interactive login now replaces claim memory, so an attribute the token omits removes what it granted. A login whose token has none of the role-rule attributes is refused with a 403 that names the missing attributes, and the user’s existing role is kept.
- On a role tie, the rule higher in the list wins.
- New SCIM group rules match on displayName.
- A glob rule value can contain more than one
-
SSO Provider Options - Every SSO provider accepts
emailField, the token claim that holds the email (for exampleupnor a namespaced Auth0 claim). The generic OIDC provider acceptsdisplayNamefor its login button. Thebifrost-cliPKCE client is accepted, and CLI sessions do not use Edge device seats. Deploy this gateway before the OSS CLI release. -
Alerting: Business Unit and User Scopes - Alert rules accept two new scopes.
business_unitwatches a unit’s budget and rate limit.usertargets one user’s budget or, for user scope only, arate_limit. Limits a user holds through access profiles and model configs are checked against their own targets and reset cycles.GET /api/alerting/users/{id}/targetslists the targets for a user, and the rule form adds a user picker and a limit picker. Rules are removed when their user or business unit is deleted. Docs -
Alerting: Rules for All Entities with Digests - Every scope accepts
scope_id: "*"(UI: Applies To > All). The rule then checks each virtual key, team, customer, business unit or user against its own limits. When several entities match in one pass, each channel gets one digest message, with rich layouts for Slack, Teams and PagerDuty. Cooldown and recovery are tracked per entity. History rows carryrule_scope_id,digest_idanddigest_size, and the UI shows “All” and “Digest of N” badges. - Alerting: Access-Profile Budgets - Budgets held through access profiles now raise alerts.
-
Alerting: History Sorting and Paging -
GET /api/alerting/historyacceptssort_by(created_at,rule_name,channel_name,scope_type,status) andsort_order. The default iscreated_atdescending. The history table sorts on the server and shows absolute and relative times. History defaults to a 7-day window, caps its count at 10,000+ (total_capped), and pages by keyset. -
Guardrail Updates - New A10 TrojAI Defend provider (
a10, withbase_urlandclient_id). Other changes:- Profiles on a rule run in a set execution order.
- The rule builder has a Builder / CEL toggle.
- Detect-only matches on Regex, Secrets, Presidio, Azure PII, Lakera and Bedrock are recorded as detections.
- Azure PII, Presidio and regex accept
allowed_values, values that are never blocked or redacted (up to 10,000). - Bedrock assessments include
confidence.
-
Connector Export Updates - New export options for BigQuery, Datadog, Splunk, Kafka and Pub/Sub:
- Per-category cost breakdown on all five. BigQuery adds 19 columns for it.
excluded_attributesdrops listed attributes before export.- BigQuery
export_raw_payloadswrites provider bodies toraw_request/raw_response, and a newappcolumn records the calling client. - Datadog
metric_dimensionssends listedx-bf-dim-*dimensions as metric tags. Datadog and Splunk metrics carryuser_idanduser_name.
-
Audit Logs Without IP Addresses - New
audit_logs.omit_ip_addressesstops storing client IPs. IPs in earlier rows are redacted on every read and export path. IP search and filters are disabled, and signatures stay valid. Docs -
Warp in Enterprise - New
WarpRBAC resource. Admin has View and Update, Developer and Viewer have View, and the log-index backfill needs Update. Warp follows the caller’s data scope, anddescribe_user_limitsreports access-profile budgets and rate limits from live counters. Docs -
RBAC Updates - New
BackgroundJobsresource for/api/sidekiq/jobs: View to list, Update to cancel. Add, edit and delete actions across guardrails, prompt deployments, Edge approvals and access profiles are hidden or disabled when the role lacks the permission. -
Bounded Audit Log Queries - Audit log search needs at least 3 characters and defaults to a 30-day window. Counts cap at 10,000+ (
total_capped), and paging is keyset. -
Edge Server Support - Admins can turn off Edge capture for one app, fleet-wide or per user or team (
PUT /edge/interceptionwithapp_key). Edge Devices shows the installed Edge version. New/mcp/inspect/v2lets MCP post-inspection run on any node, with no session affinity. Cursor config accepts per-operation models (linter_model,embedding_model,speech_model,image_model,video_model,transcription_modeland others). Docs - MCP in Clusters - MCP server instructions are saved and sent to peers with discovered tools. Refreshing a client’s tools makes every peer re-discover them right away.
🌎 Open Source Features
- Agent Gateway (A2A) - Bifrost proxies A2A agents. Register an agent by its card URL (
POST /api/agentsor the config.jsonagentsarray). Clients reach it over JSON-RPC (with SSE streaming), REST, or an optional shared gRPC listener. It supports header, OAuth and TLS upstream auth, and push notifications through a durable, retried outbox. Access is granted per virtual key withagent_grants. Every operation is logged in a new Agent Logs workspace. - Warp AI Assistant (alpha) - In-dashboard assistant that answers questions about logs, spend, latency and governance with read-only tools, inline charts and links to matching log rows. Completed logs can be embedded for semantic search, with a resumable backfill. Warp is off by default in Enterprise (
warpfeature flag). Docs - GPT Live Sessions - Proxies OpenAI GPT Live over WebSocket and WebRTC at
/v1/live/sessions, with sideband attach and recording download. Voice is billed in 30-second windows, governance is checked at each window, andliveis its own allowed request type. - Cloudflare Workers AI Provider - New
cloudflareprovider for chat (streaming included), Responses, embeddings and model listing. Each key needscloudflare_key_config.account_id. A dialog in the UI migrates an existing custom provider namedcloudflare. Docs - Provider-Injected MCP Tools - A provider’s
injected_toolsadds MCP tools to every chat and Responses request for that provider. Bifrost runs them server side and returns only the final answer. An entry namedweb_searchreplaces native web search. Configure it in the provider’s new Tools tab. - OAuth-Minted Keys for OpenAI-Compatible Providers -
oauth_key_configmints a bearer token with theclient_credentialsorjwt_bearergrant, caches it, and refreshes it before expiry. Databricks and GitHub Copilot use the same token cache. - Decisions API Updates -
/v1/decisionstakes OpenAI-shapedinputandquestions, and new/openai/v1/decisionsroutes accept the OpenAI SDK request. Native decision models are reached on OpenAI, Perplexity, Ollama and OpenRouter. TypeSafe can be a custom provider base, and decisions have their own pricing fields. Emulation on non-decision models is now opt-in throughconvert_decision_to_responses. Docs - Complexity Router Decision Classifier - The complexity router can classify with a decision model (TypeSafe Jev by default), as the primary classifier or as a fallback. Per-tier guidance is editable. Docs
- Multimodal Embeddings -
/v1/embeddingsaccepts text, image, audio, video, file and token parts, served by Cohere, Gemini, Vertex and Bedrock (Nova and Titan multimodal). Parasail now serves embeddings. - Responses Tools - Adds OpenAI
shellandapply_patchtools, mapsallowed_callersbetween OpenAI and Anthropic, and maps Gemini code execution tocode_interpreter_call. - Retrieve a Single Model -
GET /v1/models/{model}for OpenAI, Anthropic, Cohere, Gemini, Mistral and Ollama, withshutdown_datewhere the provider announces one. - xAI Realtime - xAI is a realtime voice provider on the WebSocket gateway, with client-secret minting. Docs
- Bedrock Passthrough -
/bedrock_passthroughforwards InvokeAgent, knowledge-base Retrieve and ApplyGuardrail, SigV4-signed with the key’s AWS credentials. Docs - Vertex Workload Identity from AWS -
vertex_key_config.aws_workload_identityauthenticates from EKS IRSA, Pod Identity, ECS task roles or EC2 instance profiles, with no stored key. - Pricing Updates - Web search is billed per request (
web_search_cost_per_request), and existing values are migrated.*_above_100k_tokensrates apply above 100,000 prompt tokens. A per-providerignore_provider_costsetting prices requests from the catalog instead of the provider’s reported cost. - Compat Updates -
force_reasoning_only_models_to_responses(defaulttrue, also turned on for existing deployments) sends tool requests for reasoning-only models to the Responses API. Chat acceptsreasoning.modeandreasoning.summary. - Failure Classification and Key Rotation - Each failed attempt gets a
failure_class. Credential and quota failures hold a key out for every model, and permanent per-key failures move to the next key even atmax_retries: 0. Provider retry hints are exposed asextra_fields.retry_after_ms. - Routing Updates - Routing targets accept
ttft_timeout_ms, which hands a slow-to-start stream to the next fallback. When a rule or router rewrites the route, the original is returned inrouting_info.requested_provider/requested_modeland response headers. Every traced response carriesx-bifrost-request-id. - Provider Objects Bound to the Creating Virtual Key - Files, batches, videos, containers and cached contents can be read only through the virtual key that created them. Turn this off with
client.enforce_vk_object_ownership(defaulttrue). File-based batches are checked against the key’s model allowlist. - Security Hardening - Several changes to defaults and status codes; review them before upgrading:
- Passthrough routes forward only
POSTrequests to allowlisted inference paths. - With dashboard auth off, browser requests to
/api/*from unlisted origins return 403. - Secret references, private webhook targets, plugin endpoints and Vertex
auth_credentialsneed real auth. - Re-enabling auth while it is off needs
current_passwordor asetup_token. - Compressed bodies may expand at most 100 times.
- Passthrough routes forward only
- Per-Virtual-Key Content Logging and Auto-Delete - Virtual keys have a tri-state
disable_content_logging, anddelete_after_expiredeletes a key once it expires. Docs - Global Proxy for All Outbound Traffic -
proxy_configcan be set in config.json and Helm. Withenable_for_api, MCP, catalog sync, OTel, webhooks and plugin downloads use it. Withenable_for_inference, providers without their own proxy now actually send inference through it. - MCP Updates - Tools can be refreshed on demand (
POST /api/mcp/client/{id}/refresh-tools), and dropped sessions reconnect automatically. An evicted OAuth client can be re-registered. Upstream serverinstructionsare forwarded and injected, with size caps.mcp_oauth_private_allowlistallows private OAuth servers. Rotating a virtual key revokes its MCP OAuth grants. Code mode runs on an in-process Starlark runtime withcode_mode_limits. Docs - Semantic Cache Updates - Entries are scoped by identity (virtual key plus user), so expect a cold cache after upgrading. Responses with client tool calls are not cached unless
cache_tool_call_responsesis on. Lookups addx-bifrost-cache-*response headers. Docs - Observability Updates - New trace data and metric changes:
- Root spans carry error attributes and an end-to-end TTFT.
- OTel profiles can export raw payloads, drop listed attributes, and carry a
bifrost.cost.*breakdown. - Metrics get an
applabel. - The root span uses the stable OTel HTTP attributes.
- Tracing overhead is lower when no connector is attached. Docs
- Response Headers Plugin Hook - New
HTTPTransportResponseHeadersHooklets plugins set headers on buffered and streaming responses. Custom Go plugins must add it (a no-op is fine). - Logs and Dashboard - New views and controls:
- Grouped logs collapse requests by
session_id. - A Background jobs panel lists and cancels long jobs.
object_storage_exclude_request_typeskeeps chosen request types in the database instead of object storage.- Provider and model pickers are unified, with server-side search.
- Entity pickers scroll infinitely.
- Grouped logs collapse requests by
- Bifrost CLI - The
bifrostCLI covers the published API, with resource commands,chat,infer,auth(SSO included),usage, reversibleconfigurefor native agents, and table, JSON or YAML output. - Helm Chart 2.1.44 - Exposes the new config fields,
topologySpreadConstraintsandextraContainers.
🐞 Fixed
- DAC Leaks Closed - Each of these routes now returns 404, 403 or a filtered list:
- log and MCP log deletes, and log cost recalculation;
- user sub-resources;
- budgets and rate limits lists,
from_memory=truegovernance reads, and governance introspection; - prompt versions and sessions, and routing rule deletes;
- org link removal and nested child lists, team replace, and key owners;
- access profile history.
- DAC Visibility Rules - Team member counts, model config lists and org entity creator visibility follow the caller’s scope. A member’s key is visible only when it is attached to that member. Callers with more than 65,535 members or keys no longer get errors on scoped reads.
- One Owner per Virtual Key - A key attached to a team, business unit or customer can no longer also be attached to a user, and the reverse. Both return 409.
- Governed Member Key Ownership - A governed member’s new key stays under their own access profile, whatever entity the request body names.
- Entity Profile Fixes - “All providers” entity profiles resolve unprefixed models. config.json limits detach a conflicting profile. The profile-or-limits guard covers every write path. Entity-governed keys are hidden from other pickers.
- Agent Governance for IdP Users - Callers with an IdP token now record a credential, so deny-by-default Agent checks run for them.
- Deleted Users Lose Desktop Sessions - Deleting or deprovisioning a user deletes their desktop sessions and evicts cached tokens across the cluster.
- IdP Secret Rotation to Env or Vault - Switching an IdP secret to an
env.orvault.reference is now saved. - SCIM Protocol Fixes - Changes for RFC 7644 and IdP compatibility:
GET /Usersevaluates RFC 7644 filters and pages.- Core
rolesandentitlementsare stored, andPATCH active:truereactivates a user. Entra’s"True"/"False"strings are accepted. - PATCH identity edits are kept, and a PUT clears omitted attributes.
- Extension attribute names match in any case, and multi-valued PATCH follows RFC semantics.
- A DELETE clears stored identity data.
- SCIM Group Fixes - A group push updates every team and business unit its rules name. A rename reloads memory and peers. A DELETE keeps memberships a user attribute still grants. Entra object-ID/name pairs are matched, and group pushes take over attribute-created memberships.
- Directory Pull Safety - Background pulls no longer restore deleted users or grant Admin. Users keep group-granted memberships when a group lookup fails. Okta and Entra records carry the same claims a login does. Keycloak subgroups are walked, and Entra users in more than 200 groups are resolved.
- Group Naming - A team or business unit named after a raw group ID is renamed in place instead of forked. Entra business units use the group’s display name. Two rules on one group value no longer rename one team back and forth. Retargeted exact rules find or create the new target.
- IdP Rate Limits - Okta admin reads retry until
X-Rate-Limit-Reset, and Entra group lookups retry on 429 and 5xx and cache resolved names for 10 minutes. - SSO Token Handling - Fixes:
- Entra SSO works without a
cloudkey. - Inline refresh works for Auth0, Generic, Zitadel and SailPoint.
- A refresh without an ID token no longer loops.
- Logout revokes the access and refresh tokens.
- ID-token verifiers are cached.
- The inference JIT path uses the configured email claim.
- Entra SSO works without a
- Token Exchange Subject - A valid IdP JWT sent with a virtual key under
prefer_vk, or behind an auth proxy, is recorded as the token-exchange subject. This fixessubject_token_missing. - Mapping Rules on First Boot - SCIM mapping reconcile now runs after roles and access profiles load from config.json.
- Adaptive Routing Accuracy - Cancelled, timed-out and caller-fault requests no longer count against a key. Caller
x-bf-direct-keyfailures are not held. Caller key pins no longer follow a request to its fallback. Idle failed routes move to Recovering. Deleted keys and providers are purged on every node, and editing a key releases its holds. - Adaptive Routing Cluster State - Hold timestamps keep nanosecond precision over gossip. Only the global leader writes the hold table. Restored samples keep their original timestamps.
- Load Balancer Memory - The tracker uses a chunked in-memory store and keeps 1h of history (was 24h), and key selection no longer copies route metrics on every request.
- Alerting: Rules Match Only Entities with the Named Limits - A rule no longer fires for entities that do not hold the limits it names. An idle reset no longer sends the notification again, and digest counts no longer repeat entities.
- Alerting: Per-Rule Channel Cooldowns - Cooldowns are tracked per channel and rule, so one rule no longer silences another on a shared channel. Skip history rows are throttled, CEL evaluation errors are recorded, and webhook
Authorizationheaders are kept. - Alerting: Channel Delete Guard - Deleting a rule’s last channel returns 409
alert_channel_in_usewith the blocking rules. A rule needs at least one channel, and a PUT keeps fields the body leaves out. - Alerting: Channel Edit Keeps Headers - Editing a channel keeps its stored headers unless “Remove existing headers” is on, and delete conflicts are shown in the dialog.
- Alerting: User-Scoped Alert History - Alerts with user scope now write a history row, so they show in the UI.
- Connector Fixes - Datadog metrics no longer depend on trace export, and an unreachable agent no longer blocks startup. Disabled connectors stay disabled after restart. Pub/Sub
excluded_attributesapplies on the live publisher. Splunk keeps zero costs. Kafka, Pub/Sub and Splunk strip all content attributes when content logging is off. - BigQuery Writes - Flushes are split under 9 MiB, an oversized row is dropped on its own, and latency keeps sub-millisecond precision.
- Project Fixes - Project create rejects unknown or duplicate Virtual MCP IDs with a clear error, and
calendar_alignedupdates per-model budgets. - Business Unit Fixes - Clearing one rate limit keeps the other. Deleting a unit removes its customer links on SQLite. Budget columns include active overrides.
- Late Log Redaction - Late responses written through batch updates are redacted like new inserts.
- Plugin Reload Context - Plugins reloaded through the API use the server context, not the request context.
- Startup Migrations - Startup runs only enterprise migration steps not yet recorded.
- Fallback Billing and Calendar Alignment (OSS) - Fallback usage is billed after a billed primary. Calendar-aligned team and virtual key budgets keep their alignment after restart.
- Outbound Fetch Redirect Hardening (OSS) - Datasheet, MCP library, OAuth and webhook fetches enforce the private-network policy on every redirect hop.
- Encrypted Session and Virtual Key Lookups (OSS) - The plaintext fallback matches only plaintext rows.
- Virtual Key Header Redacted in Traces (OSS) -
x-bf-vkis redacted in captured headers. - Direct Keys Stay on Their Provider (OSS) -
x-bf-direct-keyis no longer sent to every provider on an unscoped model listing. - Provider Proxy on Every Egress Path (OSS) - Side fetches, credential exchanges and Bedrock runtime calls use the provider’s
proxy_config. - config.json Governance Limits (OSS) - Inline virtual key and provider config limits are stored on model config tiers and update on reload.
- Virtual Key and Provider Key Partial Updates (OSS) -
PUTwithoutkey_idskeeps key associations, and partial key updates keep omitted fields. - Session Affinity Rebinds on Refused Keys (OSS) - A session bound to a key the provider refuses moves to another eligible key.
- Caller Errors Skip Inferred Fallbacks (OSS) - A 4xx caller error is returned instead of being answered by a catalog-inferred fallback.
- Implicit Prompt Caching for gpt-5.6+ (OSS) - Requests with
cache_controlmarkers stay in implicit mode instead of rewriting the conversation at the cache-write rate. - Stream Errors Get Real Status Codes (OSS) - Mid-stream errors return 429, 400, 502 or 529 instead of 400. Truncated Bedrock Converse and Content-Length streams are reported as errors.
- Anthropic and Bedrock Fidelity (OSS) - Anthropic error types and
stop_sequenceare preserved. Bedrock guardrailguardContent, document cache points and Converse reasoning replay are kept. Safeguard verdicts reach Claude Code. - Gemini and Vertex Fixes (OSS) - Function tools without a schema are declared, and parallel tool results are reordered.
nmaps tocandidateCount. Extra params survive retries. - Postgres Scale Fixes (OSS) - Chunked log inserts, composite owner indexes, batched retention, and retried batches on connection errors. Logs with binary content or NUL bytes no longer fail a batch.
- ClickHouse Fixes (OSS) - Large team scopes no longer exceed
max_query_size, and time filters keep millisecond precision. - Model Listing Robustness (OSS) - One unreachable provider no longer blocks
GET /v1/models. - Prometheus Fixes (OSS) - Custom labels no longer collide. Cancelled requests are billed. Errors report the real status code.
- Semantic Cache Fixes (OSS) - Entries are isolated by request family, and the cache write no longer races core cleanup.
🐙 Closed OSS Issues
- #2649 - [Feature]: OpenAI Responses API
ShellToolnot supported - #3471 - [Bug]: Bedrock Titan embedding concatenates list inputs instead of fanning out - silent corruption and 400 on large batches
- #3632 - [bug]: bedrock - Titan multimodal embedding model rejected as unsupported
- #6143 - [Bug]: data race - fasthttp requestStream released to pool while SSE reader is still inside Read (stream cancellation)
- #6477 - [Bug]: MCP OAuth reauthorization prematurely closes popup on first poll tick and rejects completion with 409 (stale “authorized” status in oauth_configs)
- #6612 - [Bug]: A single unreachable provider blocks the aggregate GET /v1/models (re-polled live every request; bounded only by the shared request timeout)
- #6742 - [Feature]: Surface DeepSeek’s silent model substitution and validate usage completeness on its Anthropic endpoint
- #6870 - [Bug]: Failed live MCP connection checks never trigger the documented reconnect
- #6885 - [Bug]: MCP tool lists never refresh when a server’s tool set changes - notifications/tools/list_changed is ignored, and per-call clients have no refresh path at all
- #7191 - [Bug]: MCP OAuth authorization is lost and manual re-login does not recover it
- #7233 - [Bug]: Direct-only cache response serialization races with core cleanup and can panic
- #7275 - [Bug]: gpt-6-astra / Foundry: tools + reasoning on /v1/chat/completions still 400 after #5231
- #7341 - [Bug]: Gemini Responses stream - response.completed.Output is empty when parts and finishReason share one frame
- #7342 - [Bug]: Gemini Responses stream drops a generated image part that carries a thoughtSignature
- #7344 - [Bug]: strict, allowed_tools, parallel_tool_calls and allowed_callers are dropped in provider conversion
- #7347 - [Bug]:
PUT /api/governance/virtual-keys/{id}silently sets allow_all_keys=false and drops key associations when key_ids is omitted (GET does not return key_ids) - #7388 - [Bug]: Gemini & Vertex Providers: Missing N Parameter Mapping to CandidateCount in Chat Completions
- #7415 - [Feature]: Support OpenRouter’s native Decisions API
- #7438 - [Bug]: otel HTTP telemetry uses deprecated semconv; no http.route or http.server.request.duration
- #7446 - [Bug]: otel HTTP metrics exporter ignores https scheme when insecure is omitted (defaults true)
- #7450 - [Bug]: Semantic cache panics while marshaling /v1/responses
- #7560 - [Bug]: semantic_cache serves a chat.completion entry to a /v1/responses caller because the direct cache key omits the request family
- #7572 -
PUT /api/providers/{provider}/keys/{key_id}: partial update silently wipes key value and weight (destructive merge default) - #7580 - [Feature]: Allow OpenAI reasoning.mode (“pro”) on Chat Completions and carry it through chat→responses conversion
- #7581 - [Bug]: Complexity Router: fails to find provider config unless provider name is all-lowercase
- #7584 - UI: Recharts warns width(-1)/height(-1) on Dashboard, LLM Logs and MCP Logs
- #7599 - [Bug]: TypeSafe native compatibility rejects SDK-valid inputs and loses payload/response fidelity
- #7601 - [Bug]: /v1/responses for Anthropic and Gemini omits status and does not signal max_output_tokens truncation
- #7610 - Provider harness: group 25 (DeepSeek Anthropic-Compatible Migration) runs on the OpenAI-compatible endpoint - is use_anthropic_endpoints meant to be set?
- #7613 - [Bug]: Bedrock Converse drops cache_control on file/document content blocks
- #7634 - Access profile summary shows “All models” when blocked models are configured
- #7649 - [Bug]: Bedrock provider drops extended-thinking token count (
output_tokens_details.thinking_tokens) that AWS returns - #7659 - [Bug]: mirrored reasoning params (reasoning_effort + reasoning.effort, equal values) rejected as 400 Invalid request payload
- #7661 - [Bug]: Reasoning Parameters renders an unlabeled 0 for
reasoning.max_tokens - #7693 - [Bug]: streamed chat completions omit delta.role when the request is converted to the Responses API
- #7694 - [Bug]: Gemini rejects tool results that contain
$ref- JSON-object tool output is forwarded as structured function_response.response - #7696 - [Bug]: Bedrock guardrail selective evaluation is impossible - guardContent blocks silently stripped in canonical round-trip; guardrailConfig has no tagSuffix
- #7720 - [Bug]: Bifrost ignores “store”: false in additionalModelRequestFields on the Bedrock Converse route, so store cannot be disabled for Azure
- #7729 - [Bug]: Bifrost replaces the reasoning item id when a Bedrock Converse request replays redactedContent, so Azure rejects it and Bifrost strips the reasoning
- #7760 - ListAllModels returns duplicate and skipped models when a provider listing changes between pages
- #7768 - [Bug]: bare Claude model ids hoist thinking blocks on the Bedrock path
- #7784 - [MCP Library] Parlel - free people/companies/jobs/agents MCP
- #7812 - [Bug]: Gemini embeddings:
taskType/titleapplied only to the first input of a batched/v1/embeddingsrequest - #7819 - [Bug]: Transcription cost ignores provider-reported usage.cost and per-second pricing is unreachable when input_tokens > 0
- #7826 - [Bug]: Gemini and Vertex image and transcription requests lose ExtraParams on retry
- #7843 - [Bug]: Postgres log store batch inserts exceed the 65,535 bind-parameter limit, so full batches fall back to row-by-row inserts
- #7915 - [Bug]: Anthropic-compatible /anthropic/v1/messages returns wrong or non-standard error.type
- #7920 - [Bug]: Anthropic /v1/messages never reports stop_reason “stop_sequence” or the matched stop_sequence
- #7926 - [Bug]: Gemini/Vertex drop function tools without input_schema and mis-pair parallel tool results
- #7990 - [Bug]: Responses history gains
logprobs: null, causing upstream 400 - #8004 - [MCP Library] Add: FXMacroData
- #8153 - [Bug]: Routing Tree silently truncates routing rules at 100
- #8171 - [Bug]: Routing Tree CEL parser splits and rewrites operators inside quoted string literals
- #8195 - [Bug]: Anthropic
tool_result.is_errorno longer reaches OpenAI Responses upstreams - thestatus: "incomplete"set by the Anthropic converter is cleared inToOpenAIResponsesRequest(#7835) - #8196 - [Bug]: /v1/responses rejects multi-part assistant messages - output_text is not mapped to text in ToChatMessages
- #8205 - [Bug]: ClickHouse log list returns full input histories
- #8207 - [Bug]: Anthropic tool_addition / tool_removal blocks lose their
toolobject in the Responses conversion - #8212 - [Bug]: Log retention changes do not update the running cleaner
- #8215 - [Bug]: DeepCopyChatMessage drops cache_control, citations, prompt_cache_breakpoint and cachePoint on chat content blocks
- #8246 - skills_registry: config-driven skill updates always fail -
populateSkillFilesresolves the serving version viaskill.LatestVersion, whichconfigEntryToTableSkillnever sets - #8266 - [Bug]: calendar-aligned virtual key budgets reset on a rolling window after a restart
- #8286 - [Bug]: Fixed-length streamed responses silently accept premature EOF
📀 Base OSS version
transports/v2.3.0 (pinned as github.com/maximhq/bifrost/transports v1.6.12-0.20261013033355-a014d2db10df, the v2.3.0 tag plus its changelog commit), with core v1.12.0, framework v1.9.0, governance v1.9.0, and logging v1.9.0.
