Skip to content

feat: support Claude Code native context_window API#71

Merged
Haleclipse merged 2 commits intoHaleclipse:masterfrom
Gyv12345:feat/context-window-api-support
Jan 23, 2026
Merged

feat: support Claude Code native context_window API#71
Haleclipse merged 2 commits intoHaleclipse:masterfrom
Gyv12345:feat/context-window-api-support

Conversation

@Gyv12345
Copy link
Contributor

@Gyv12345 Gyv12345 commented Jan 21, 2026

  • Add ContextWindow struct to support native Claude Code v2.0.37+ context window data
  • Prioritize native context_window field for accurate token usage
  • Maintain backward compatibility with transcript parsing fallback
  • Add session history search as additional fallback mechanism
  • Improve percentage calculation and token display formatting

Summary by Sourcery

Support native context window metadata from Claude Code while preserving existing transcript-based fallbacks for token usage display.

New Features:

  • Introduce a ContextWindow and CurrentContextUsage schema on InputData to consume native context window data from Claude Code.

Enhancements:

  • Prioritize native context window size and usage for computing context limits and usage percentages, with improved percentage and token display formatting.
  • Add session history search as an additional fallback when deriving token usage from transcripts.

- Add ContextWindow struct to support native Claude Code v2.0.37+ context window data
- Prioritize native context_window field for accurate token usage
- Maintain backward compatibility with transcript parsing fallback
- Add session history search as additional fallback mechanism
- Improve percentage calculation and token display formatting

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@sourcery-ai
Copy link

sourcery-ai bot commented Jan 21, 2026

Reviewer's Guide

Implements native Claude Code context_window support by introducing a ContextWindow struct, preferring native usage data when available, and adding layered fallbacks plus improved percentage and token formatting in the context window segment.

Sequence diagram for context usage resolution with native context_window and fallbacks

sequenceDiagram
    participant Caller
    participant ContextWindowSegment
    participant InputData
    participant ContextWindow
    participant ModelConfig
    participant TranscriptParser
    participant SessionHistory

    Caller->>ContextWindowSegment: collect(input)
    activate ContextWindowSegment

    ContextWindowSegment->>InputData: read context_window
    InputData-->>ContextWindowSegment: ContextWindow
    ContextWindowSegment->>ContextWindow: context_window_size
    ContextWindow-->>ContextWindowSegment: Option context_window_size

    alt context_window_size is Some
        ContextWindowSegment-->>ContextWindowSegment: context_limit = context_window_size
    else context_window_size is None
        ContextWindowSegment->>InputData: read model.id
        ContextWindowSegment->>ModelConfig: get_context_limit(model_id)
        ModelConfig-->>ContextWindowSegment: context_limit
    end

    ContextWindowSegment->>ContextWindow: get_display_percentage()
    ContextWindow-->>ContextWindowSegment: Option percentage

    alt percentage is Some
        ContextWindowSegment->>ContextWindow: total_tokens()
        ContextWindow-->>ContextWindowSegment: Option total_tokens
        ContextWindowSegment-->>Caller: SegmentData with native percentage and tokens
    else percentage is None
        ContextWindowSegment-->>ContextWindowSegment: get_context_usage_with_fallback(input)
        activate TranscriptParser
        ContextWindowSegment->>ContextWindow: is_available()
        ContextWindow-->>ContextWindowSegment: bool

        alt ContextWindow is available
            ContextWindowSegment->>ContextWindow: total_tokens()
            ContextWindow-->>ContextWindowSegment: Option total_tokens
            ContextWindowSegment-->>ContextWindowSegment: compute percentage from tokens and context_limit
        else ContextWindow not available
            ContextWindowSegment->>TranscriptParser: parse_transcript_usage(transcript_path)
            TranscriptParser-->>ContextWindowSegment: Option usage

            alt usage is None
                deactivate TranscriptParser
                activate SessionHistory
                ContextWindowSegment->>SessionHistory: try_get_from_session_history(transcript_path)
                SessionHistory-->>ContextWindowSegment: Option usage
                deactivate SessionHistory
            end
        end

        alt usage is Some
            ContextWindowSegment-->>ContextWindowSegment: format percentage and tokens
            ContextWindowSegment-->>Caller: SegmentData with fallback percentage and tokens
        else usage is None
            ContextWindowSegment-->>Caller: SegmentData with "-" for percentage and tokens
        end
        deactivate ContextWindowSegment
    end
Loading

Class diagram for new ContextWindow and InputData structures

classDiagram
    class InputData {
        +Model model
        +String transcript_path
        +Option~Cost~ cost
        +Option~OutputStyle~ output_style
        +ContextWindow context_window
    }

    class ContextWindow {
        +Option~u32~ total_input_tokens
        +Option~u32~ total_output_tokens
        +Option~u32~ context_window_size
        +Option~f64~ used_percentage
        +Option~f64~ remaining_percentage
        +Option~CurrentContextUsage~ current_usage
        +total_tokens() Option~u32~
        +is_available() bool
        +get_display_percentage() Option~f64~
    }

    class CurrentContextUsage {
        +Option~u32~ input_tokens
        +Option~u32~ output_tokens
        +Option~u32~ cache_creation_input_tokens
        +Option~u32~ cache_read_input_tokens
    }

    InputData --> ContextWindow : has
    ContextWindow --> CurrentContextUsage : has
Loading

Class diagram for updated ContextWindowSegment behavior

classDiagram
    class ContextWindowSegment {
        +new() ContextWindowSegment
        -get_context_limit_for_model(model_id: &str) u32
        -get_context_usage_with_fallback(input: &InputData) Option~u32~
        -try_get_from_session_history(transcript_path: &str) Option~u32~
        +collect(input: &InputData) Option~SegmentData~
    }

    class InputData {
        +Model model
        +String transcript_path
        +ContextWindow context_window
    }

    class ContextWindow {
        +Option~u32~ context_window_size
        +total_tokens() Option~u32~
        +is_available() bool
        +get_display_percentage() Option~f64~
    }

    class Model {
        +String id
    }

    class SegmentData

    ContextWindowSegment ..> InputData : reads
    ContextWindowSegment ..> ContextWindow : reads
    ContextWindowSegment ..> Model : reads
    ContextWindowSegment ..> SegmentData : returns
Loading

File-Level Changes

Change Details Files
Add ContextWindow and CurrentContextUsage types and wire them into InputData for native Claude Code context window support.
  • Introduce ContextWindow and CurrentContextUsage structs with serde-deserializable optional fields for input/output tokens, window size, and percentage values.
  • Implement helper methods on ContextWindow to compute total tokens, check availability, and derive display percentage when only tokens and size are known.
  • Extend InputData to include a context_window field with a default value for backward compatibility.
src/config/types.rs
Refactor ContextWindowSegment to prioritize native context_window data and provide layered fallbacks for usage and improved display formatting.
  • Add get_context_usage_with_fallback that first uses native context_window totals, then transcript parsing, then session history search.
  • Add try_get_from_session_history helper that scans recent .jsonl session files by mtime and reuses transcript parsing to recover usage.
  • Change collect implementation to use context_window for context_limit and percentage when available, with formatting rounded to 0 or 1 decimal place and k-suffix for large token counts.
  • Update metadata population to prefer native context_window values, then fallback usage, with consistent percentage and token strings and always include context limit and model id.
src/core/segments/context_window.rs
Tidy transcript parsing utilities while keeping backward-compatible behavior for usage extraction from transcript and project history.
  • Preserve parse_transcript_usage, try_parse_transcript_file, find_usage_by_leaf_uuid, search_uuid_in_file, and try_find_usage_from_project_history logic but remove redundant comments and rely on new higher-level fallback orchestration.
  • Ensure project history search still sorts session files by modification time descending and inspects the most recent sessions for usage data.
src/core/segments/context_window.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • The new try_get_from_session_history logic overlaps heavily with try_find_usage_from_project_history; consider refactoring shared behaviors (directory scan, sort, recent-file iteration) into a common helper to avoid duplication and keep the fallback behavior consistent.
  • In the metadata population, context_window.total_tokens().unwrap_or(0) will report 0 tokens when no token data is available, while the display shows -; consider aligning this by using "-" instead of 0 to avoid misleading zero-usage metadata.
  • The ContextWindow::get_display_percentage fallback uses a hard-coded default limit of 200000 when context_window_size is missing; it may be safer to derive this from the model configuration (or avoid computing a percentage) to prevent incorrect usage ratios for models with different limits.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `try_get_from_session_history` logic overlaps heavily with `try_find_usage_from_project_history`; consider refactoring shared behaviors (directory scan, sort, recent-file iteration) into a common helper to avoid duplication and keep the fallback behavior consistent.
- In the metadata population, `context_window.total_tokens().unwrap_or(0)` will report `0` tokens when no token data is available, while the display shows `-`; consider aligning this by using `"-"` instead of `0` to avoid misleading zero-usage metadata.
- The `ContextWindow::get_display_percentage` fallback uses a hard-coded default limit of `200000` when `context_window_size` is missing; it may be safer to derive this from the model configuration (or avoid computing a percentage) to prevent incorrect usage ratios for models with different limits.

## Individual Comments

### Comment 1
<location> `src/config/types.rs:170-171` </location>
<code_context>
+        if let Some(percentage) = self.used_percentage {
+            Some(percentage)
+        } else if self.is_available() {
+            self.total_tokens().map(|tokens| {
+                let limit = self.context_window_size.unwrap_or(200000);
+                (tokens as f64 / limit as f64) * 100.0
+            })
</code_context>

<issue_to_address>
**issue (bug_risk):** Avoid hardcoded 200_000 and align percentage calculation with the actual context limit used elsewhere.

Here this falls back to a hardcoded `200_000` when `context_window_size` is `None`, but `ContextWindowSegment::collect` instead derives the limit from the model config. That can yield inconsistent percentages versus the metadata and `limit` field. Prefer wiring the effective limit into `get_display_percentage`, or removing the `200_000` default and reusing the segment’s limit logic so there is a single source of truth.
</issue_to_address>

### Comment 2
<location> `src/core/segments/context_window.rs:138-142` </location>
<code_context>
-                metadata.insert("percentage".to_string(), "-".to_string());
-            }
+
+        if let Some(percentage_val) = context_window.get_display_percentage() {
+            metadata.insert("percentage".to_string(), percentage_val.to_string());
+            metadata.insert(
+                "tokens".to_string(),
+                context_window.total_tokens().unwrap_or(0).to_string(),
+            );
+        } else if let Some(context_used_token) = Self::get_context_usage_with_fallback(input) {
</code_context>

<issue_to_address>
**issue (bug_risk):** Using `0` as a fallback token count may be misleading when the token total is unknown.

When `get_display_percentage()` is `Some` but `total_tokens()` is `None`, this stores `tokens = "0"`, which suggests zero tokens instead of “unknown”. Consider omitting `tokens`, using a placeholder like `"-"`, or matching the display fallback so metadata consumers don’t misread missing totals as zero usage.
</issue_to_address>

### Comment 3
<location> `src/config/types.rs:149-157` </location>
<code_context>
+}
+
+impl ContextWindow {
+    pub fn total_tokens(&self) -> Option<u32> {
+        match (self.total_input_tokens, self.total_output_tokens) {
+            (Some(input), Some(output)) => Some(input + output),
+            (Some(input), None) => Some(input),
+            (None, Some(output)) => Some(output),
+            (None, None) => None,
+        }
+    }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Consider using a saturating or wider integer type when summing token counts.

`input + output` in `u32` can overflow (panic in debug, wrap in release). Even if current counts are unlikely to reach `u32::MAX`, using `u64` for the sum or `input.saturating_add(output)` would avoid hidden overflow issues if limits increase later.

```suggestion
impl ContextWindow {
    pub fn total_tokens(&self) -> Option<u32> {
        match (self.total_input_tokens, self.total_output_tokens) {
            (Some(input), Some(output)) => Some(input.saturating_add(output)),
            (Some(input), None) => Some(input),
            (None, Some(output)) => Some(output),
            (None, None) => None,
        }
    }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

- Fix u32 overflow potential by using saturating_add in ContextWindow::total_tokens
- Remove hardcoded 200000 limit, pass actual context_limit to get_display_percentage
- Fix metadata consistency: use "-" instead of "0" when token count is unknown
- Refactor duplicated logic: extract search_recent_session_files helper to unify session history and project history searching
- Improve code maintainability with single source of truth for context limit calculation

Changes:
- types.rs: Add context_limit parameter to get_display_percentage, use saturating_add
- context_window.rs: Refactor session search logic, fix metadata tokens display, align percentage calculation

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@Haleclipse
Copy link
Owner

Haleclipse commented Jan 21, 2026

有人提过 也早考虑过跟进
但是之前有实现 模型名和对应上下文窗口值的覆盖 功能
如果直接抄收使用 2.1.6 追加的百分比值
该覆盖功能会直接失效


所以也许应该需要再附加一段逻辑 当模型id匹配成功被覆盖时 fallback 到 旧时的计算

@Haleclipse Haleclipse merged commit bd88e9d into Haleclipse:master Jan 23, 2026
1 check passed
Haleclipse added a commit that referenced this pull request Jan 25, 2026
Revert changes from bd88e9d to restore original context window logic.
The native API approach needs further refinement.
Haleclipse pushed a commit that referenced this pull request Jan 25, 2026
* feat: support Claude Code native context_window API

- Add ContextWindow struct to support native Claude Code v2.0.37+ context window data
- Prioritize native context_window field for accurate token usage
- Maintain backward compatibility with transcript parsing fallback
- Add session history search as additional fallback mechanism
- Improve percentage calculation and token display formatting


* fix: address code review feedback

- Fix u32 overflow potential by using saturating_add in ContextWindow::total_tokens
- Remove hardcoded 200000 limit, pass actual context_limit to get_display_percentage
- Fix metadata consistency: use "-" instead of "0" when token count is unknown
- Refactor duplicated logic: extract search_recent_session_files helper to unify session history and project history searching
- Improve code maintainability with single source of truth for context limit calculation

Changes:
- types.rs: Add context_limit parameter to get_display_percentage, use saturating_add
- context_window.rs: Refactor session search logic, fix metadata tokens display, align percentage calculation


---------
Haleclipse added a commit that referenced this pull request Jan 25, 2026
Revert changes from bd88e9d to restore original context window logic.
The native API approach needs further refinement.
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.

2 participants