Skip to content

fix: update model column on mid-session model switches#28677

Closed
annguyenNous wants to merge 1 commit into
NousResearch:mainfrom
annguyenNous:fix/per-model-token-usage
Closed

fix: update model column on mid-session model switches#28677
annguyenNous wants to merge 1 commit into
NousResearch:mainfrom
annguyenNous:fix/per-model-token-usage

Conversation

@annguyenNous

Copy link
Copy Markdown
Contributor

Problem

The sessions table's model column uses COALESCE(model, ?) — first-writer-wins. Once a model is recorded for a session, it never updates on /model switches. Cumulative counters (input_tokens, output_tokens, etc.) keep summing across all models, but /usage and /insights attribute everything to the single locked-in model.

Fix

Change model = COALESCE(model, ?) to model = ? in both UPDATE statements in hermes_state.py (lines 805 and 826). This makes the column always reflect the latest model used.

Note: the acp_adapter/session.py already uses the correct pattern COALESCE(?, model) (reverse argument order — prefer new value). Only hermes_state.py had the bug.

Before vs After

Scenario Before After
Session starts with gpt-4o, switches to claude-sonnet model = gpt-4o forever model = claude-sonnet after switch
/usage attribution All tokens → gpt-4o Tokens attributed to correct model

Tests

Verified syntax with py_compile.compile(). The change is 2 lines (removing COALESCE wrapper) in a single file.

The sessions table uses COALESCE(model, ?) which is first-writer-wins —
once a model is recorded, it never updates on /model switches. This
causes /usage and /insights to attribute all tokens to the initial model.

Fix: change to model = ? so the column always reflects the latest model.
The acp_adapter already uses the correct pattern (COALESCE(?, model)).

Fixes NousResearch#28637
@teknium1

Copy link
Copy Markdown
Contributor

Closed in favor of PR #35256 (merged), which uses a targeted update_session_model() rather than flipping COALESCE(model, ?) to an unconditional set in update_token_counts — that method runs on every API call and the unconditional set risked clobbering with stale/None from other callers. Same root cause you correctly identified (#34850). Thanks @annguyenNous!

@teknium1 teknium1 closed this May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants