Skip to content

fix: calculate context fullness from last response usage - #24

Merged
serialx merged 2 commits into
mainfrom
codex/fix-context_fullness-calculation-in-main.py
Oct 14, 2025
Merged

serialx merged 2 commits into
mainfrom
codex/fix-context_fullness-calculation-in-main.py

Conversation

@serialx

@serialx serialx commented Oct 14, 2025

Copy link
Copy Markdown
Owner

Summary

  • compute the context usage indicator using the usage data from the final model response instead of aggregated totals
  • fall back to aggregated usage data when per-response usage is unavailable

Testing

  • not run (not requested)

https://chatgpt.com/codex/tasks/task_e_68ee00ac98fc832a98b4e69ce8fc6b58

@claude

claude Bot commented Oct 14, 2025 •

Copy link
Copy Markdown
Contributor

Claude finished @serialx's task —— View job


Code Review for PR #24

I've reviewed the changes to fix context fullness calculation in src/vibecore/main.py. Here's my analysis:

Todo List

  • Read and analyze the changes in src/vibecore/main.py
  • Review for code quality and best practices
  • Check for potential bugs or issues
  • Assess performance considerations
  • Evaluate security concerns
  • Review test coverage requirements

Review Feedback

✅ Code Quality and Best Practices

  • The refactoring improves code clarity with descriptive variable names (used_tokens vs used)
  • Good use of defensive programming with explicit type hints (float | None)
  • Excellent comments explaining the rationale for the change
  • Proper fallback logic when per-response usage is unavailable

✅ Correctness of the Fix

The change correctly addresses the issue where context usage was calculated from aggregated session totals. The new approach:

  1. Tries to get usage from the last model response first
  2. Falls back to aggregated totals if unavailable
  3. This ensures the context fullness indicator reflects the most recent request's actual context usage

⚠️ Potential Issues

  1. Type Safety Concern: Using getattr() without proper type checking

    last_usage = getattr(last_response, "usage", None)

    Consider checking if last_response has the expected type before using getattr(), or using type-safe property access if the response type is known.

  2. Missing Error Handling: The code assumes last_usage.total_tokens exists if last_usage is truthy. Consider adding a try-except or additional checks:

    if last_usage and hasattr(last_usage, 'total_tokens'):
        used_tokens = float(last_usage.total_tokens)

✅ Performance Considerations

  • The change is performance-neutral - it accesses already available data
  • No additional API calls or expensive computations introduced
  • The fallback mechanism ensures no performance regression

✅ Security Concerns

  • No security implications identified
  • No external data access or user input handling in this change

❌ Test Coverage

Missing Tests: No tests exist for the context usage calculation functionality. Consider adding:

  1. Unit tests for handle_streamed_response method
  2. Tests for both scenarios: when raw_responses is available and when fallback is needed
  3. Test edge cases: empty responses, missing usage data
  4. Integration test to verify the context progress bar updates correctly

💡 Additional Suggestions

  1. TODO Resolution: The _get_model_context_window() method returns a hardcoded value (200000) with a TODO comment. This should be addressed to get actual model context limits.

  2. Consider Extracting Logic: The usage calculation logic could be extracted to a separate method for better testability:

    def _get_context_usage(self, result: RunResultStreaming) -> float:
        """Calculate context usage from streaming result."""
        # Implementation here
  3. Logging Enhancement: Consider adding debug logging when falling back to aggregated usage to help diagnose issues in production.

Summary

The fix correctly addresses the context fullness calculation issue and improves code quality. However, it would benefit from:

  • Better type safety around the getattr usage
  • Test coverage for the new logic
  • Resolution of the TODO for dynamic context window sizing

Overall, this is a good fix that solves the immediate problem. The suggested improvements would make it more robust.

@serialx
serialx force-pushed the codex/fix-context_fullness-calculation-in-main.py branch from 063e1fe to af863dc Compare October 14, 2025 08:00
@claude

claude Bot commented Oct 14, 2025 •

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


PR Review: Context Fullness Calculation Fix

Summary

This PR changes the context usage calculation from using aggregated session totals to deriving it from the last response's usage data. This provides a more accurate representation of the current context fullness.

✅ Positive Changes

  1. More Accurate Context Tracking: Using the last response's usage data provides a better reflection of the actual context window utilization for the current interaction
  2. Clear Comments: The code includes helpful comments explaining why this approach was chosen
  3. Safe Type Handling: Uses getattr() with a default value to safely access the usage attribute
  4. Defensive Programming: Initializes used_tokens to 0.0 as a safe default

⚠️ Issues Found

1. Missing Fallback Logic

The PR description mentions "falling back to aggregated usage if not available", but this fallback is not implemented in the code. Currently, if raw_responses is empty or the last response doesn't have usage data, the context fullness will always be 0.

Suggested Fix:

# Determine usage based on the last model response rather than the aggregated usage
# from the entire session so that context fullness reflects the most recent request.
used_tokens: float = 0.0
if result.raw_responses:
    last_response = result.raw_responses[-1]
    last_usage = getattr(last_response, "usage", None)
    if last_usage and hasattr(last_usage, "total_tokens"):
        used_tokens = float(last_usage.total_tokens)

# Fallback to aggregated usage if last response usage is not available
if used_tokens == 0.0 and result.context_wrapper and result.context_wrapper.usage:
    used_tokens = float(result.context_wrapper.usage.total_tokens)

2. Type Safety Concerns

The use of getattr() without proper type checking could mask attribute access issues. Consider using proper type checking:

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from openai.types.completion_usage import CompletionUsage

# Then in the code:
if result.raw_responses:
    last_response = result.raw_responses[-1]
    if hasattr(last_response, "usage") and last_response.usage:
        usage: CompletionUsage = last_response.usage
        if hasattr(usage, "total_tokens"):
            used_tokens = float(usage.total_tokens)

3. Complete Lack of Test Coverage

There are no tests for this critical functionality. The handle_streamed_response method and context usage calculation have zero test coverage.

Recommended Tests:

  • Test with empty raw_responses list
  • Test with responses lacking usage data
  • Test with valid usage data
  • Test the fallback logic (once implemented)
  • Test boundary conditions (context at 0%, 50%, 100%, >100%)

4. Hard-coded Context Window

The _get_model_context_window() method returns a hard-coded value of 200,000. This should ideally be:

  • Configurable per model
  • Derived from the actual model being used
  • At minimum, documented why 200,000 was chosen

📝 Recommendations

  1. Extract to Testable Method: Consider extracting the usage calculation logic to a separate method for better testability:
def _calculate_context_usage(self, result: RunResultStreaming) -> float:
    """Calculate context token usage from the result."""
    # Implementation here
    return used_tokens
  1. Add Logging for Debugging: Consider adding debug logs when fallback is used or when usage data is unavailable.

  2. Add Integration Test: Create an integration test that verifies the footer progress bar updates correctly with different context usage scenarios.

🔒 Security

No security concerns identified with this change.

⚡ Performance

The change is performance-neutral - accessing the last element of a list is O(1) and the calculation is minimal.

✔️ Verdict

The change is conceptually good and addresses a real issue with context tracking. However, it needs:

  1. Implementation of the fallback logic mentioned in the PR description
  2. Addition of comprehensive test coverage
  3. Better type safety handling

Once these issues are addressed, this will be a solid improvement to the context tracking functionality.

@claude

claude Bot commented Oct 14, 2025 •

Copy link
Copy Markdown
Contributor

Claude finished @serialx's task —— View job


Code Review for PR #24

Todo List

  • Read the changed files (src/vibecore/main.py and pyproject.toml)
  • Analyze code quality and best practices
  • Check for potential bugs or issues
  • Assess performance considerations
  • Evaluate security concerns
  • Review test coverage
  • Provide comprehensive feedback

Review Summary

