Skip to content

WebUI context indicator can prefer stale session usage over latest usage on session load #437

@dx47618004

Description

@dx47618004

Summary

On current origin/master (v0.50.36, 37850a4), the WebUI context indicator can prefer stale per-session metadata over fresher usage data, and older session/index entries may also lack the usage fields needed to render the indicator correctly.

In practice this shows up after provider/model changes or after reopening older sessions:

  • the active provider/model is correct
  • the backend is healthy
  • but the UI can still show an old context window (for example 128k) or stale usage values from the stored session object

This is related to stale-session UI state, but distinct from the already-open stale-model issues.

Why this still appears on origin/master

In static/sessions.js on origin/master, loadSession(...) still merges context usage like this:

const _s=S.session;
if(_s&&typeof _syncCtxIndicator==='function'){
  const u=S.lastUsage||{};
  _syncCtxIndicator({
    input_tokens:_s.input_tokens||u.input_tokens||0,
    output_tokens:_s.output_tokens||u.output_tokens||0,
    estimated_cost:_s.estimated_cost||u.estimated_cost,
    context_length:u.context_length||0,
    last_prompt_tokens:u.last_prompt_tokens||0,
    threshold_tokens:u.threshold_tokens||0
  });
}

Problems with this shape:

  1. It mixes session-level and latest-usage fields inconsistently.
  2. It uses ||, so valid falsy values are not preserved correctly.
  3. Older session/index entries may not contain context_length, threshold_tokens, or last_prompt_tokens at all.
  4. There is no single latest-first merge helper for usage payloads.

Reproduction pattern

  1. Use WebUI with provider/model A and create a session.
  2. Switch provider/model (for example to openai-codex / gpt-5.4) or reopen an older session created under a different provider/model path.
  3. Confirm backend state is correct via /api/models.
  4. Load the session in the UI.
  5. Observe that the context indicator can still reflect stale values from the session snapshot rather than the latest usage/model path.

A real observed symptom was an old 128k indicator surviving even after provider/model had been corrected, because the UI merge favored stored session state over fresher usage information.

Expected behavior

When loading a session, the UI should prefer the freshest usage payload over stale session metadata for:

  • input_tokens
  • output_tokens
  • estimated_cost
  • context_length
  • last_prompt_tokens
  • threshold_tokens

Also, session/index compaction should preserve these fields so older session loads do not silently drop them.

Suggested fix

A local patch that resolved this used two pieces:

1. Latest-first usage merge in static/sessions.js

function _pickUsageValue(primary, fallback, defaultValue=0){
  if(primary!==undefined&&primary!==null) return primary;
  if(fallback!==undefined&&fallback!==null) return fallback;
  return defaultValue;
}

function _mergedCtxUsage(sessionUsage, latestUsage){
  const s=sessionUsage||{};
  const u=latestUsage||{};
  return {
    input_tokens:_pickUsageValue(u.input_tokens,s.input_tokens,0),
    output_tokens:_pickUsageValue(u.output_tokens,s.output_tokens,0),
    estimated_cost:_pickUsageValue(u.estimated_cost,s.estimated_cost,null),
    context_length:_pickUsageValue(u.context_length,s.context_length,0),
    last_prompt_tokens:_pickUsageValue(u.last_prompt_tokens,s.last_prompt_tokens,0),
    threshold_tokens:_pickUsageValue(u.threshold_tokens,s.threshold_tokens,0),
  };
}

Then in loadSession(...):

_syncCtxIndicator(_mergedCtxUsage(_s,S.lastUsage));

2. Preserve usage fields in session/index models

The same local fix also added these fields to the session model / compacted session payloads in api/models.py and populated them from the context compressor in api/streaming.py:

  • context_length
  • threshold_tokens
  • last_prompt_tokens

Related issues

Potentially related but not the same root bug:

This issue is specifically about the context/usage indicator and stale session usage metadata on load.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsprint-candidateStrong candidate for next sprint

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions