Core Release v1.8.0
- fix: forward OpenCode Responses requests directly to /v1/responses @mohammadrezwankhan
- feat: add the
VideoEditoperation withBifrostVideoEditRequest,VideoEditInputandVideoEditParametersfor prompt-driven edits, upscaling and background removal on an existing video supplied as bytes, a URL or a provider video ID; implemented for OpenAI (/v1/videos/edits) and Runware (videoInference,upscale,removeBackground), with the model optional when the source is a video ID and the prompt optional for asset-driven task types (#6270) - feat: batch accounting:
MergeBifrostLLMUsagepromoted toschemas,EndpointonBifrostBatchResultsResponse,BatchResultItem.Failed(),BatchRequestCountsFromResults,BatchRequestCounts.IsZero(), raw-JSON Gemini batch result parsing andcustom_idvalidation inConvertRequestsToJSONL; the settlement engine (AccountBatchResultswith runner-ID ownership fencing, idempotent aggregate log writes and governance reporting) and a sweeper that polls due jobs with capped, jittered backoff; aggregate log entries carry abifrost/<version>user agent viaBifrostContextKeyRuntimeVersion(thanks @SahilChoudhary22!) (#5291, #5294, #6474) - feat: Claude-on-Vertex batch support:
ToVertexBatchCreateRequestresolves Anthropic families topublishers/anthropic/models/...,vertexConvertRequestsToJSONLemits Claude-on-Vertex instances,custom_idround-trips throughbatchResultsByKey, andGeminiBatchGenerateContentRequestkeepstools,toolConfig,cachedContent,labelsand the display name (#5368) - feat: add
HTTPTransportPreAuthHookto theHTTPTransportPlugininterface, a phase that runs before transport authentication;HTTPTransportPreHooknow runs after it (#6375)
Breaking for plugin authors: Go plugins implementingHTTPTransportPluginmust addHTTPTransportPreAuthHook(.soplugins that predate it are skipped for that phase), and any plugin that injected a credential such asx-bf-vkorAuthorizationfromHTTPTransportPreHookmust move that work toHTTPTransportPreAuthHook, since the pre-hook no longer runs before auth.
- feat: add
semaphore_sizeandinject_timeouttoPluginConfigso observabilityInjectcalls are context-bounded per plugin (#6341) - feat: Runware provider expansion: chat completions, streaming and Responses through its OpenAI-compatible
/v1/chat/completionsendpoint (Responses muxed viaToChatRequest()),ListModelssweeping the curatedmodelSearchcatalog with the AIR as the model ID, image upscale via/v1/images/edits(type=upscale) and image-to-3D via/v1/videos(type=3d), a sharedsettingsextra-param coercion for multipart and JSON callers, prompt-optional asset-driven operations, and input handling for edit, upscale and video task shapes (#6260, #6372, #6208) - feat: OpenAI
ultrafastservice tier:BifrostServiceTierUltrafast, capability-gated forwarding viaserviceTierForModelon chat, Responses and compaction, andultrafastpreserved throughWithDefaults(#6396) - feat: JSON bodies on
/v1/images/edits:ImageInputaccepts a bare string or{ "url", "image" }, typed extra params reach providers with their real types, andimagesis a known field (#6418) - feat:
EmbeddingData.EncodingFormatwith typedint8,uint8,binary,ubinaryandbase64vectors; Bedrock Titan V2embeddingTypesand Cohereembedding_typeson Converse, native invoke and LangChainBedrockEmbeddingscompatibility (#6381) - feat: rerank:
RerankDocument.Datafor structured documents,RerankResult.ID,RerankParameters.NextToken,ReturnDocumentsforwarded to Cohere and Vertex,ToCohereErrorfor Cohere-shaped errors,/genai/v1/rankserved cross-provider viax-model-provider, cross-provider responses converted back to the caller's wire shape withToBedrockRerankResponse,ToCohereRerankResponseandToVertexRankResponse, and rerank cost accounting for Bedrock and Cohere (#6301, #6328) - feat: datasheet-backed compatibility flows: Anthropic, Bedrock, Cohere and Gemini request shaping (adaptive-only thinking, adaptive thinking, native effort, disable-reasoning, mid-conversation system turns, computer-use and text-editor tool generations, default max output tokens, tool validation, thinking-budget zeroing) is resolved through
schemas.ResolveModelCapsinstead of hardcoded model-name checks (#6281, #6492) - feat: Gemini 3 per-model
thinkingLevelsupport table (geminiThinkingLevelSupport) withclampThinkingLevelsnapping requested levels to the nearest rung (ties break upward) andlowestThinkingLevelforreasoning_effort: "none", sosetThinkingBudgetZeroIfSupportedsets the floor level on Gemini 3+ instead of zeroingthinkingBudget(#6280) - feat: Bifrost overhead latency accounting:
upstream_latencyandoverhead_latencyonBifrostResponseExtraFields(PopulateOverheadLatency,BifrostContextKeyRequestStartTime,populateLatencyExtraFieldsso logging plugins see both at hook time); per-phase overhead spans across the request pipeline (queue-wait,attribute-population,convertor,request-marshal,response-parse,handle-setup,pipeline-pre,pipeline-post,worker-setup,key-pool, Bedrockrequest-signandcredentials-fetch,response-finalize) withStampWorkerHandoffonChannelMessage.sentAt; lock-free stream overhead accumulators for per-chunk parse, conversion and backpressure installed viaResetStreamOverhead,StampStreamTransportfor the outbound marshal and client-write time, anddefaultSSEDataReader.ReadDataLineattributing socket reads to upstream; andIsOverheadBreakdownSpan,WithoutOverheadBreakdownSpansand theOverheadSpanConsumerinterface so breakdown spans stay out of connectors that do not opt in (#5533, #6388, #6389, #6433, #6470, #6495) - feat: input/output/additional cost split (
BifrostCost) on inference usages, extended to speech, transcription and OCR usages - feat:
Notification,NotificationInput,NotificationSeverity,NotificationAudienceand theNotificationPublisherfunction type for the dashboard notification center (#6207) - feat:
BifrostContextKeySkipModelCheckshort-circuits the virtual key model allowlist for evaluate-only requests such as/inspectwhile keeping every other governance rule (#6479) - feat:
HarnessSessionHeadersandMaxSessionIDLengthso Claude Code, Codex CLI and OpenCode session headers can fall back into the session ID (#6333) - feat:
RedactSensitiveHeaders, withIsSensitiveHeaderextended to Cloudflare Access (cf-access-*), AWS ALB OIDC (x-amzn-oidc-*) and genericjwt/assertionheaders (#6371) - feat:
ResponsesResponseError.Typeand a shared Responses stream-error normalizer so terminalerror/response.failedevents inside an HTTP 200 Azure SSE stream surface as errors with their nested type, code and message on both create-stream and retrieve-stream paths (thanks @dani29!) (#6302) - feat:
ServiceTieronStreamAccumulatorResult, with Anthropic'sservice_tierfrommessage_startlatched onto the final chunk of chat and Responses streams (#6236) - feat: OpenRouter speech and transcription through the OpenAI-compatible audio handlers instead of returning unsupported-operation errors (#5734)
- fix: preserve
max_tokensfor OpenCode-compatible chat endpoints (thanks @Alex-wangyang!) (#6458) - fix: HuggingFace chat streaming completed with zero tokens and therefore zero cost while non-streaming calls on the same models priced correctly, for two reasons: HuggingFace was listed as a provider that omits the
[DONE]marker (it sends one), which made the shared OpenAI streaming loopbreakon the firstfinish_reasonand discard the trailing usage-only chunk that several router inference providers emit; andstream_options.include_usagenever reached the router because the shared streaming handler returns early when a provider supplies a custom request converter. Both are corrected, and an explicitstream_optionsfrom the caller still wins (thanks @elliottrabac!) (#6478) - fix: preserve the caller's JSON Schema key order for structured outputs -
ChatParameters.UnmarshalJSONholdsresponse_formatas raw bytes and the newChatResponseFormatreader splices them verbatim into OpenAI, Anthropic, Bedrock, Gemini (unless a uniontypearray needs normalizing) and Cohere requests, andResponsesTextConfigFormatJSONSchemare-encodes in the decoded key sequence, because OpenAI structured outputs generate fields in the declared order and a re-sorted schema silently changes model behavior (#6235) - fix: open reasoning stream items that carry both an encrypted payload and a visible summary as
thinkingblocks instead ofredacted_thinkingon the Anthropic egress, withisReasoningItemandreasoningPayloadAndSummaryshared by the native-reasoning and misclassified-function-call branches (#6292) - fix: replayed thinking blocks through the Anthropic ingress with a
bedrock/model prefix: content-lesstool_resultblocks are kept, interleaved text/tool-use/thinking order is preserved by the grouped converter,incompletemaps toerroron ConversetoolResult.status, and buffered reasoning is consumed by the item that owns it, so multi-turn tool use no longer wedges (#6346) - fix: Gemini/Vertex HTTP 400s on Claude Code traffic routed through
/anthropic/v1/messages: trailing assistant prefills are trimmed on both the Responses and chat paths, mid-conversationsystemmessages are inlined in place instead of hoisted intosystemInstruction, andAnthropicMessageResponsegainsExtraFields(#6363) - fix: alias Bedrock
toolUseId/toolResultIdvalues longer than 64 characters or outside[a-zA-Z0-9_.:-](such as Gemini thought-signature IDs) with a deterministic hash prefix, applied identically ontool_useandtool_resultin both the Responses and chat converters (#6300) - fix: route Grok (
xai.) models through theopenai/v1Mantle path on Bedrock and Bedrock Mantle, since they have no Converse equivalent (#6022) - fix: register Bedrock Mantle in
ProviderSendsDoneMarkerso its streams end afterfinish_reasoninstead of waiting for a[DONE]marker (#6021) - fix: include OpenRouter embedding models from
/v1/embeddings/modelsinListModels, merged case-insensitively and best-effort (#6264) - fix: force
reasoning.effortto"none"for models that reason by default but do not support reasoning with tool calls when they advertisesupports_none_reasoning_effort, instead of droppingreasoningoutright (#6293) - fix: backfill upscale output resolution on Replicate from the
target/factorparams andmetrics.resolution_targetbands so resolution-tiered pricing bills the real output size (#6083) - fix: filter forwarded
Accept-Encodingto the codecsCheckAndDecodeBodycan decode (gzip,x-gzip,deflate,br,zstd,identity), restrict streaming endpoints togzip/identityviaSetPassthroughHeadersForStreaming, and decode chained content encodings in reverse order (#6360) - fix:
tool_sync_intervalhandling: negative values are rejected (the "disable sync" semantic is gone now that the connection checker drives discovery and liveness together),ResolveToolSyncIntervalfollows the global setting for sub-second values, a fresh per-call checker starts onEnableClientand on a sticky-to-per-call flip, andMCPManager.UpdateToolSyncInterval,ConnectionCheckerManager.SetGlobalInterval/ApplyGlobalInterval/RetimeClientandClientConnectionChecker.SetHealthyIntervalhot-reload the global cadence and re-time running checkers in place;GetMCPConfigcarries the stored global interval (#6502) - fix:
SetClientToolsandUpdateClientCredentialsreplace the MCP tool map instead ofmaps.Copy-merging into it, so a tool removed upstream is evicted from memory once the database has dropped it (#6484) - fix: per-call shared-credential MCP clients (
oauth,headers,none) refresh tools synchronously on credential update instead of returningErrMCPReconnectNotApplicable; disabled per-call clients and per-user auth types keep the sentinel (#6483) - fix: park a failed
EnableClientdial atDisabledinstead ofUnstable, addErrMCPEnableConnectFailedso callers do not roll back the persisteddisabledflag, and guardisEnableableon both state and config so the admin can retry (#6431) - fix:
output_item.donereplaces server-side tool item shells (web_search_call,code_interpreter_call,image_generation_call) in the Responses streaming accumulator so their full payload survives (#6475) - feat: send
s3://image and document references to Bedrock Converse as thes3Locationsource member instead of downloading the bytes and re-uploading them - Converse resolves the object itself, which skips a round trip and the 25 MiB inline cap entirely. Image format is derived from the object extension since nothing is fetched and there is noContent-Typeto read, and an extension-less object is rejected up front rather than producing an opaque 400 (#6239) - feat: resolve Vertex URL sources per model family rather than inlining everything - a
gs://URI is now forwarded to Gemini/Gemma asfileData.fileUri(the documented form, resolved under the caller's own project IAM, and the only thing that keeps multi-hundred-MB video inputs viable) and read from Cloud Storage with the request key's own Google credentials for Claude-on-Vertex, which accepts base64 sources only.http(s)is still always fetched: forwarding one was measured against the harness and Vertex rejected every endpoint shape withURL_REJECTED-REJECTED_FC_TOO_MANY_PENDING(#6239) - fix: always emit a Gemini candidate carrying its finish reason on
generateContent, even when nothing visible was generated - a thinking model that spends its whole output budget before emitting a token is a successful 200 with an empty answer, butCandidatesisomitempty, so dropping that candidate produced a body with nocandidateskey at all and left a loneusageMetadataobject that every Gemini-shaped client dereferences blind (#6239) - fix: drop payload-free Gemini parts when assembling a candidate - every
Partfield isomitempty, so such a part marshals to exactly{}; the harness observed one on the wire when a transcription request for an unintelligible tone came back asparts:[{}], where it is noise a client will try to read and it masks the contentless case by making the parts slice look non-empty (#6239) - fix: accept a bare model identifier on Bedrock rerank by synthesizing the foundation-model ARN from the resolved region - Rerank is the one Bedrock surface that names its model by ARN rather than by bare ID, so all three rerank drop-ins in the provider harness 400'd on
amazon.rerank-v1:0. The partition is derived from the region (aws,aws-cn,aws-us-gov) so GovCloud and China build a correct ARN, and an explicit ARN still passes through untouched (#6239) - fix: stop stripping
file_urlfrom OpenAI-shaped chat file blocks on marshal - dropping it produced{"type":"file","file":{}}and an upstream complaint about a missingfile_id, which hid the fact that a source had been discarded. Providers that cannot take a URL now say so by name, and any OpenAI-compatible endpoint that does accept one keeps working without a Bifrost change (#6239) - fix: leave URL content sources Bifrost cannot download in place on the OpenAI and native-Anthropic paths instead of failing the request - only
http(s)is fetched, and whether ags://,s3://or scheme-less reference is usable is the provider's call, so the source now travels as{"type":"url"}and the platform answers for itself (#6239) - perf: JSON serialization on the hot path: shared MCP tools cache their serialized bytes on
ChatTool(EnsureSerialized,precomputeToolSerialization) so catalog tools are marshalled once, andOrderedMap.MarshalJSONwrites compact JSON directly into a buffer with an inline HTML-safe string escaper instead of re-routing every nested map throughMarshalSorted, pinned by a byte-identity fuzz harness (#6241, #6242) - perf: allocation and tracing reductions on the request path:
StartSpanIDandSpanFromHandleon the tracer withSpan.SetAttributesfor bulk writes, a resolved-once attribute block inexecuteRequestWithRetries, reusable worker delivery timers,Span.Resetkeeping map capacity,reservedKeysas a set, pre-sizeduserValues, logging context reads deferred to the final chunk, no redundantfmt.Sprintfin logger calls, cached plugin span names, compact JSON request bodies,math/rand/v2inGetRandomString, and aHasPluginLogsguard before draining plugin logs (#5657, #5956, #5957, #6211) - chore: remove the legacy
gen_ai.*-namespaced Bifrost-internal attribute constants,AttrPromptTokens/AttrCompletionTokens,AttrLegacyRetryCountand the nanosecondAttrTimeToFirstTokenin favor of the canonicalbifrost.*keys (#6403) - chore: build with Go 1.26.6 (#6269)
Installation
go get github.com/maximhq/bifrost/core@v1.8.0This release was automatically created from version file: core/version