Skip to content

feat: adds bifrost latency data to connectors - #5467

Merged
akshaydeo merged 1 commit into
devfrom
07-21-feat_adds_bifrost_latency_data_to_connectors
Jul 23, 2026
Merged

feat: adds bifrost latency data to connectors#5467
akshaydeo merged 1 commit into
devfrom
07-21-feat_adds_bifrost_latency_data_to_connectors

Conversation

@roroghost17

@roroghost17 roroghost17 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces a per-request upstream latency accumulator that tracks cumulative time Bifrost spends blocked on provider sockets across every attempt, retry, fallback, MCP tool call, and media fetch. Subtracting this from total wall time gives Bifrost's own processing overhead — a number that was previously impossible to derive accurately.

Changes

  • New upstreamlatency.go schema: Installs an *atomic.Int64 accumulator on the BifrostContext once per request. Uses an atomic pointer so streaming goroutines can keep writing after the request handler returns without touching the context's value map.
  • ResetUpstreamLatency / AddUpstreamLatency / GetUpstreamLatency: Core API for the accumulator. Reset is mandatory at request entry because Bifrost reuses a single process-global context for nil-ctx SDK callers; without it the counter would grow unboundedly.
  • DoStreamingRequest / DoHTTPRequest helpers: Thin wrappers around fasthttp.Client.Do and net/http.Client.Do that record the call duration as upstream latency. All provider call sites are migrated to these helpers.
  • idleTimeoutReader.Read instrumentation: Each blocking read in a streaming response is counted as upstream time, covering the token-generation window that DoStreamingRequest (which returns at first byte) cannot see.
  • MCP tool call instrumentation: executeToolInternal wraps CallTool with the same accumulator, since waiting on an MCP server is upstream time, not Bifrost overhead.
  • FetchAndEncodeURL instrumentation: Remote media fetches are counted as upstream, preventing multi-second fetches from appearing as Bifrost overhead.
  • StampUpstreamLatency / PopulateUpstreamLatency: Write the accumulated total onto the root trace span (bifrost.upstream.duration_ms) and onto BifrostResponseExtraFields.UpstreamLatency respectively. Both are called via a named-return defer in handleRequest so they fire even on error paths.
  • Trace.StampOverheadDuration: Computes bifrost.overhead.duration_ms = root_span_duration - upstream_total on the export snapshot, after the root span has ended. Clamped at zero to absorb clock skew.
  • OTel plugin: Reads AttrBifrostOverheadDurationMs from the root span and records it as a new bifrost_overhead_latency_seconds histogram with fine-grained sub-millisecond buckets appropriate for processing overhead rather than network latency.
  • Prometheus plugin: Records the same overhead histogram via the HTTPTransportPreHook/HTTPTransportPostHook window (widest available, matching the OTel root span). Falls back to the PostLLMHook window for SDK callers that bypass the transport layer.
  • HTTP transport: Emits x-bifrost-upstream-latency-ms response header so proxy callers can derive overhead from their own elapsed time without parsing the response body.
  • New trace attributes: bifrost.upstream.duration_ms and bifrost.overhead.duration_ms added to the attribute constant set.

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 ./...
  • Make a request through the HTTP transport and verify the x-bifrost-upstream-latency-ms response header is present and less than the total elapsed time.
  • Make a streaming request and confirm the header value grows to reflect the full generation window, not just time-to-first-byte.
  • Make a request that triggers a fallback and confirm the upstream latency reflects the sum of both attempts.
  • In OTel/Prometheus dashboards, verify bifrost_overhead_latency_seconds appears and that its values are in the sub-millisecond to low-tens-of-milliseconds range for healthy requests.
  • Confirm bifrost.upstream.duration_ms and bifrost.overhead.duration_ms appear on root spans in exported traces.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

None. The upstream latency value is derived from internal timing and contains no secrets or PII. The new response header exposes only a duration in milliseconds.

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

@CLAassistant

CLAassistant commented Jul 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f7e7a21d-0eed-4ce6-917d-0fc3e66245a0

📥 Commits

Reviewing files that changed from the base of the PR and between f5ee311 and 18c4935.

📒 Files selected for processing (31)
  • core/bifrost.go
  • core/mcp/toolmanager.go
  • core/overhead_e2e_test.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/openai/openai.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/sarvam/sarvam.go
  • core/providers/utils/fetch.go
  • core/providers/utils/upstream_latency_test.go
  • core/providers/utils/utils.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/trace.go
  • core/schemas/upstream_latency_test.go
  • core/schemas/upstreamlatency.go
  • framework/tracing/tracer.go
  • plugins/otel/converter.go
  • plugins/otel/main.go
  • plugins/otel/metrics.go
  • plugins/telemetry/main.go
  • transports/bifrost-http/integrations/utils.go
🚧 Files skipped from review as they are similar to previous changes (28)
  • core/schemas/context.go
  • core/providers/utils/fetch.go
  • core/providers/sarvam/sarvam.go
  • plugins/otel/converter.go
  • core/schemas/bifrost.go
  • core/mcp/toolmanager.go
  • core/providers/mistral/mistral.go
  • core/providers/replicate/utils.go
  • core/providers/cohere/cohere.go
  • core/providers/replicate/replicate.go
  • core/providers/elevenlabs/elevenlabs.go
  • framework/tracing/tracer.go
  • core/providers/huggingface/huggingface.go
  • plugins/otel/main.go
  • core/schemas/upstreamlatency.go
  • core/providers/vllm/vllm.go
  • core/bifrost.go
  • core/providers/gemini/gemini.go
  • core/schemas/trace.go
  • core/providers/vertex/vertex.go
  • plugins/otel/metrics.go
  • core/providers/anthropic/anthropic.go
  • transports/bifrost-http/integrations/utils.go
  • core/providers/utils/utils.go
  • plugins/telemetry/main.go
  • core/providers/bedrock/bedrock.go
  • core/providers/openai/openai.go
  • core/providers/azure/azure.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added upstream latency telemetry to responses via x-bifrost-upstream-latency-ms.
    • Added Bifrost “overhead” and upstream latency metrics, including root-span overhead timing for improved observability.
  • Bug Fixes
    • Improved upstream latency lifecycle tracking across retries, failures, fallbacks, and streaming.
    • Standardized streaming request execution to better respect cancellation and context consistently across providers.
  • Tests
    • Added end-to-end and unit coverage for upstream latency accumulation, reset, cancellation, and streaming behavior.

Walkthrough

This PR adds per-request upstream latency accumulation, routes provider calls through instrumented helpers, exposes latency in traces, responses, and headers, computes Bifrost overhead, and records overhead in OTel and Prometheus telemetry.

Changes

Upstream Latency and Overhead Instrumentation

Layer / File(s) Summary
Upstream latency and overhead data model
core/schemas/upstreamlatency.go, core/schemas/bifrost.go, core/schemas/context.go, core/schemas/trace.go
Adds latency accumulators, response fields, trace attributes, stamping helpers, overhead calculation, and reserved-key protection.
Shared HTTP and streaming execution helpers
core/providers/utils/utils.go, core/providers/utils/fetch.go
Adds instrumented HTTP helpers and records latency for unary calls, stream reads, cancellation, deferred spans, and URL fetching.
Provider call sites switched to instrumented helpers
core/providers/{anthropic,azure,bedrock,cohere,elevenlabs,gemini,huggingface,mistral,openai,replicate,sarvam,vertex,vllm}/*
Routes provider streaming, unary, batch, file, and passthrough requests through shared helpers.
Core request and MCP latency wiring
core/bifrost.go, core/mcp/toolmanager.go
Resets and exports latency around core requests and records MCP tool-call duration.
Trace overhead stamping
framework/tracing/tracer.go
Stamps calculated overhead onto exported trace snapshots.
OTel overhead metrics
plugins/otel/main.go, plugins/otel/metrics.go, plugins/otel/converter.go
Adds overhead extraction, histogram configuration, and conditional metric recording.
Prometheus overhead metrics
plugins/telemetry/main.go
Adds overhead histogram configuration and recording across transport and SDK paths.
HTTP response latency header
transports/bifrost-http/integrations/utils.go
Adds and conditionally emits x-bifrost-upstream-latency-ms.
Latency and overhead validation
core/schemas/upstream_latency_test.go, core/providers/utils/upstream_latency_test.go, core/overhead_e2e_test.go
Validates accumulation, retries, streaming reads, resets, tracing, responses, and overhead calculations.

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

Possibly related PRs

  • maximhq/bifrost#5237: Both changes modify MCP executeToolInternal and the CallTool execution path.

Suggested reviewers: akshaydeo, danpiths, tejasghatte, sammaji

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and broadly matches the PR’s new latency instrumentation across connectors.
Description check ✅ Passed The PR description follows the template closely and includes the key sections, testing steps, and impact notes.
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-21-feat_adds_bifrost_latency_data_to_connectors

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.

roroghost17 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

@roroghost17
roroghost17 force-pushed the 07-21-feat_adds_bifrost_latency_data_to_connectors branch from f9e0b06 to f4f9848 Compare July 22, 2026 12:38
@roroghost17
roroghost17 marked this pull request as ready for review July 22, 2026 13:29

@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: 3

🤖 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/schemas/upstreamlatency.go`:
- Around line 29-56: Update ResetUpstreamLatency so it never replaces the
accumulator on the shared fallback context used by nil callers; ensure each
request receives a distinct context/accumulator before reset, or otherwise keep
upstream latency state request-scoped. Preserve AddUpstreamLatency’s
context-based lookup and ensure response telemetry cannot combine or
misattribute concurrent nil-context requests.

In `@plugins/telemetry/main.go`:
- Around line 1039-1048: Update PostLLMHook so the cloned overheadLabels are
stored via ctx.SetValue before launching the asynchronous goroutine, only for
the final stream or non-stream request. Keep HTTPTransportPostHook able to read
those labels immediately, and retain direct SDK overhead recording inside the
goroutine.

In `@transports/bifrost-http/integrations/utils.go`:
- Around line 300-304: Update the upstream-latency header logic around
GetUpstreamLatency so the header is emitted only when an upstream duration was
actually measured, not merely when the accumulator exists. Treat zero or
otherwise unrecorded latency as absent while preserving the existing millisecond
formatting for valid measurements.
🪄 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: 00f65123-b5e3-4755-b599-27b1a3866aec

📥 Commits

Reviewing files that changed from the base of the PR and between f736463 and f4f9848.

📒 Files selected for processing (28)
  • core/bifrost.go
  • core/mcp/toolmanager.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/openai/openai.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/sarvam/sarvam.go
  • core/providers/utils/fetch.go
  • core/providers/utils/utils.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/trace.go
  • core/schemas/upstreamlatency.go
  • framework/tracing/tracer.go
  • plugins/otel/converter.go
  • plugins/otel/main.go
  • plugins/otel/metrics.go
  • plugins/telemetry/main.go
  • transports/bifrost-http/integrations/utils.go

Comment thread core/schemas/upstreamlatency.go
Comment thread plugins/telemetry/main.go Outdated
Comment thread transports/bifrost-http/integrations/utils.go Outdated

@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: 1

🤖 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/bedrock/bedrock.go`:
- Line 313: Update the Bedrock request flows using providerUtils.DoHTTPRequest
so upstream latency spans both HTTP execution and response-body consumption,
rather than stopping at response headers. Apply this consistently in
core/providers/bedrock/bedrock.go at lines 313, 410, 734, 815, 2483, 2612, 2822,
2903, 3108, 3233, 3351, 3413, and 3557, covering foundation/agent/Mantle calls,
S3 operations, and batch operations; preserve each method’s existing body and
error handling while recording the elapsed time only after the relevant body
read completes.
🪄 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: e26c08f2-bae8-4105-8505-be6c33318b7b

📥 Commits

Reviewing files that changed from the base of the PR and between f4f9848 and f5ee311.

📒 Files selected for processing (28)
  • core/bifrost.go
  • core/mcp/toolmanager.go
  • core/providers/anthropic/anthropic.go
  • core/providers/azure/azure.go
  • core/providers/bedrock/bedrock.go
  • core/providers/cohere/cohere.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/gemini/gemini.go
  • core/providers/huggingface/huggingface.go
  • core/providers/mistral/mistral.go
  • core/providers/openai/openai.go
  • core/providers/replicate/replicate.go
  • core/providers/replicate/utils.go
  • core/providers/sarvam/sarvam.go
  • core/providers/utils/fetch.go
  • core/providers/utils/utils.go
  • core/providers/vertex/vertex.go
  • core/providers/vllm/vllm.go
  • core/schemas/bifrost.go
  • core/schemas/context.go
  • core/schemas/trace.go
  • core/schemas/upstreamlatency.go
  • framework/tracing/tracer.go
  • plugins/otel/converter.go
  • plugins/otel/main.go
  • plugins/otel/metrics.go
  • plugins/telemetry/main.go
  • transports/bifrost-http/integrations/utils.go
🚧 Files skipped from review as they are similar to previous changes (26)
  • core/providers/utils/fetch.go
  • core/schemas/context.go
  • core/providers/vllm/vllm.go
  • core/providers/elevenlabs/elevenlabs.go
  • core/providers/vertex/vertex.go
  • core/providers/cohere/cohere.go
  • core/providers/mistral/mistral.go
  • core/providers/replicate/replicate.go
  • core/providers/azure/azure.go
  • core/providers/replicate/utils.go
  • framework/tracing/tracer.go
  • core/providers/sarvam/sarvam.go
  • core/schemas/bifrost.go
  • core/mcp/toolmanager.go
  • core/providers/huggingface/huggingface.go
  • core/schemas/trace.go
  • core/providers/gemini/gemini.go
  • core/providers/openai/openai.go
  • transports/bifrost-http/integrations/utils.go
  • core/schemas/upstreamlatency.go
  • core/providers/anthropic/anthropic.go
  • core/bifrost.go
  • core/providers/utils/utils.go
  • plugins/telemetry/main.go
  • plugins/otel/main.go
  • plugins/otel/converter.go

Comment thread core/providers/bedrock/bedrock.go
@roroghost17
roroghost17 force-pushed the 07-21-feat_adds_bifrost_latency_data_to_connectors branch from f5ee311 to 18c4935 Compare July 23, 2026 00:12

akshaydeo commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jul 23, 7:34 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 23, 7:34 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit b152185 into dev Jul 23, 2026
14 of 15 checks passed
@akshaydeo
akshaydeo deleted the 07-21-feat_adds_bifrost_latency_data_to_connectors branch July 23, 2026 07:34
akshaydeo pushed a commit that referenced this pull request Jul 24, 2026
## Summary

Introduces a per-request upstream latency accumulator that tracks cumulative time Bifrost spends blocked on provider sockets across every attempt, retry, fallback, MCP tool call, and media fetch. Subtracting this from total wall time gives Bifrost's own processing overhead — a number that was previously impossible to derive accurately.

## Changes

- **New `upstreamlatency.go` schema**: Installs an `*atomic.Int64` accumulator on the `BifrostContext` once per request. Uses an atomic pointer so streaming goroutines can keep writing after the request handler returns without touching the context's value map.
- **`ResetUpstreamLatency` / `AddUpstreamLatency` / `GetUpstreamLatency`**: Core API for the accumulator. `Reset` is mandatory at request entry because Bifrost reuses a single process-global context for nil-ctx SDK callers; without it the counter would grow unboundedly.
- **`DoStreamingRequest` / `DoHTTPRequest` helpers**: Thin wrappers around `fasthttp.Client.Do` and `net/http.Client.Do` that record the call duration as upstream latency. All provider call sites are migrated to these helpers.
- **`idleTimeoutReader.Read` instrumentation**: Each blocking read in a streaming response is counted as upstream time, covering the token-generation window that `DoStreamingRequest` (which returns at first byte) cannot see.
- **MCP tool call instrumentation**: `executeToolInternal` wraps `CallTool` with the same accumulator, since waiting on an MCP server is upstream time, not Bifrost overhead.
- **`FetchAndEncodeURL` instrumentation**: Remote media fetches are counted as upstream, preventing multi-second fetches from appearing as Bifrost overhead.
- **`StampUpstreamLatency` / `PopulateUpstreamLatency`**: Write the accumulated total onto the root trace span (`bifrost.upstream.duration_ms`) and onto `BifrostResponseExtraFields.UpstreamLatency` respectively. Both are called via a named-return `defer` in `handleRequest` so they fire even on error paths.
- **`Trace.StampOverheadDuration`**: Computes `bifrost.overhead.duration_ms = root_span_duration - upstream_total` on the export snapshot, after the root span has ended. Clamped at zero to absorb clock skew.
- **OTel plugin**: Reads `AttrBifrostOverheadDurationMs` from the root span and records it as a new `bifrost_overhead_latency_seconds` histogram with fine-grained sub-millisecond buckets appropriate for processing overhead rather than network latency.
- **Prometheus plugin**: Records the same overhead histogram via the `HTTPTransportPreHook`/`HTTPTransportPostHook` window (widest available, matching the OTel root span). Falls back to the `PostLLMHook` window for SDK callers that bypass the transport layer.
- **HTTP transport**: Emits `x-bifrost-upstream-latency-ms` response header so proxy callers can derive overhead from their own elapsed time without parsing the response body.
- **New trace attributes**: `bifrost.upstream.duration_ms` and `bifrost.overhead.duration_ms` added to the attribute constant set.

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./...
```

- Make a request through the HTTP transport and verify the `x-bifrost-upstream-latency-ms` response header is present and less than the total elapsed time.
- Make a streaming request and confirm the header value grows to reflect the full generation window, not just time-to-first-byte.
- Make a request that triggers a fallback and confirm the upstream latency reflects the sum of both attempts.
- In OTel/Prometheus dashboards, verify `bifrost_overhead_latency_seconds` appears and that its values are in the sub-millisecond to low-tens-of-milliseconds range for healthy requests.
- Confirm `bifrost.upstream.duration_ms` and `bifrost.overhead.duration_ms` appear on root spans in exported traces.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None. The upstream latency value is derived from internal timing and contains no secrets or PII. The new response header exposes only a duration in milliseconds.

## 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
BearTS pushed a commit that referenced this pull request Jul 27, 2026
Introduces a per-request upstream latency accumulator that tracks cumulative time Bifrost spends blocked on provider sockets across every attempt, retry, fallback, MCP tool call, and media fetch. Subtracting this from total wall time gives Bifrost's own processing overhead — a number that was previously impossible to derive accurately.

- **New `upstreamlatency.go` schema**: Installs an `*atomic.Int64` accumulator on the `BifrostContext` once per request. Uses an atomic pointer so streaming goroutines can keep writing after the request handler returns without touching the context's value map.
- **`ResetUpstreamLatency` / `AddUpstreamLatency` / `GetUpstreamLatency`**: Core API for the accumulator. `Reset` is mandatory at request entry because Bifrost reuses a single process-global context for nil-ctx SDK callers; without it the counter would grow unboundedly.
- **`DoStreamingRequest` / `DoHTTPRequest` helpers**: Thin wrappers around `fasthttp.Client.Do` and `net/http.Client.Do` that record the call duration as upstream latency. All provider call sites are migrated to these helpers.
- **`idleTimeoutReader.Read` instrumentation**: Each blocking read in a streaming response is counted as upstream time, covering the token-generation window that `DoStreamingRequest` (which returns at first byte) cannot see.
- **MCP tool call instrumentation**: `executeToolInternal` wraps `CallTool` with the same accumulator, since waiting on an MCP server is upstream time, not Bifrost overhead.
- **`FetchAndEncodeURL` instrumentation**: Remote media fetches are counted as upstream, preventing multi-second fetches from appearing as Bifrost overhead.
- **`StampUpstreamLatency` / `PopulateUpstreamLatency`**: Write the accumulated total onto the root trace span (`bifrost.upstream.duration_ms`) and onto `BifrostResponseExtraFields.UpstreamLatency` respectively. Both are called via a named-return `defer` in `handleRequest` so they fire even on error paths.
- **`Trace.StampOverheadDuration`**: Computes `bifrost.overhead.duration_ms = root_span_duration - upstream_total` on the export snapshot, after the root span has ended. Clamped at zero to absorb clock skew.
- **OTel plugin**: Reads `AttrBifrostOverheadDurationMs` from the root span and records it as a new `bifrost_overhead_latency_seconds` histogram with fine-grained sub-millisecond buckets appropriate for processing overhead rather than network latency.
- **Prometheus plugin**: Records the same overhead histogram via the `HTTPTransportPreHook`/`HTTPTransportPostHook` window (widest available, matching the OTel root span). Falls back to the `PostLLMHook` window for SDK callers that bypass the transport layer.
- **HTTP transport**: Emits `x-bifrost-upstream-latency-ms` response header so proxy callers can derive overhead from their own elapsed time without parsing the response body.
- **New trace attributes**: `bifrost.upstream.duration_ms` and `bifrost.overhead.duration_ms` added to the attribute constant set.

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [ ] UI (React)
- [ ] Docs

```sh
go test ./...
```

- Make a request through the HTTP transport and verify the `x-bifrost-upstream-latency-ms` response header is present and less than the total elapsed time.
- Make a streaming request and confirm the header value grows to reflect the full generation window, not just time-to-first-byte.
- Make a request that triggers a fallback and confirm the upstream latency reflects the sum of both attempts.
- In OTel/Prometheus dashboards, verify `bifrost_overhead_latency_seconds` appears and that its values are in the sub-millisecond to low-tens-of-milliseconds range for healthy requests.
- Confirm `bifrost.upstream.duration_ms` and `bifrost.overhead.duration_ms` appear on root spans in exported traces.

- [ ] Yes
- [x] No

None. The upstream latency value is derived from internal timing and contains no secrets or PII. The new response header exposes only a duration in milliseconds.

- [ ] 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
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