I've reviewed the changes to fix context fullness calculation. The PR correctly addresses the issue where context usage was showing cumulative session totals instead of the current request's usage.

✅ Code Quality and Best Practices

  • Good refactoring: Improved variable naming (used_tokens vs used) makes the code more readable
  • Clear comments: The new comment explains why the change was made and what it accomplishes
  • Proper type annotation: Used used_tokens: float = 0.0 with explicit type hint
  • Addressed TODO: Successfully resolved the previous XXX comment that marked this as a known issue
  • Clean pyproject.toml update: Added .git to pyright excludes, which is a sensible addition

⚠️ Potential Bugs or Issues

  1. Missing Fallback Logic: The PR description states "fall back to aggregated usage data when per-response usage is unavailable," but the implementation doesn't include this fallback. When raw_responses is empty or usage is None, used_tokens remains 0.0, potentially showing 0% context usage incorrectly.

    Suggested implementation:

    # Determine usage based on the last model response rather than aggregated usage
    used_tokens: float = 0.0
    if result.raw_responses:
        last_response = result.raw_responses[-1]
        last_usage = getattr(last_response, "usage", None)
        if last_usage:
            used_tokens = float(last_usage.total_tokens)
    
    # Fallback to aggregated usage if no per-response data available
    if used_tokens == 0.0 and hasattr(result.context_wrapper, 'usage'):
        if result.context_wrapper.usage:
            used_tokens = float(result.context_wrapper.usage.total_tokens)
  2. Type Safety with getattr: While getattr(last_response, "usage", None) is reasonably safe, adding an extra check would be more defensive:

    if last_usage and hasattr(last_usage, 'total_tokens'):
        used_tokens = float(last_usage.total_tokens)

✅ Performance Considerations

  • The change is performance-neutral, accessing already available data from result.raw_responses
  • No additional API calls or expensive computations
  • Actually slightly more efficient than the previous nested attribute access

✅ Security Concerns

  • No security issues identified
  • Safe attribute access with getattr default value
  • No external data processing or user input handling

❌ Test Coverage

Critical Gap: There are NO tests for the handle_streamed_response method or context usage calculation. This is concerning for a core UI feature that affects user experience.

Recommended tests to add:

  1. Unit tests for handle_streamed_response:

    • Test with valid raw_responses containing usage data
    • Test with empty raw_responses list
    • Test with raw_responses where usage is None
    • Test the fallback scenario (once implemented)
  2. Integration tests to verify:

    • Context progress bar updates correctly with real agent responses
    • Footer displays accurate context percentage

💡 Additional Improvements to Consider

  1. Hardcoded Context Window: The _get_model_context_window() method at line 239 returns a hardcoded value (200000) with a TODO comment. This should be addressed to dynamically determine the actual model's context limit.

  2. Extract Logic for Testability: Consider extracting the usage calculation into a separate method:

    def _calculate_context_usage(self, result: RunResultStreaming) -> float:
        """Calculate context usage from streaming result with fallback."""
        # Implementation here
        return used_tokens
  3. Add Debug Logging: When fallback is used (once implemented), add debug logging to help diagnose issues in production.

Verdict

The fix correctly addresses the core issue, improving how context usage is displayed to users. However, it's incomplete without the fallback logic mentioned in the PR description. The lack of test coverage is also a significant concern that should be addressed before merging.

Recommended actions:

  1. ✅ Implement the fallback logic as described in the PR summary
  2. ✅ Add comprehensive test coverage for this functionality
  3. ✅ Consider the suggested defensive programming improvements
  4. ⭐ Address the TODO for dynamic context window sizing (can be a separate PR)

Overall, this is a good fix that solves the immediate problem, but needs the fallback mechanism and tests to be production-ready.

@serialx
serialx merged commit dc2aec2 into main Oct 14, 2025
3 checks passed
@serialx
serialx deleted the codex/fix-context_fullness-calculation-in-main.py branch October 14, 2025 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant