Skip to content

feat(traces): Show cached prompt tokens in token breakdowns#5352

Draft
ashrafchowdury wants to merge 3 commits into
mainfrom
fix/agent-token-usage-related-issues
Draft

feat(traces): Show cached prompt tokens in token breakdowns#5352
ashrafchowdury wants to merge 3 commits into
mainfrom
fix/agent-token-usage-related-issues

Conversation

@ashrafchowdury

Copy link
Copy Markdown
Contributor

Context

Sending "hi" to an agent in the playground showed "Total 15.0K / Prompt 3 / Completion 14". The total is real (the agent harness sends its system prompt and tool schemas on every model call), but the breakdown was misleading: providers report cached prompt tokens separately from the regular input count, and we dropped that split everywhere. So Prompt + Completion never added up to Total. The trace drawer had the same problem.

Changes

The cache split (cache read / cache write) now flows end to end, and both token tooltips fold it into the displayed prompt count so the numbers add up.

  • Runner: run usage now accumulates cacheRead/cacheWrite from the harness, stamps them on the agent span as gen_ai.usage.cache_read.input_tokens / gen_ai.usage.cache_creation.input_tokens, and carries them on the wire. AgentUsage.input keeps its harness semantics (non-cached tokens only); the cached portion travels in the new optional fields.
  • Wire contract: AgentUsage (TS) and WireAgentUsage (Python) gained optional cacheRead/cacheWrite. Golden fixtures and both contract tests updated.
  • Python SDK: the vercel stream adapter forwards the fields in message metadata, and tracing stamps the same span attributes.
  • Playground tooltip and trace drawer: displayed Prompt folds the cached tokens back in, with dimmed "Cached (read)" / "Cached (write)" sub-rows underneath. The drawer reads ag.metrics.tokens.*.cache_read / cache_creation, which the logfire OTLP adapter already ingests.
  • Backend rollup: cumulate_tokens in trees.py now propagates the cache keys up the span tree alongside prompt/completion/total. Cache keys are written only when non-zero, so stored attributes for non-cache traces are unchanged.

With real numbers from a local run:

Before: Total 32.8K / Prompt 6 / Completion 115
After: Total 32.8K / Prompt 32.7K / Cached (read) 14.9K / Cached (write) 17.7K / Completion 115

No DB migration. Span attributes are a JSONB blob; this only adds keys inside it. Old traces render as before.

Tests

  • Runner: typecheck clean, 1158 vitest tests pass (wire-contract goldens updated).
  • Python SDK: 660 agent tests pass, ruff clean.
  • API: new unit test for cache propagation in cumulate_tokens (11 pass in test_trees.py).
  • Verified end to end on a local EE stack against a DeepSeek run with real cache hits, in both the playground tooltip and the trace drawer.

What to QA

  • Playground: chat with an agent twice in the same session, hover the token count on the second reply. Prompt + Completion equals Total, with dimmed Cached (read)/(write) rows under Prompt.
  • Trace drawer: open that run's trace, select the invoke_agent span, hover Tokens & Cost. Same breakdown as the playground.
  • Regression: open a trace ingested before this deploy. The tooltip shows Prompt/Completion as before with no cache rows.

Preview

Before:

No way to understand where the 15l tokens costs
image

After:

Showing the correct token costs + the cached token
image

Trace drawer

image

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 16, 2026
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 16, 2026 1:38pm

Request Review

@dosubot dosubot Bot added the enhancement New feature or request label Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a5ebac47-4fbc-4f8c-83e2-484d1a05fe56

📥 Commits

Reviewing files that changed from the base of the PR and between 650d4ed and c2b6c4e.

📒 Files selected for processing (15)
  • api/oss/src/core/tracing/utils/trees.py
  • api/oss/tests/pytest/unit/tracing/utils/test_trees.py
  • sdks/python/agenta/sdk/agents/adapters/vercel/stream.py
  • sdks/python/agenta/sdk/agents/tracing.py
  • sdks/python/agenta/sdk/agents/wire_models.py
  • sdks/python/oss/tests/pytest/unit/agents/golden/run_result.ok.json
  • sdks/python/oss/tests/pytest/unit/agents/test_wire_contract.py
  • services/runner/src/engines/sandbox_agent/usage.ts
  • services/runner/src/protocol.ts
  • services/runner/src/tracing/otel.ts
  • services/runner/tests/unit/wire-contract.test.ts
  • web/oss/src/components/AgentChatSlice/assets/trace.ts
  • web/oss/src/components/SharedDrawers/TraceDrawer/components/TraceSidePanel/TraceDetails/index.tsx
  • web/oss/src/state/newObservability/selectors/tracing.ts
  • web/packages/agenta-ui/src/components/presentational/metrics/ExecutionMetricsDisplay.tsx

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for reporting cached prompt tokens, including separate read and write counts.
    • Token totals now include cached usage while preserving the cache breakdown.
    • Trace details and execution metrics display cached read/write token values when available.
    • Usage events and run results now expose cache usage fields.
  • Bug Fixes

    • Improved token propagation and usage aggregation across spans and streamed responses.
    • Updated usage reporting to consistently match supported wire-format fields.

Walkthrough

Cache read/write token counts are added to agent usage contracts, aggregation, OpenTelemetry attributes, cumulative tracing, SDK wire serialization, and web token displays. Prompt totals now include cached tokens while cache read/write values remain separately available.

Changes

Cache-aware token accounting

Layer / File(s) Summary
Usage contracts and runner aggregation
services/runner/src/protocol.ts, services/runner/src/engines/sandbox_agent/usage.ts, services/runner/src/tracing/otel.ts, services/runner/tests/unit/wire-contract.test.ts
Runner usage types, aggregation, tracing attributes, and contract expectations now include cache read/write counts and cache-inclusive totals.
SDK wire usage propagation
sdks/python/agenta/sdk/agents/wire_models.py, sdks/python/agenta/sdk/agents/adapters/vercel/stream.py, sdks/python/agenta/sdk/agents/tracing.py, sdks/python/oss/tests/pytest/unit/agents/*
Python wire usage models and metadata extraction expose cache fields, record them in tracing, and update fixtures and parsing assertions.
Cumulative token propagation
api/oss/src/core/tracing/utils/trees.py, api/oss/tests/pytest/unit/tracing/utils/test_trees.py
Token accumulation generalizes across prompt, completion, total, and cache metrics, with cache propagation covered by a unit test.
Web token metrics and displays
web/oss/src/components/AgentChatSlice/assets/trace.ts, web/oss/src/state/newObservability/selectors/tracing.ts, web/oss/src/components/SharedDrawers/.../TraceDetails/index.tsx, web/packages/agenta-ui/.../ExecutionMetricsDisplay.tsx
Prompt totals fold cached tokens into the displayed count while trace and execution metric views render separate cache read/write rows when present.

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

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant RunnerUsage
  participant OpenTelemetry
  participant TraceSelectors
  participant TraceDetails
  Agent->>RunnerUsage: Emit input/output/cacheRead/cacheWrite usage
  RunnerUsage->>OpenTelemetry: Aggregate usage and stamp gen_ai.usage attributes
  OpenTelemetry->>TraceSelectors: Expose cumulative token metrics
  TraceSelectors->>TraceDetails: Provide formatted cache token values
  TraceDetails->>TraceDetails: Render cache read/write token rows
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 60.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 clearly summarizes the main change: showing cached prompt tokens in token breakdowns.
Description check ✅ Passed The description accurately explains the cached-token flow and UI changes, and is clearly related to the diff.
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 fix/agent-token-usage-related-issues

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ashrafchowdury

Copy link
Copy Markdown
Contributor Author

I had faced this issue several times, where I wanted to see how much that amount of token costs, in which part, where and how. The token usage detail popover was misleading

@ashrafchowdury
ashrafchowdury requested a review from mmabrouk July 16, 2026 13:40
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Status Destroyed (PR converted to draft)

Updated at 2026-07-17T07:44:24.763Z

mmabrouk commented Jul 16, 2026

Copy link
Copy Markdown
Member

Hey @ashrafchowdury

This is a great idea, and the user-facing problem is real. Showing cached-token usage makes the numbers much easier to understand. However, this implementation does not fit the current plan for usage and cost telemetry. We already have a broader design in #5253 that covers the runner contract, cache semantics, cost provenance, trace attribution, and rollups.

As a general rule, changes to interfaces inside the system should start with a discussion and design sync before implementation. The boundaries do not all have the same stability or freedom to change.

We currently have more freedom at the service-to-runner boundary. That part of the system is new, still somewhat ad hoc, and has not yet been fully refactored or organized. Quick changes there can be acceptable to some degree, especially when they clarify ownership and move the design toward a cleaner structure.

Changes in the other direction, especially from the runner back through the service, API, tracing semantics, storage rollups, and UI, need much more thought. The main platform has already been designed, refactored, and organized around stable semantic conventions. A quick interface change there can create inconsistent meanings, duplicate sources of truth, or hidden compatibility problems. Even when the local change looks small, it may make the wider system harder to reason about.

For example, #5253 treats input tokens as an inclusive total and cache-read/cache-creation tokens as subcategories. This PR keeps input as non-cached and makes the cache fields additive siblings. Both can make the tooltip add up, but they define different contracts. We should agree on the contract before wiring one shape through the runner, SDK, tracing pipeline, API rollups, and frontend.

The goal should be to reduce entropy with each change: make responsibilities clearer, preserve standard meanings, remove ambiguity, and leave fewer special cases behind. We should avoid changes that solve one visible symptom by adding more uncertainty to the underlying interfaces.

I also recommend using the coding agent as a design partner before implementation. Ask it questions such as: “What are the best practices here?”, “What would a staff engineer do?”, “Who should own this field?”, “Is there an existing standard?”, and “How can this change reduce complexity across the whole system?” These conversations are useful for learning what a good design looks like, not just for producing code faster.

The idea is valuable. I suggest aligning it with #5253 first, agreeing on the canonical usage shape and attribution rules, and then adapting this implementation to that design.

@mmabrouk mmabrouk 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.

see comment

@ashrafchowdury
ashrafchowdury marked this pull request as draft July 17, 2026 07:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants