# How Token Savings Estimates Are Calculated in Code-Review-Graph Using context_savings Metadata

> Discover how code-review-graph estimates token savings using context_savings metadata. Learn the efficient calculation method comparing full code to graph contexts and its benefits.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-22

---

**Code-review-graph calculates token savings by comparing the estimated token count of full source code against the compact graph-based context, using a conservative 4-character-per-token approximation implemented in [`context_savings.py`](https://github.com/tirth8205/code-review-graph/blob/main/context_savings.py).**

The `code-review-graph` repository optimizes LLM interactions by replacing full source code uploads with compact graph representations. To quantify this optimization, the system calculates **token savings estimates** using the `context_savings` metadata block. This lightweight calculation helps developers understand exactly how many tokens they avoid sending to the LLM by leveraging the graph-based context.

## The Token Estimation Algorithm

### Character-Based Approximation

The foundation of the estimation lies in `estimate_tokens()` within [`code_review_graph/context_savings.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/context_savings.py) (lines 16-32). This function uses a conservative approximation of **4 characters per token** (`CHARS_PER_TOKEN = 4`), which aligns with general LLM tokenizer behavior without requiring model-specific dependencies.

When the input `value` is a string, the function calculates `max(1, (len(text) + 3) // 4)` to ensure at least one token is counted even for short strings.

### Handling Complex Objects

For non-string Python objects such as dictionaries or lists, the function serializes the value using `json.dumps(..., separators=(",", ":"))` before applying the character-to-token division. This approach provides a consistent baseline token count for any payload structure without manual string conversion.

## Computing Context Savings with estimate_context_savings

The `estimate_context_savings()` function (lines 54-82 in [`code_review_graph/context_savings.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/context_savings.py)) performs the core comparison between baseline and returned contexts. It accepts either pre-calculated token counts (`original_tokens`, `returned_tokens`) or raw context objects (`original_context`, `returned_context`) that it processes via `estimate_tokens()`.

The calculation follows these steps:

1. Establish the **baseline** from `original_tokens` or derive it from `original_context`
2. Determine the **returned** count from `returned_tokens` or `returned_context`
3. If baseline ≤ 0, return `None`
4. Calculate **saved tokens**: `max(0, baseline - returned)`
5. Calculate **saved percentage**: `round((saved / baseline) * 100)`

The function returns a dictionary containing:

```json
{
  "estimated": true,
  "saved_tokens": <int>,
  "saved_percent": <int>
}

```

## Attaching Metadata to Tool Responses

The `attach_context_savings()` function (lines 85-101) integrates the savings calculation into every tool response. It accepts the same parameters as `estimate_context_savings()` and injects the result under the `"context_savings"` key within the response dictionary. This automatic attachment ensures that CLI commands like `code-review-graph run` include savings data without manual intervention.

## Formatting Savings for Display

### One-Line Summaries

The `format_context_savings()` helper produces concise outputs such as `Estimated context saved: ~1,235 tokens (~68%)`, ideal for logging and terse reporting.

### Detailed Panels

For terminal output, `format_context_savings_panel()` (lines 105-173) generates a boxed multi-line display showing the full context token count, graph context token count, absolute and percentage savings, and optional category breakdowns.

## Optional Tiktoken Verification

When the `tiktoken` library is available, `verify_with_tiktoken()` (lines 151-199) provides model-accurate token counts using the `cl100k_base` encoding (used by GPT-4 and GPT-3.5-turbo). This bypasses the 4-character approximation and returns verified baseline, returned, and saved counts that `format_context_savings_panel()` can display alongside estimates.

## Implementation Example

```python
from code_review_graph.context_savings import (
    estimate_context_savings,
    attach_context_savings,
    format_context_savings_panel
)

# Simulate original payload vs graph representation

original = {"file": "large_source.py", "content": "..." * 2000}
returned = {"graph": {"nodes": 42}}

# Method 1: Direct estimation

savings = estimate_context_savings(
    original_context=original,
    returned_context=returned
)

# Result: {'estimated': True, 'saved_tokens': 450, 'saved_percent': 68}

# Method 2: Automatic attachment to response

response = {"changed_functions": ["foo"], "test_gaps": []}
response = attach_context_savings(
    response,
    original_context=original
)

# Display formatted panel

print(format_context_savings_panel(response["context_savings"], response=response))

```

## Summary

- Token estimation uses a **4-character-per-token approximation** in `estimate_tokens()` within [`code_review_graph/context_savings.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/context_savings.py)
- **Savings are calculated** as `max(0, baseline - returned)` with percentage rounding in `estimate_context_savings()`
- The `context_savings` metadata dictionary attaches automatically via `attach_context_savings()` to all tool responses
- **Optional `tiktoken` verification** using `cl100k_base` provides model-accurate counts when available
- Formatting helpers render both one-line summaries and detailed boxed panels for CLI display

## Frequently Asked Questions

### How accurate is the 4-character token estimation?

The conservative 4-character approximation matches general LLM tokenizer behavior for English text and code, though actual token counts vary by model. For production-grade accuracy, enable the optional `tiktoken` verification which uses the official `cl100k_base` encoding.

### Can I use my own tokenizer instead of the default estimation?

The codebase supports `tiktoken` via `verify_with_tiktoken()`, but custom tokenizers require modifying `estimate_tokens()` in [`code_review_graph/context_savings.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/context_savings.py). The architecture accepts pre-calculated token counts via the `original_tokens` and `returned_tokens` parameters, allowing you to bypass the built-in estimator entirely.

### Why does the function return None when the baseline is zero or negative?

`estimate_context_savings()` returns `None` when `original_tokens` ≤ 0 because savings calculation requires a valid positive baseline. This guard clause prevents division-by-zero errors in percentage calculations and indicates that no meaningful comparison can be performed.

### Where is the context_savings metadata displayed in the CLI?

The CLI entry point in [`code_review_graph/cli.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/cli.py) calls `format_context_savings_panel()` to render the boxed summary after change detection completes. This appears in the terminal output following the `code-review-graph run` command, showing users exactly how many tokens the graph representation saved compared to uploading full source files.