Skip to content

fix(aio): price Anthropic cache writes by TTL - #71323

Merged
richardsolomou merged 2 commits into
PostHog:masterfrom
gouveags:fix/anthropic-cache-ttl-pricing
Jul 28, 2026
Merged

fix(aio): price Anthropic cache writes by TTL#71323
richardsolomou merged 2 commits into
PostHog:masterfrom
gouveags:fix/anthropic-cache-ttl-pricing

Conversation

@gouveags

@gouveags gouveags commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Problem

Anthropic prices 5-minute cache writes at 1.25 × the input-token rate and 1-hour writes at 2 ×. PostHog currently collapses both into one aggregate count, so automatic costing applies the 5-minute rate to 1-hour writes.

Closes #71306

Changes

  • Preserve Anthropic's 5-minute and 1-hour cache-creation counts from direct raw usage and @posthog/ai's Vercel wrapper (usage.raw and providerMetadata.anthropic.usage).
  • Extract Vercel Amazon Bedrock's TTL breakdown from providerMetadata.amazonBedrock.usage.cacheDetails, with legacy bedrock alias support and no double-counting when both aliases are present.
  • Price a complete TTL breakdown separately without double-counting the aggregate. Aggregate-only and partial-breakdown events keep the existing path.
  • Register, validate, and document the new token-count fields and custom-pricing precedence.

For custom pricing, $ai_cache_write_1h_token_price wins for 1-hour writes. If it is absent, $ai_cache_write_token_price applies to both TTLs. Catalog pricing keeps the existing 5-minute rate and derives the 1-hour rate from 2 × the resolved prompt price. No model prices are hardcoded.

Note

This corrects core ingestion when an event supplies a complete TTL breakdown through raw Anthropic usage, Vercel Amazon Bedrock metadata, or both explicit properties. SDKs that emit only the aggregate keep the existing pricing path until they propagate the breakdown.

How did you test this code?

  • Focused AI costing, extraction, and pipeline suites: 3 suites, 257 tests passed.
  • Shared AI token validator suite: 1 suite, 1,183 tests passed.
  • Covered 5-minute, 1-hour, mixed-TTL, aggregate-only, partial-breakdown, custom-price precedence, raw extraction, Vercel Bedrock top-level and nested provider metadata, aliases, and sparse TTL buckets, $ai_usage removal, process-level pricing, and invalid-property normalization.
  • Ran the Node.js TypeScript check with Node 24.
  • Regenerated the frontend taxonomy JSON with the repository generator and verified it parses.
  • Ran changed-file Prettier and git diff --check.

I did not run a full PostHog stack or a full production build. The change is covered at the calculation, extraction, validation, and processAiEvent boundaries.

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

Updated the AI generation event reference with the TTL-specific count fields, complete-pair fallback rule, aggregate invariant, and custom-price precedence. Registered the fields in the event taxonomy.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

I directed the fix and used Codex for implementation, tests, validation, and review. The repository's /writing-tests skill shaped the regression-first test contract. No public session link is available.

The implementation stays in the existing ingestion pipeline and continues using the existing model catalog. It derives the 1-hour rate from the resolved prompt price, preserves aggregate-only events, and leaves SDK-specific propagation as follow-up work.

Companion Python SDK work

PostHog/posthog-python#746 preserves the TTL breakdown across supported Python integrations. It is intentionally a draft until this server contract merges. The SDK gap is tracked in PostHog/posthog-python#745.

@richardsolomou richardsolomou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the contribution! Could we add one TTL-breakdown case using numeric strings? The validator accepts them, but the pricing-path tests only use numbers, so a regression in hasNumericProperty could silently fall back to aggregate pricing.

@gouveags

gouveags commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@richardsolomou Thanks for catching this. I added a numeric-string TTL breakdown case in aa11d718e5 and verified that it still prices the 5-minute and 1-hour counts separately instead of falling back to the aggregate. Does that cover the regression you had in mind?

Comment thread nodejs/src/ingestion/pipelines/ai/costs/modality-tokens.ts
@gouveags
gouveags requested a review from richardsolomou July 20, 2026 14:12
@gouveags

Copy link
Copy Markdown
Contributor Author

@richardsolomou Your last review prompted me to take another close pass over the provider payloads, and I noticed we weren't covering Vercel's Amazon Bedrock cacheDetails shape.

I've added support for its 5-minute and 1-hour TTL buckets under both amazonBedrock and the legacy bedrock alias. When both aliases are present we read the canonical one once, and sparse responses fill the missing bucket with zero so pricing doesn't fall back to the aggregate. The extractor and processAiEvent tests now cover the aliases, sparse responses, and end-to-end mixed-TTL pricing.

Let me know if you'd like me to cover anything else.

@richardsolomou richardsolomou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we also cover rawUsage.providerMetadata.amazonBedrock? That supported nested path currently has no regression test.

@gouveags

gouveags commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

I added the missing rawUsage.providerMetadata.amazonBedrock case with both 5-minute and 1-hour cacheDetails entries. It verifies that both TTL buckets are extracted before $ai_usage is removed, and the focused extractor suite passes.

@gouveags

gouveags commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

@richardsolomou Thanks again for the reviews. It seems like the remaining step is for you or another maintainer to approve the check workflows so the required pipeline can run, and then merge if everything passes.

I also opened the companion draft PR PostHog/posthog-python#746. I have been running into this exact issue in our application, and we need both the ingestion and Python SDK sides covered so the same reporting bugs do not continue through that path. We use PostHog to track our users' LLM usage and inform product and business decisions, so accurate cost data is important to us. If there is someone on the Python SDK or LLM analytics side I should coordinate with, I would really appreciate a pointer.

Please let me know if there is anything else you have in mind or any other way I can help.

Thanks for the whole review process and for the chance of contributing!

@carlos-marchal-ph
carlos-marchal-ph removed the request for review from a team July 22, 2026 15:40
@richardsolomou

Copy link
Copy Markdown
Member

@gouveags Ran CI, couple small issues to sort out then should be good to go

@gouveags

gouveags commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@richardsolomou No worries! It looks like I can’t do much from my side, so I’ll wait for the checks to be rerun. Thanks again for all the help!

@gouveags

Copy link
Copy Markdown
Contributor Author

@richardsolomou this seems finally ready to be merged

@richardsolomou

Copy link
Copy Markdown
Member

@gouveags Last thing, our repository only accepts verified commits. Could you verify your commits and update the branch? GitHub’s guide here.

@gouveags
gouveags force-pushed the fix/anthropic-cache-ttl-pricing branch from 337a032 to db5b57d Compare July 28, 2026 12:24
@gouveags

gouveags commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@richardsolomou I didn't know that all commits were required to be verified, really sorry. I'll keep this in mind for future contributions. I've fixed the branch history. Can you check again?

@richardsolomou
richardsolomou merged commit d573c7b into PostHog:master Jul 28, 2026
267 checks passed
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 28, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-28 13:47 UTC Run
prod-us ✅ Deployed 2026-07-28 14:53 UTC Run
prod-eu ✅ Deployed 2026-07-28 14:29 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Anthropic 1-hour prompt-cache writes use the 5-minute rate in auto-costing

2 participants