Skip to content

feat: latency info on errors - #4867

Merged
akshaydeo merged 1 commit into
devfrom
07-02-feat_latency_info_on_errors
Jul 3, 2026
Merged

feat: latency info on errors#4867
akshaydeo merged 1 commit into
devfrom
07-02-feat_latency_info_on_errors

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Provider errors were missing latency information, making it impossible to know how long a request took when it failed. This PR ensures that all error paths — across every provider, for both streaming and non-streaming requests — carry the measured provider request latency in BifrostError.ExtraFields.Latency. The logging plugin is updated to read this latency from errors so failed requests are logged with accurate timing.

Changes

  • Added Latency int64 field to BifrostErrorExtraFields so errors can carry timing data.
  • Added BifrostContextKeyProviderRequestLatency context key to pass measured latency from HTTP helpers to error constructors.
  • Introduced three new helpers in providerUtils:
    • SetErrorLatency — stamps a time.Duration directly onto a BifrostError.
    • SetProviderRequestLatency — records measured latency on the context after client.Do returns.
    • SetErrorLatencyFromContext — reads the context-stored latency and stamps it onto an error; used on error returns that bypass EnrichError.
  • Updated EnrichError to accept an optional variadic latency argument; when provided it stamps the error directly, otherwise it falls back to the context-stored value.
  • Updated MakeRequestWithContext and MakeRequestWithContextFollowRedirects to call SetProviderRequestLatency after the request completes, and updated all error returns inside makeRequestWithDoFunc to carry latency.
  • Applied SetErrorLatency / SetErrorLatencyFromContext / updated EnrichError calls across all providers (Anthropic, Azure, Bedrock, Cohere, ElevenLabs, Gemini, HuggingFace, Mistral, OpenAI, OpenRouter, Perplexity, Replicate, Runware, Runway, VLLM, Vertex) on every error return path, including streaming, passthrough, file, batch, container, and model-listing operations.
  • Updated the logging plugin's PostLLMHook to read bifrostErr.ExtraFields.Latency when a result is absent, so failed requests are logged with the correct latency instead of zero.
  • Replaced inline bifrostErr.ExtraFields = schemas.BifrostErrorExtraFields{...} assignments in bifrost.go with the new PopulateExtraFields helper.
  • Added unit tests covering EnrichError latency stamping, context-based latency propagation, and SetErrorLatencyFromContext no-op behavior.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./core/... ./plugins/...

Trigger a request to any provider with an invalid API key or a network error and verify that the returned BifrostError.ExtraFields.Latency is non-zero and reflects the actual time spent waiting for the provider. Check that the logging plugin records the same non-zero latency for the failed request.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

None. No auth, secrets, or PII are involved; only timing metadata is added to error structs.

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

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 22ff832b-10ca-46a8-a99d-c1827535b197

📥 Commits

Reviewing files that changed from the base of the PR and between 7222d7b and 1d1a633.

📒 Files selected for processing (28)
  • core/bifrost.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/azure/realtime.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/batch.go
  • core/providers/gemini/cachedcontents.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/nebius/nebius.go
  • core/providers/openai/openai.go
  • core/providers/openai/realtime.go
  • core/providers/openrouter/openrouter.go
  • core/providers/perplexity/perplexity.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/runware/runware.go
  • core/providers/runway/runway.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/cachedcontents.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • plugins/logging/main.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Provider errors now consistently include request latency metadata (including streaming and passthrough), improving troubleshooting of slow or failed upstream calls.
  • Bug Fixes

    • Fixed incomplete Bifrost error extra fields when provider queue shutdown prevented rerouting.
    • Updated logging to fall back to latency from the error payload when no result is available.
  • Tests

    • Added unit coverage to ensure latency is set only when explicitly provided during error enrichment.

Walkthrough

This PR adds request-latency tracking utilities and propagates measured latency into Bifrost errors across core request handling, provider implementations, and logging fallback behavior.

Changes

Latency plumbing and core dispatcher

Layer / File(s) Summary
Latency utilities and core dispatcher
core/providers/utils/utils.go, core/providers/utils/utils_test.go, core/schemas/bifrost.go, core/bifrost.go, plugins/logging/main.go
Adds latency error metadata support, updates request helper latency handling, changes dispatcher shutdown metadata population, and adds logging fallback from error latency.

Provider latency enrichment

Layer / File(s) Summary
OpenAI-family providers
core/providers/openai/openai.go, core/providers/openai/realtime.go, core/providers/openrouter/openrouter.go, core/providers/perplexity/perplexity.go, core/providers/azure/azure.go, core/providers/azure/realtime.go, core/providers/vllm/vllm.go
OpenAI, Azure, OpenRouter, Perplexity, and vLLM request, streaming, passthrough, and realtime error paths now attach measured latency.
Anthropic, Bedrock, Cohere, ElevenLabs, HuggingFace, Mistral, Runware, Runway, Replicate
core/providers/anthropic/anthropic.go, core/providers/bedrock/bedrock.go, core/providers/cohere/cohere.go, core/providers/elevenlabs/elevenlabs.go, core/providers/huggingface/huggingface.go, core/providers/mistral/mistral.go, core/providers/runware/runware.go, core/providers/runway/runway.go, core/providers/replicate/replicate.go, core/providers/replicate/utils.go
These providers now propagate request latency through non-OK HTTP responses, streaming failures, and higher-level error enrichment.
Gemini and Vertex providers
core/providers/gemini/batch.go, core/providers/gemini/cachedcontents.go, core/providers/gemini/gemini.go, core/providers/vertex/cachedcontents.go, core/providers/vertex/vertex.go
Gemini and Vertex request, batch, file, cached-content, GCS, streaming, and passthrough paths now attach measured latency to errors and record it in context.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • maximhq/bifrost#3210: Both PRs touch plugins/logging/main.go latency handling on the error path.
  • maximhq/bifrost#4615: Both PRs modify Runware provider error latency handling in sendTaskArray and downstream video flows.
  • maximhq/bifrost#4735: Both PRs modify shared OpenAI and Anthropic handler flows in core/providers/....

Suggested reviewers: akshaydeo, danpiths, roroghost17

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding latency info to errors.
Description check ✅ Passed The description largely matches the template with summary, changes, testing, checklist, and security sections filled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-02-feat_latency_info_on_errors

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e7f7ad04-e800-483c-a214-83ec31f50c6c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-02-feat_latency_info_on_errors

Comment @coderabbitai help to get the list of available commands.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@TejasGhatte
TejasGhatte marked this pull request as ready for review July 2, 2026 19:19

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge after fixing the Anthropic PassthroughStream error type; all other provider paths are correct.

The Anthropic PassthroughStream changes the fallback connection error from NewBifrostOperationError (IsBifrostError=true, stops retry loop) to NewBifrostUpstreamConnectionError (IsBifrostError=false, 502, retriable). This makes Anthropic passthrough connection failures silently retriable when they were not before, and inconsistent with OpenAI passthrough which correctly keeps the non-retriable form. All other latency propagation across the 16+ providers is accurate and well-tested.

core/providers/anthropic/anthropic.go — PassthroughStream fallback error constructor

Important Files Changed

Filename Overview
core/providers/anthropic/anthropic.go Latency plumbed to all error returns. PassthroughStream accidentally changes the fallback connection error from NewBifrostOperationError (non-retriable) to NewBifrostUpstreamConnectionError (retriable), inconsistent with OpenAI's PassthroughStream.
core/providers/utils/utils.go Adds SetErrorLatency helper and inlines latency on all makeRequestWithDoFunc error paths. EnrichError gains optional latency variadic. MakeRequestWithContext wrappers are functionally unchanged (cosmetic rewrite).
core/providers/openai/openai.go Latency consistently threaded into all EnrichError and SetErrorLatency calls. PassthroughStream correctly retains NewBifrostOperationError for the fallback connection error path.
core/providers/replicate/replicate.go createPrediction latency now captured and propagated to EnrichError calls. getPrediction latency set via MakeRequestWithContext. Polling errors report creation latency as a best-effort approximation.
core/schemas/bifrost.go Adds Latency int64 field to BifrostErrorExtraFields with json tag; non-breaking additive schema change.
plugins/logging/main.go Two-line change: reads bifrostErr.ExtraFields.Latency when result is nil, so failed requests log non-zero latency. Correct and safe.
core/bifrost.go Inline BifrostErrorExtraFields{…} assignments on the 'provider is shutting down' paths replaced by PopulateExtraFields helper; no latency loss since these are pre-request errors.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Provider HTTP request] --> B{Request outcome}
    B -->|Connection error| C[makeRequestWithDoFunc\nsets ExtraFields.Latency\ndirectly on error]
    B -->|HTTP error status| D[Caller captures latency\nfrom MakeRequestWithContext\nor time.Since]
    B -->|Streaming: Do returns| E[latency = time.Since\ncaptured before goroutine]
    D --> F[EnrichError called\nwith explicit latency]
    E --> G[Streaming goroutine errors\nuse captured latency]
    F --> H[SetErrorLatency overwrites\nExtraFields.Latency]
    G --> H
    C --> I[Error already has\nlatency set]
    I --> J{Caller calls EnrichError\nwith explicit latency?}
    J -->|Yes| H
    J -->|No| K[Existing latency preserved]
    H --> L[BifrostError.ExtraFields.Latency\nnon-zero on all error paths]
    K --> L
    L --> M[logging plugin PostLLMHook\nreads Latency from error\nwhen result is nil]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Provider HTTP request] --> B{Request outcome}
    B -->|Connection error| C[makeRequestWithDoFunc\nsets ExtraFields.Latency\ndirectly on error]
    B -->|HTTP error status| D[Caller captures latency\nfrom MakeRequestWithContext\nor time.Since]
    B -->|Streaming: Do returns| E[latency = time.Since\ncaptured before goroutine]
    D --> F[EnrichError called\nwith explicit latency]
    E --> G[Streaming goroutine errors\nuse captured latency]
    F --> H[SetErrorLatency overwrites\nExtraFields.Latency]
    G --> H
    C --> I[Error already has\nlatency set]
    I --> J{Caller calls EnrichError\nwith explicit latency?}
    J -->|Yes| H
    J -->|No| K[Existing latency preserved]
    H --> L[BifrostError.ExtraFields.Latency\nnon-zero on all error paths]
    K --> L
    L --> M[logging plugin PostLLMHook\nreads Latency from error\nwhen result is nil]
Loading

Reviews (3): Last reviewed commit: "feat: latency info on errors" | Re-trigger Greptile

Comment thread core/providers/openai/openai.go
Comment thread core/providers/bedrock/bedrock.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
core/providers/openai/openai.go (2)

498-540: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Missing SetProviderRequestLatency call in HandleOpenAITextCompletionStreaming.

Every other streaming handler in this file (HandleOpenAIChatCompletionStreaming line 1076, HandleOpenAIResponsesStreaming line 1750, HandleOpenAISpeechStreamRequest line 2375, HandleOpenAITranscriptionStreamRequest line 2820, HandleOpenAIImageGenerationStreaming line 3256, HandleOpenAIImageEditStreamRequest line 4619, PassthroughStream line 7261) calls providerUtils.SetProviderRequestLatency(ctx, time.Since(startTime)) immediately after activeClient.Do(req, resp). This function computes latency := time.Since(startTime) locally and passes it explicitly to EnrichError for the initial request-level errors, but never stamps it into ctx. As a result, the mid-stream error paths later in this function (lines 628, 640 — unchanged, calling EnrichError without an explicit latency arg) will have no latency in ExtraFields.Latency since the context key was never set.

🐛 Proposed fix
 	startTime := time.Now()
 	// Make the request
 	err := activeClient.Do(req, resp)
