Skip to content

fix: inference geo cost on anthropic (#5072) - #5088

Merged
akshaydeo merged 1 commit into
mainfrom
07-10-cp-inference-geo-cost
Jul 10, 2026
Merged

akshaydeo merged 1 commit into
mainfrom
07-10-cp-inference-geo-cost

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds end-to-end support for Anthropic's data-residency billing feature (inference_geo). When Anthropic serves a request with inference_geo: "us", a 1.1× multiplier is applied to all token and cache costs. This PR propagates the inference_geo field from the Anthropic API response through all converter paths (chat, responses, streaming, passthrough) and wires it into the cost engine so US-residency requests bill correctly. It also fixes a related streaming bug where web search request counts were lost on the terminal chunk of streamed Responses requests, causing web search to go unbilled.

Changes

  • inference_geo field propagation: Added InferenceGeo *string to BifrostChatResponse, BifrostResponsesResponse, and BifrostPassthroughUsage schemas. All Anthropic converters (ToBifrostChatResponse, ToBifrostResponsesResponse, ToBifrostResponsesStream, passthrough usage) now forward inference_geo from the provider's usage block.
  • Streaming terminal chunk fix: In both HandleAnthropicChatCompletionStreaming and HandleAnthropicResponsesStream, servedSpeed and servedInferenceGeo are captured across events and re-applied to the terminal chunk. The terminal response.completed chunk is built fresh with no served modifiers, so without this re-apply, fast-mode and data-residency billing silently fell back to standard rates.
  • Web search count accumulation fix: accumulateAnthropicResponsesUsage now carries ServerToolUse.WebSearchRequests into both the response usage accumulator and the mirrored billed usage. Previously the per-event count was overwritten by the terminal chunk's fresh usage, causing web search to go unbilled on streamed Responses requests.
  • Cost engine: serviceTier gains an inferenceGeoUS bool field. tierFromResponse accepts a third inferenceGeo *string argument and sets inferenceGeoUS when the value is "us" (case-insensitive). computeTextCost applies InferenceGeoUSMultiplier to all token/cache costs when inferenceGeoUS is true; the flat per-search fee is intentionally excluded from the multiplier.
  • Database migration: Adds inference_geo_us_multiplier column to TableModelPricing via a new migration step. The column is included in pricing sync, override patching, and the entry↔table conversion helpers.
  • UI: Exposes inference_geo_us_multiplier as a configurable field in the custom pricing override sheet.
  • Tests: New unit tests cover the accumulator web-search fix, the chat and responses converters forwarding inference_geo and web search counts, the cost engine multiplier logic (including the safe no-op when the column is unpopulated), tierFromResponse for inferenceGeoUS, and an end-to-end streaming test (TestResponsesStream_TerminalChunkCarriesServedModifiers) that replays message_start → message_delta → message_stop and asserts the terminal billed chunk carries speed, inference_geo, web search count, and cache-creation tokens.

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

# Core/Transports
go test ./core/providers/anthropic/... ./framework/modelcatalog/datasheet/...

# UI
cd ui
pnpm i
pnpm build

To validate end-to-end: send a chat or responses request to an Anthropic model with data residency enabled. Confirm the response carries inference_geo: "us" and that the billed cost reflects the 1.1× multiplier on token/cache costs with the per-search fee unchanged. For streaming, confirm the terminal chunk carries both speed and inference_geo after message_stop.

The inference_geo_us_multiplier column must be populated in the model pricing datasheet for the multiplier to apply; if the column is null, billing is a safe no-op (standard rates).

Breaking changes

  • No

tierFromResponse gains a third parameter but is an internal function. All call sites have been updated.

Related issues

Security considerations

No auth, secrets, or PII implications. The multiplier is a pricing configuration value stored in the existing model pricing table with the same access controls as other pricing columns.

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

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.
You have signed the CLA already but the status is still pending? Let us recheck it.

TejasGhatte commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
core/providers/anthropic/anthropic.go Updates Anthropic streaming billing state for served speed, inference geo, and web-search usage.
framework/modelcatalog/datasheet/cost.go Adds inference geo tier handling and applies the multiplier to token and cache costs.
framework/configstore/migrations.go Adds a nullable model pricing column for the inference geo multiplier.
ui/app/workspace/custom-pricing/overrides/pricingOverrideSheet.tsx Exposes the inference geo multiplier in the custom pricing override sheet.

Reviews (3): Last reviewed commit: "fix: inference geo cost on anthropic (#5..." | Re-trigger Greptile

Comment thread core/providers/anthropic/anthropic.go
Comment thread core/providers/anthropic/anthropic.go
Comment thread framework/configstore/rdb.go
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 10, 2026
@TejasGhatte
TejasGhatte force-pushed the 07-10-cp-inference-geo-cost branch from b900b3a to 19fb627 Compare July 10, 2026 08:33
@coderabbitai

coderabbitai Bot commented Jul 10, 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: 1c11974c-61cc-4978-9a26-56cb54b9b1df

📥 Commits

Reviewing files that changed from the base of the PR and between 19fb627 and 41d99a8.

📒 Files selected for processing (17)
  • core/providers/anthropic/anthropic.go
  • core/providers/anthropic/chat.go
  • core/providers/anthropic/passthrough_usage.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/utils_test.go
  • core/schemas/chatcompletions.go
  • core/schemas/passthrough.go
  • core/schemas/responses.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/modelpricing.go
  • framework/modelcatalog/datasheet/cost.go
  • framework/modelcatalog/datasheet/cost_test.go
  • framework/modelcatalog/datasheet/overrides.go
  • framework/modelcatalog/datasheet/types.go
  • ui/app/workspace/custom-pricing/overrides/pricingOverrideSheet.tsx
  • ui/lib/types/governance.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Anthropic responses now surface inference geography, fast-mode status, and web-search usage.
    • Billing accurately accounts for web-search queries and US inference-geography pricing.
    • Custom pricing supports configuring an inference-geo US multiplier.
  • Bug Fixes

    • Streaming and non-streaming usage now consistently preserve served pricing details, including terminal responses and passthrough usage.

Walkthrough

Anthropic usage handling now propagates web-search counts, served speed, and inference geography through streaming and response conversions. Model pricing persists and applies an inference-geography multiplier to token costs, with configstore and custom-pricing support.

Changes

Anthropic usage propagation

Layer / File(s) Summary
Response usage contracts and converters
core/schemas/*, core/providers/anthropic/chat.go, core/providers/anthropic/responses.go, core/providers/anthropic/passthrough_usage.go
Response and passthrough usage now carry inference geography, while Anthropic converters forward inference geography and web-search request counts.
Streaming usage and terminal billing
core/providers/anthropic/anthropic.go, core/providers/anthropic/utils_test.go
Streaming handlers retain served speed and inference geography, accumulate web-search requests, and apply these values to terminal billing responses.
Inference-geography pricing and persistence
framework/configstore/*, framework/modelcatalog/datasheet/*
Model pricing stores the US inference multiplier, synchronizes it through configstore and overrides, derives inference-geography tiers, and applies the multiplier to token costs while excluding search fees.
Pricing override interface
ui/app/workspace/custom-pricing/overrides/pricingOverrideSheet.tsx, ui/lib/types/governance.ts
Custom pricing overrides recognize the inference-geography US multiplier field.

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

Sequence Diagram(s)

sequenceDiagram
  participant Anthropic
  participant BifrostStreaming
  participant UsageBilling
  participant ModelPricing
  Anthropic->>BifrostStreaming: stream usage with Speed, InferenceGeo, and web-search counts
  BifrostStreaming->>UsageBilling: accumulate usage and served-tier metadata
  UsageBilling->>ModelPricing: derive pricing tier
  ModelPricing->>UsageBilling: apply US multiplier to token costs
Loading

Possibly related PRs

Suggested reviewers: danpiths, Pratham-Mishra04, roroghost17, akshaydeo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% 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
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.
Title check ✅ Passed The title is concise and accurately summarizes the Anthropic inference-geo billing change.
Description check ✅ Passed The description follows the template closely and covers the required sections, though UI screenshots are omitted.
✨ 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-10-cp-inference-geo-cost

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.

Comment thread framework/configstore/rdb.go

akshaydeo commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jul 10, 10:32 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 10, 10:34 AM UTC: Graphite rebased this pull request as part of a merge.
  • Jul 10, 10:35 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 07-10-cp-anthropic-fast-cache-rate to graphite-base/5088 July 10, 2026 10:32
@akshaydeo
akshaydeo changed the base branch from graphite-base/5088 to main July 10, 2026 10:32
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review July 10, 2026 10:32

The base branch was changed.

## Summary

Adds support for Anthropic's data-residency billing feature (`inference_geo`). When Anthropic serves inference in the US (`inference_geo: "us"`), a 1.1x multiplier is applied to all token and cache costs. This PR propagates the `inference_geo` field through the full response pipeline (chat, responses, streaming, passthrough) and wires it into the cost computation layer, including a new database column and UI override field.

A secondary fix ensures Anthropic server-tool web search request counts (`ServerToolUse.WebSearchRequests`) are correctly forwarded and billed in both streaming and non-streaming paths, where previously the count could be lost when the terminal chunk overwrote the accumulated usage.

## Changes

- **`inference_geo` propagation**: `InferenceGeo *string` added to `BifrostChatResponse`, `BifrostResponsesResponse`, and `BifrostPassthroughUsage`. The field is forwarded from `AnthropicUsage` in all conversion paths: non-streaming chat, non-streaming responses, streaming chat (captured across events and set on the final chunk), streaming responses (`message_delta`), and passthrough.
- **Data-residency multiplier in cost computation**: `serviceTier` gains an `inferenceGeoUS bool` flag. `tierFromResponse` now accepts and evaluates `inferenceGeo`. `computeTextCost` applies `InferenceGeoUSMultiplier` to token/cache costs only — the flat per-search fee is intentionally excluded.
- **Database migration**: `migrationAddInferenceGeoMultiplierColumn` adds `inference_geo_us_multiplier` to `TableModelPricing`. The column is included in the pricing sync update list and mapped through `convertEntryToTablePricing` / `convertTablePricingToEntry`.
- **Web search billing fix**: `accumulateAnthropicResponsesUsage` now carries `ServerToolUse.WebSearchRequests` into the accumulator so the count survives the terminal-chunk overwrite on streamed Responses requests. The non-streaming chat converter also forwards the count into `CompletionTokensDetails.NumSearchQueries`.
- **UI**: `inference_geo_us_multiplier` added to the custom pricing override sheet and `PricingOverridePatch` TypeScript type.
- **Tests**: New unit tests cover the accumulator web-search fix, chat/responses converter forwarding of `InferenceGeo` and web search counts, multiplier application (including the no-multiplier-column safe no-op), and `tierFromResponse` geo detection (case-insensitive).

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go test ./core/providers/anthropic/... ./framework/modelcatalog/datasheet/...

# UI
cd ui
pnpm i || npm i
pnpm build || npm run build
```

To validate end-to-end: send a request to an Anthropic model with data residency enabled. The response should include `inference_geo: "us"` and the computed cost should reflect the 1.1x multiplier on token/cache costs, with the per-search fee unchanged.

## Breaking changes

- [ ] Yes
- [x] No

## Security considerations

No auth, secrets, or PII implications. The `inference_geo` value is sourced from Anthropic's API response and used only for billing computation.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@akshaydeo
akshaydeo force-pushed the 07-10-cp-inference-geo-cost branch from 19fb627 to 41d99a8 Compare July 10, 2026 10:33
@akshaydeo
akshaydeo merged commit e6dfc82 into main Jul 10, 2026
13 of 14 checks passed
@akshaydeo
akshaydeo deleted the 07-10-cp-inference-geo-cost branch July 10, 2026 10:35
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
## Summary

Adds end-to-end support for Anthropic's data-residency billing feature (`inference_geo`). When Anthropic serves a request with `inference_geo: "us"`, a 1.1× multiplier is applied to all token and cache costs. This PR propagates the `inference_geo` field from the Anthropic API response through all converter paths (chat, responses, streaming, passthrough) and wires it into the cost engine so US-residency requests bill correctly. It also fixes a related streaming bug where web search request counts were lost on the terminal chunk of streamed Responses requests, causing web search to go unbilled.

## Changes

- **`inference_geo` field propagation**: Added `InferenceGeo *string` to `BifrostChatResponse`, `BifrostResponsesResponse`, and `BifrostPassthroughUsage` schemas. All Anthropic converters (`ToBifrostChatResponse`, `ToBifrostResponsesResponse`, `ToBifrostResponsesStream`, passthrough usage) now forward `inference_geo` from the provider's usage block.
- **Streaming terminal chunk fix**: In both `HandleAnthropicChatCompletionStreaming` and `HandleAnthropicResponsesStream`, `servedSpeed` and `servedInferenceGeo` are captured across events and re-applied to the terminal chunk. The terminal `response.completed` chunk is built fresh with no served modifiers, so without this re-apply, fast-mode and data-residency billing silently fell back to standard rates.
- **Web search count accumulation fix**: `accumulateAnthropicResponsesUsage` now carries `ServerToolUse.WebSearchRequests` into both the response usage accumulator and the mirrored billed usage. Previously the per-event count was overwritten by the terminal chunk's fresh usage, causing web search to go unbilled on streamed Responses requests.
- **Cost engine**: `serviceTier` gains an `inferenceGeoUS bool` field. `tierFromResponse` accepts a third `inferenceGeo *string` argument and sets `inferenceGeoUS` when the value is `"us"` (case-insensitive). `computeTextCost` applies `InferenceGeoUSMultiplier` to all token/cache costs when `inferenceGeoUS` is true; the flat per-search fee is intentionally excluded from the multiplier.
- **Database migration**: Adds `inference_geo_us_multiplier` column to `TableModelPricing` via a new migration step. The column is included in pricing sync, override patching, and the entry↔table conversion helpers.
- **UI**: Exposes `inference_geo_us_multiplier` as a configurable field in the custom pricing override sheet.
- **Tests**: New unit tests cover the accumulator web-search fix, the chat and responses converters forwarding `inference_geo` and web search counts, the cost engine multiplier logic (including the safe no-op when the column is unpopulated), `tierFromResponse` for `inferenceGeoUS`, and an end-to-end streaming test (`TestResponsesStream_TerminalChunkCarriesServedModifiers`) that replays `message_start → message_delta → message_stop` and asserts the terminal billed chunk carries `speed`, `inference_geo`, web search count, and cache-creation tokens.

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go test ./core/providers/anthropic/... ./framework/modelcatalog/datasheet/...

# UI
cd ui
pnpm i
pnpm build
```

To validate end-to-end: send a chat or responses request to an Anthropic model with data residency enabled. Confirm the response carries `inference_geo: "us"` and that the billed cost reflects the 1.1× multiplier on token/cache costs with the per-search fee unchanged. For streaming, confirm the terminal chunk carries both `speed` and `inference_geo` after `message_stop`.

The `inference_geo_us_multiplier` column must be populated in the model pricing datasheet for the multiplier to apply; if the column is `null`, billing is a safe no-op (standard rates).

## Breaking changes

- [x] No

`tierFromResponse` gains a third parameter but is an internal function. All call sites have been updated.

## Related issues

## Security considerations

No auth, secrets, or PII implications. The multiplier is a pricing configuration value stored in the existing model pricing table with the same access controls as other pricing columns.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
## Summary

Adds end-to-end support for Anthropic's data-residency billing feature (`inference_geo`). When Anthropic serves a request with `inference_geo: "us"`, a 1.1× multiplier is applied to all token and cache costs. This PR propagates the `inference_geo` field from the Anthropic API response through all converter paths (chat, responses, streaming, passthrough) and wires it into the cost engine so US-residency requests bill correctly. It also fixes a related streaming bug where web search request counts were lost on the terminal chunk of streamed Responses requests, causing web search to go unbilled.

## Changes

- **`inference_geo` field propagation**: Added `InferenceGeo *string` to `BifrostChatResponse`, `BifrostResponsesResponse`, and `BifrostPassthroughUsage` schemas. All Anthropic converters (`ToBifrostChatResponse`, `ToBifrostResponsesResponse`, `ToBifrostResponsesStream`, passthrough usage) now forward `inference_geo` from the provider's usage block.
- **Streaming terminal chunk fix**: In both `HandleAnthropicChatCompletionStreaming` and `HandleAnthropicResponsesStream`, `servedSpeed` and `servedInferenceGeo` are captured across events and re-applied to the terminal chunk. The terminal `response.completed` chunk is built fresh with no served modifiers, so without this re-apply, fast-mode and data-residency billing silently fell back to standard rates.
- **Web search count accumulation fix**: `accumulateAnthropicResponsesUsage` now carries `ServerToolUse.WebSearchRequests` into both the response usage accumulator and the mirrored billed usage. Previously the per-event count was overwritten by the terminal chunk's fresh usage, causing web search to go unbilled on streamed Responses requests.
- **Cost engine**: `serviceTier` gains an `inferenceGeoUS bool` field. `tierFromResponse` accepts a third `inferenceGeo *string` argument and sets `inferenceGeoUS` when the value is `"us"` (case-insensitive). `computeTextCost` applies `InferenceGeoUSMultiplier` to all token/cache costs when `inferenceGeoUS` is true; the flat per-search fee is intentionally excluded from the multiplier.
- **Database migration**: Adds `inference_geo_us_multiplier` column to `TableModelPricing` via a new migration step. The column is included in pricing sync, override patching, and the entry↔table conversion helpers.
- **UI**: Exposes `inference_geo_us_multiplier` as a configurable field in the custom pricing override sheet.
- **Tests**: New unit tests cover the accumulator web-search fix, the chat and responses converters forwarding `inference_geo` and web search counts, the cost engine multiplier logic (including the safe no-op when the column is unpopulated), `tierFromResponse` for `inferenceGeoUS`, and an end-to-end streaming test (`TestResponsesStream_TerminalChunkCarriesServedModifiers`) that replays `message_start → message_delta → message_stop` and asserts the terminal billed chunk carries `speed`, `inference_geo`, web search count, and cache-creation tokens.

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go test ./core/providers/anthropic/... ./framework/modelcatalog/datasheet/...

# UI
cd ui
pnpm i
pnpm build
```

To validate end-to-end: send a chat or responses request to an Anthropic model with data residency enabled. Confirm the response carries `inference_geo: "us"` and that the billed cost reflects the 1.1× multiplier on token/cache costs with the per-search fee unchanged. For streaming, confirm the terminal chunk carries both `speed` and `inference_geo` after `message_stop`.

The `inference_geo_us_multiplier` column must be populated in the model pricing datasheet for the multiplier to apply; if the column is `null`, billing is a safe no-op (standard rates).

## Breaking changes

- [x] No

`tierFromResponse` gains a third parameter but is an internal function. All call sites have been updated.

## Related issues

## Security considerations

No auth, secrets, or PII implications. The multiplier is a pricing configuration value stored in the existing model pricing table with the same access controls as other pricing columns.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] 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