Framework Release v1.7.0
- feat: model allow and block lists accept
regex:entries. The provider-key aggregate keeps an exact name next to a pattern that also covers it, the catalog allow check tries a pattern against the bare name andprovider/model, and listings skip pattern entries - fix: ClickHouse log store deletes no longer run as heavyweight
ALTER TABLE ... DELETEmutations. The retention cleaner issued one such mutation per 100 rows, each rewriting the whole current-month part, and the once-a-minute stale-processingsweeps issued one per table unconditionally, filling replica disks in minutes. Every delete on the ClickHouse store (retention sweep,Flush/FlushMCPToolLogs, UI log deletes, async job and webhook delivery expiry) is now a single lightweightDELETE FROM ... WHEREper run, skipped entirely when nothing matches. The table TTL derived fromlogs_store.retention_daysis now reconciled on every startup withMODIFY TTL(metadata only), so changing the value reaches existing tables;0leaves an existing TTL untouched (#7098) - feat: access profiles and governance projects reference Virtual MCPs through
virtual_mcp_name, so config files are portable across environments instead of carrying database-assigned integer IDs. Names resolve to stored records on startup and a name that matches nothing is refused;virtual_mcp_idis deprecated, still accepted, and wins when both are set.mcp_configs({ mcp_client_id, tools_to_execute }) replaces themcp_serversandmcp_tool_overridesinclude-exclude model with a single allowlist, where["*"]grants all tools including future ones,[]grants none, and a named list grants only those; the old keys are deprecated, still accepted, and folded into the new shape at load time (#7181) - feat:
MCPToolLogrecords governance entity names beside their IDs, so MCP tool logs carry the same attribution shape thelogstable has instead of rendering raw UUIDs in the dashboard.user_name,team_name,customer_nameandbusiness_unit_namestop beinggorm:"-"transients and become storage; the multi-valuedteam_ids/team_names,customer_ids/customer_namesandbusiness_unit_ids/business_unit_namessets are stored as index-aligned JSON arrays; andbudget_idsandrate_limit_idsare recorded id-only, as inlogs. Names are written from the request context at ingestion through the newMCPToolLog.ApplyGovernanceinframework/logstore/governance.go, with nothing resolved on read. Added by migrationmcp_tool_logs_add_governance_snapshots(#7154) - feat: endpoint-attributed MCP observations are carried in the standard logging pipeline, so inspected MCP tool calls are logged with bounded identity (device, app key, server label, tool name, decision) sourced from the gateway rather than from payload-supplied headers.
SetMCPObservationattaches the attribution to aBifrostContextandapplyMCPObservationwrites it onto theMCPToolLogfrom bothPreMCPHookandPostMCPHook, snapshotting the observation so it cannot alias across async log entries (#6959) - feat: the
error_typeclassification vocabulary is threaded through the framework sobifrost_error_requests_totalcan carry a normalized fault-domain label alongsidestatus_code(#7141) - feat: model pricing supports time-of-day peak and off-peak rates.
TableModelPricinggainsoff_peak_cost_multiplier(a nullable float) andpeak_hours(a JSON-serializedPeakHoursScheduleof recurring weekly windows using IANA timezone names, weekday numbers and half-openHH:MMintervals that may wrap past midnight), added by migrationadd_time_of_day_pricing_columnsand aliased into the datasheet package so the JSON shape stays self-contained. The cost engine evaluates the schedule against the request start time and scales usage-based charges by the multiplier when the request falls outside every peak window, applied once incomputeCostFromInputso every modality is covered; flatCostPerRequestandSearchQueriesCostfees are excluded, as isAdditionalCost, which is discounted independently through its own pricing rows. Both fields are exposed onPricingPatchin the OpenAPI and governance schemas, withoff_peak_cost_multiplierbounded to(0, 1](#6574, #6575, #6576) - feat:
SecretVar.RedactedIfSecret()is used for non-credential fields inProviderConfig.Redacted(),Config.GetAllKeys()andConfig.RedactMCPClientConfig(), so regions, endpoints, service URLs and MCP connection strings surface as plaintext while anything env-var or vault-backed stays masked (#7085) - feat: GA realtime transcription sessions are routed, governed, logged and priced through the normal framework pipeline, resolving the routing model from the nested
audio.input.transcription.modelthat arrives insession.updaterather than from the connect URL (#7089) - feat: a
use_openai_endpointscolumn on the provider keys table, added by migrationadd_use_openai_endpoints_column, opts a Bedrock key or alias into Bedrock's OpenAI-compatible endpoints instead of Converse (#7073) - feat: the reserved tool-namespace list a provider keeps for its own server tools is read from the datasheet row
reserved_tool_namespaces, so a namespace collision check no longer requires a code change (#7084) - fix:
exchangeRefreshTokenincludesclient_secretonly when the secret is non-empty, matchingexchangeCodeForTokensWithPKCE. Public OAuth2 clients registered against servers that support onlytoken_endpoint_auth_method: nonehave no secret, and unconditionally settingclient_secret=sent an emptyclient_secret_postattempt that strict authorization servers answered withinvalid_client, flipping the token row toneeds_reautheven though the refresh token was valid (#7042) - fix: the virtual key
allowed_models: ["*"]handling for governance added in #6767 is reverted, returning the wildcard-with-empty-synced-catalog case to its previous behaviour (#7053)
Installation
go get github.com/maximhq/bifrost/framework@v1.7.0This release was automatically created and uses core version: v1.9.0