+	providerUtils.SetProviderRequestLatency(ctx, time.Since(startTime))
 	if err != nil {
 		defer providerUtils.ReleaseStreamingResponse(ctx, resp)
 		latency := time.Since(startTime)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/openai/openai.go` around lines 498 - 540,
HandleOpenAITextCompletionStreaming should record request latency in the context
the same way the other streaming handlers do. After activeClient.Do(req, resp)
succeeds, call providerUtils.SetProviderRequestLatency(ctx,
time.Since(startTime)) before any later error handling or stream processing.
This ensures the downstream EnrichError paths in
HandleOpenAITextCompletionStreaming can pick up latency from ctx and populate
ExtraFields.Latency consistently.

2817-2847: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Classify pre-first-byte stream Do() failures as upstream connection errors
NewBifrostOperationError(...) in these streaming passthrough branches (openai.go:2836, 3272, 4635, 7277; anthropic.go:2897; gemini.go:4238) stops executeRequestWithRetries before max_retries, so transient connection/DNS/refused failures won’t retry. Switch them to NewBifrostUpstreamConnectionError(...).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/openai/openai.go` around lines 2817 - 2847, Pre-first-byte
streaming Do() failures are currently classified as operation errors, which
prevents executeRequestWithRetries from retrying transient
connection/DNS/refused failures. Update the streaming passthrough error paths
that handle client.Do(req, resp) before the first byte arrives to use
providerUtils.NewBifrostUpstreamConnectionError(...) instead of
providerUtils.NewBifrostOperationError(...). Apply this change in the openai
provider’s streaming request handling and the matching streaming branches in
anthropic and gemini so the retry logic treats these failures as upstream
connection errors.
🧹 Nitpick comments (3)
core/providers/vertex/vertex.go (2)

4557-4563: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Empty-stream-body error also misses latency, right after the newly-instrumented block.

SetProviderRequestLatency was just recorded a few lines above (line 4527), but the "provider returned an empty stream body" error a few lines below returns NewBifrostOperationError unwrapped, so it won't carry the latency this PR is adding elsewhere in the same function.

♻️ Proposed fix
 	bodyStream := resp.BodyStream()
 	if bodyStream == nil {
 		providerUtils.ReleaseStreamingResponse(ctx, resp)
-		return nil, providerUtils.NewBifrostOperationError(
-			"provider returned an empty stream body",
-			fmt.Errorf("provider returned an empty stream body"))
+		return nil, providerUtils.SetErrorLatencyFromContext(ctx, providerUtils.NewBifrostOperationError(
+			"provider returned an empty stream body",
+			fmt.Errorf("provider returned an empty stream body")))
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/vertex/vertex.go` around lines 4557 - 4563, The
empty-stream-body path in the streaming response handling is bypassing the newly
added latency instrumentation. Update the error return in the bodyStream nil
check within the stream-processing logic to include the recorded request latency
the same way the other error paths in this function do, using the existing
SetProviderRequestLatency data before calling
providerUtils.NewBifrostOperationError. Keep the fix localized to the
response-stream handling around bodyStream and the latency instrumentation added
earlier in the same function.

3300-3355: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

gcsListAllObjects missing the same latency wrap as its siblings.

Every other GCS helper in this file (gcsDownloadObject, gcsFileUploadDirect/Resumable, FileList, fileRetrieveByKey, fileDeleteByKey, fileContentByKey) now wraps its parseGCSAPIError return with providerUtils.SetErrorLatencyFromContext(ctx, ...). This function's identical apiErr branch (used by BatchResultsbatchResultsByKey) still returns the raw parsed error with no latency attached, since batchResultsByKey doesn't post-process listErr either.

🐛 Proposed fix
 		var apiErr *schemas.BifrostError
 		if statusCode != fasthttp.StatusOK {
-			apiErr = parseGCSAPIError(resp.Body(), statusCode, "list")
+			apiErr = providerUtils.SetErrorLatencyFromContext(ctx, parseGCSAPIError(resp.Body(), statusCode, "list"))
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/vertex/vertex.go` around lines 3300 - 3355, The
gcsListAllObjects error path is returning a raw parseGCSAPIError result without
the standard latency metadata. Update the apiErr branch in gcsListAllObjects to
wrap the parsed GCS error with providerUtils.SetErrorLatencyFromContext(ctx,
...) just like the sibling helpers (for example gcsDownloadObject and
fileRetrieveByKey), so BatchResults/batchResultsByKey receives the
latency-attached BifrostError consistently.
core/providers/vertex/cachedcontents.go (1)

175-181: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: inconsistent latency-wrapping style vs. sibling methods.

CachedContentCreate wraps the error with providerUtils.SetErrorLatencyFromContext(ctx, ...), while the sibling cachedContentListByKey/cachedContentRetrieveByKey/cachedContentUpdateByKey/cachedContentDeleteByKey (Lines 253, 326, 430, 515) use providerUtils.SetErrorLatency(err, latency) directly with the already-available local latency variable. Both should be functionally equivalent here since ctx is typed *schemas.BifrostContext, but using the direct local latency avoids the extra context-lookup indirection and keeps the file internally consistent.

♻️ Suggested consistency fix
-		return nil, providerUtils.SetErrorLatencyFromContext(ctx, parseVertexCachedContentError(resp))
+		return nil, providerUtils.SetErrorLatency(parseVertexCachedContentError(resp), latency)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/vertex/cachedcontents.go` around lines 175 - 181,
CachedContentCreate uses a different error-latency wrapping style than the
sibling cachedContentListByKey, cachedContentRetrieveByKey,
cachedContentUpdateByKey, and cachedContentDeleteByKey methods. Update the error
return path in CachedContentCreate to wrap parseVertexCachedContentError(resp)
with providerUtils.SetErrorLatency using the local latency value, matching the
other methods and keeping the file consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/anthropic.go`:
- Around line 2880-2898: The error handling in PassthroughStream is using the
wrong Bifrost error type for failures before the first byte is received. Update
the err branch in the activeClient.Do path to return
providerUtils.NewBifrostUpstreamConnectionError(schemas.ErrProviderDoRequest,
err) instead of providerUtils.NewBifrostOperationError(...), while keeping the
existing context-cancelled and timeout handling unchanged.

In `@core/providers/gemini/gemini.go`:
- Around line 4221-4238: Treat pre-first-byte failures from activeClient.Do in
the Gemini streaming path as retriable upstream errors instead of terminal
operation errors. In the error handling block around
providerUtils.ReleaseStreamingResponse and the context canceled/timeout checks,
replace the NewBifrostOperationError branch with
NewBifrostUpstreamConnectionError so executeRequestWithRetries can continue
retrying before max_retries is reached. Keep the existing handling in gemini.go
consistent with the other streaming provider implementations.

---

Outside diff comments:
In `@core/providers/openai/openai.go`:
- Around line 498-540: HandleOpenAITextCompletionStreaming should record request
latency in the context the same way the other streaming handlers do. After
activeClient.Do(req, resp) succeeds, call
providerUtils.SetProviderRequestLatency(ctx, time.Since(startTime)) before any
later error handling or stream processing. This ensures the downstream
EnrichError paths in HandleOpenAITextCompletionStreaming can pick up latency
from ctx and populate ExtraFields.Latency consistently.
- Around line 2817-2847: Pre-first-byte streaming Do() failures are currently
classified as operation errors, which prevents executeRequestWithRetries from
retrying transient connection/DNS/refused failures. Update the streaming
passthrough error paths that handle client.Do(req, resp) before the first byte
arrives to use providerUtils.NewBifrostUpstreamConnectionError(...) instead of
providerUtils.NewBifrostOperationError(...). Apply this change in the openai
provider’s streaming request handling and the matching streaming branches in
anthropic and gemini so the retry logic treats these failures as upstream
connection errors.

---

Nitpick comments:
In `@core/providers/vertex/cachedcontents.go`:
- Around line 175-181: CachedContentCreate uses a different error-latency
wrapping style than the sibling cachedContentListByKey,
cachedContentRetrieveByKey, cachedContentUpdateByKey, and
cachedContentDeleteByKey methods. Update the error return path in
CachedContentCreate to wrap parseVertexCachedContentError(resp) with
providerUtils.SetErrorLatency using the local latency value, matching the other
methods and keeping the file consistent.

In `@core/providers/vertex/vertex.go`:
- Around line 4557-4563: The empty-stream-body path in the streaming response
handling is bypassing the newly added latency instrumentation. Update the error
return in the bodyStream nil check within the stream-processing logic to include
the recorded request latency the same way the other error paths in this function
do, using the existing SetProviderRequestLatency data before calling
providerUtils.NewBifrostOperationError. Keep the fix localized to the
response-stream handling around bodyStream and the latency instrumentation added
earlier in the same function.
- Around line 3300-3355: The gcsListAllObjects error path is returning a raw
parseGCSAPIError result without the standard latency metadata. Update the apiErr
branch in gcsListAllObjects to wrap the parsed GCS error with
providerUtils.SetErrorLatencyFromContext(ctx, ...) just like the sibling helpers
(for example gcsDownloadObject and fileRetrieveByKey), so
BatchResults/batchResultsByKey receives the latency-attached BifrostError
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a1cb1524-eb81-46b3-add4-746dec17f5f3

📥 Commits

Reviewing files that changed from the base of the PR and between 97c8a21 and a3c163c.

📒 Files selected for processing (27)
  • core/bifrost.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/azure/realtime.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/batch.go
  • core/providers/gemini/cachedcontents.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/openai/openai.go
  • core/providers/openai/realtime.go
  • core/providers/openrouter/openrouter.go
  • core/providers/perplexity/perplexity.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/runware/runware.go
  • core/providers/runway/runway.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/cachedcontents.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • plugins/logging/main.go

Comment thread core/providers/anthropic/anthropic.go
Comment thread core/providers/gemini/gemini.go Outdated
@TejasGhatte
TejasGhatte force-pushed the 07-02-feat_latency_info_on_errors branch from a3c163c to 7222d7b Compare July 3, 2026 05:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
core/providers/bedrock/bedrock.go (1)

541-596: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

makeStreamingRequest's Do() catch-all also uses generic classification instead of the retriable upstream-connection error.

Same convention gap as replicate/utils.go's listenToReplicateStreamURL and vllm.go's TranscriptionStream: the final catch-all (lines 576-582) for a pre-first-byte streaming Do() failure builds a plain schemas.ErrProviderDoRequest error instead of NewBifrostUpstreamConnectionError, unlike the corrected pattern used in this same PR by huggingface.go and vertex.go's streaming paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/bedrock/bedrock.go` around lines 541 - 596, The final
catch-all error path in makeStreamingRequest is classifying pre-first-byte
streaming Do() failures as a generic provider request error instead of the
retriable upstream-connection error. Update the respErr handling in
makeStreamingRequest to use NewBifrostUpstreamConnectionError for the
non-timeout, non-cancel, non-DNS/network cases, matching the streaming patterns
used in huggingface.go and vertex.go and keeping the existing latency/error
wrapping through SetErrorLatency.

Source: Learnings

core/providers/vllm/vllm.go (1)

483-504: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Same streaming Do() catch-all classification gap as replicate/utils.go.

The final catch-all at line 503 uses NewBifrostOperationError for a pre-first-byte streaming Do() failure, instead of NewBifrostUpstreamConnectionError used by huggingface.go's and vertex.go's equivalent streaming branches in this same PR. Same fix applies here for retry consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/vllm/vllm.go` around lines 483 - 504, The streaming Do() error
handling in provider.streamingClient.Do within the vllm provider uses the wrong
catch-all classification for pre-first-byte failures. Update the final
non-cancel/non-timeout branch to return a NewBifrostUpstreamConnectionError
instead of NewBifrostOperationError, matching the equivalent streaming paths in
huggingface.go and vertex.go and keeping retry behavior consistent. Keep the
existing latency/error wrapping flow intact with providerUtils.SetErrorLatency.

Source: Learnings

core/providers/replicate/utils.go (1)

110-132: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Streaming Do() catch-all uses generic error, not the retriable upstream-connection classification.

Cancellation/timeout branches look correct, but the final catch-all wraps err with NewBifrostOperationError instead of NewBifrostUpstreamConnectionError. Per repo convention (PR 4662, applied in huggingface.go's ImageGenerationStream/ImageEditStream and vertex.go's PassthroughStream in this same PR), pre-first-byte streaming Do() failures should be classified as retriable upstream-connection errors so executeRequestWithRetries honors max_retries consistently with the non-streaming path.

♻️ Suggested alignment with repo convention
-		return nil, nil, providerUtils.SetErrorLatency(providerUtils.NewBifrostOperationError(schemas.ErrProviderDoRequest, err), latency)
+		// Request failed before the first response byte — classify as retriable upstream connection error,
+		// matching the non-streaming path (see maximhq/bifrost#4496).
+		return nil, nil, providerUtils.SetErrorLatency(providerUtils.NewBifrostUpstreamConnectionError(schemas.ErrProviderDoRequest, err), latency)

Based on learnings: "treat failures that occur in the pre-first-byte phase of the upstream Do() call as NewBifrostUpstreamConnectionError... Also ensure retries only occur when the operator configures max_retries > 0".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/replicate/utils.go` around lines 110 - 132, The catch-all
error path in the streaming Do() flow should be classified as a retriable
upstream connection failure instead of a generic operation error. In the
Replicate streaming helper in utils.go, keep the cancellation and timeout
branches as-is, but change the final return that currently uses
NewBifrostOperationError to use NewBifrostUpstreamConnectionError so
executeRequestWithRetries can apply the same retry behavior as the non-streaming
path. Match the repo convention used in huggingface.go and vertex.go for
pre-first-byte streaming Do() failures.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/providers/bedrock/bedrock.go`:
- Around line 541-596: The final catch-all error path in makeStreamingRequest is
classifying pre-first-byte streaming Do() failures as a generic provider request
error instead of the retriable upstream-connection error. Update the respErr
handling in makeStreamingRequest to use NewBifrostUpstreamConnectionError for
the non-timeout, non-cancel, non-DNS/network cases, matching the streaming
patterns used in huggingface.go and vertex.go and keeping the existing
latency/error wrapping through SetErrorLatency.

In `@core/providers/replicate/utils.go`:
- Around line 110-132: The catch-all error path in the streaming Do() flow
should be classified as a retriable upstream connection failure instead of a
generic operation error. In the Replicate streaming helper in utils.go, keep the
cancellation and timeout branches as-is, but change the final return that
currently uses NewBifrostOperationError to use NewBifrostUpstreamConnectionError
so executeRequestWithRetries can apply the same retry behavior as the
non-streaming path. Match the repo convention used in huggingface.go and
vertex.go for pre-first-byte streaming Do() failures.

In `@core/providers/vllm/vllm.go`:
- Around line 483-504: The streaming Do() error handling in
provider.streamingClient.Do within the vllm provider uses the wrong catch-all
classification for pre-first-byte failures. Update the final
non-cancel/non-timeout branch to return a NewBifrostUpstreamConnectionError
instead of NewBifrostOperationError, matching the equivalent streaming paths in
huggingface.go and vertex.go and keeping retry behavior consistent. Keep the
existing latency/error wrapping flow intact with providerUtils.SetErrorLatency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: eedb5005-6d29-437b-b1fd-769591207ecd

📥 Commits

Reviewing files that changed from the base of the PR and between a3c163c and 7222d7b.

📒 Files selected for processing (27)
  • core/bifrost.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/azure/realtime.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/batch.go
  • core/providers/gemini/cachedcontents.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/openai/openai.go
  • core/providers/openai/realtime.go
  • core/providers/openrouter/openrouter.go
  • core/providers/perplexity/perplexity.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/runware/runware.go
  • core/providers/runway/runway.go
  • core/providers/utils/utils.go
  • core/providers/utils/utils_test.go
  • core/providers/vertex/cachedcontents.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • plugins/logging/main.go
🚧 Files skipped from review as they are similar to previous changes (21)
  • core/providers/openai/realtime.go
  • core/providers/gemini/batch.go
  • core/providers/runware/runware.go
  • core/providers/vertex/cachedcontents.go
  • core/bifrost.go
  • core/providers/azure/realtime.go
  • plugins/logging/main.go
  • core/schemas/bifrost.go
  • core/providers/utils/utils_test.go
  • core/providers/replicate/replicate.go
  • core/providers/perplexity/perplexity.go
  • core/providers/gemini/cachedcontents.go
  • core/providers/cohere/cohere.go
  • core/providers/openrouter/openrouter.go
  • core/providers/anthropic/anthropic.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/azure/azure.go
  • core/providers/mistral/mistral.go
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
  • core/providers/openai/openai.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026

akshaydeo commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jul 3, 5:52 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 3, 5:53 AM UTC: @akshaydeo merged this pull request with Graphite.

Comment thread core/providers/anthropic/anthropic.go
@akshaydeo
akshaydeo merged commit 815c4ce into dev Jul 3, 2026
14 of 16 checks passed
@akshaydeo
akshaydeo deleted the 07-02-feat_latency_info_on_errors branch July 3, 2026 05:53
yangtuooc added a commit to yangtuooc/bifrost that referenced this pull request Jul 3, 2026
* upstream/dev:
  feat: adds multiple teams / customers / bus to connectors (maximhq#4875)
  fix: small latency return fixes (maximhq#4876)
  Added missing OpenAI responses methods for lifecycle related tasks (maximhq#3125)
  feat: latency info on errors (maximhq#4867)
  feat: add `user_name`, `team_ids`, `team_names`, `customer_ids`, `customer_names`, `business_unit_ids`, `business_unit_names` to log list select columns (maximhq#4866)
  feat: add multi-value attribution cell with plural fallback for logs columns (maximhq#4865)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants