Skip to content

fix(context): stabilize usage status updates - #95

Merged
omarluq merged 3 commits into
mainfrom
fix/context-usage-stability
Jun 7, 2026
Merged

fix(context): stabilize usage status updates#95
omarluq merged 3 commits into
mainfrom
fix/context-usage-stability

Conversation

@omarluq

@omarluq omarluq commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Keep the previous context usage visible while prompts are in flight, hide misleading zero-token window-only usage, and emit fresh usage snapshots after manual and automatic compaction so the footer reflects real context reductions.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1387f377-dc9f-4a02-835f-0a630643fea1

📥 Commits

Reviewing files that changed from the base of the PR and between 9a23c58 and 890a795.

📒 Files selected for processing (1)
  • internal/terminal/async_events_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/terminal/async_events_test.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Token usage now emits full-context "usage snapshot" events to replace prior usage info.
  • Bug Fixes

    • Fixed token usage updates after auto-compaction and compaction recovery.
    • Prompt streaming redraws now apply usage snapshots at appropriate times.
    • Token status hides empty context-window-only indicators.
    • Compact completion can preserve existing usage when no new usage is available.
  • Refactor

    • Centralized and standardized token-usage event emission and snapshot handling.
  • Tests

    • Added tests verifying snapshot emission, application, and snapshot-copy semantics.

Walkthrough

This PR introduces a fresh usage-snapshot event system where StreamEventUsageSnapshot represents a complete context-usage state intended to replace prior UI values. The assistant emits snapshots after auto-compaction and context overflow recovery, routing them through the terminal's async pipeline to be applied via deep-clone instead of incremental merge, while threading usage through the compaction workflow.

Changes

Usage Snapshot Feature

Layer / File(s) Summary
Snapshot event infrastructure
internal/assistant/runtime.go, internal/assistant/usage_events.go
New StreamEventUsageSnapshot constant, refactored emitUsageEvent to accept kind parameter, wrappers emitUsage and emitUsageSnapshot, and JSON payload enriched with snapshot: true when kind is snapshot.
Assistant auto-compaction refactoring
internal/assistant/context_auto_compaction.go, internal/assistant/export_test.go, internal/assistant/runtime.go
autoCompactAfterResponse returns (model.TokenUsage, bool), new maybeAutoCompactAfterResponse helper updates bundle.Usage, preflight auto-compaction emits snapshot, and Runtime.Prompt integrates refactored flow.
Context overflow recovery
internal/assistant/context_overflow_compaction.go
Switches from emitUsage to emitUsageSnapshot when emitting usage after rebuilding completion request following provider context overflow.
Prompt progression event handling
internal/assistant/runtime_persist.go
partialPromptProgress.record treats StreamEventUsageSnapshot as non-prompt event, preventing recording into prompt blocks or progression state.
Terminal async event routing
internal/terminal/async_events.go
New asyncEventPromptUsageSnapshot constant, promptStreamHandler recognizes StreamEventUsageSnapshot and posts async event, dispatch logic routes snapshot through prompt lifecycle as a prompt async event, and handlePromptStreamEvent applies usage via applyTokenUsageEvent(payload.Usage, true).
Token usage application and formatting
internal/terminal/token_usage.go, internal/terminal/app.go, internal/terminal/token_usage_export_test.go, internal/terminal/token_usage_test.go, internal/terminal/context_contributors_extra_test.go
New applyTokenUsageEvent(usage, snapshot) deep-clones when snapshot, merges otherwise; formatContextUsage returns empty when only ContextWindow is set; high-volume event classification includes usage events; test helpers and assertions verify snapshot application and format behavior.
Compaction flow integration
internal/terminal/compact_commands.go, internal/terminal/compact_commands_test.go
runCompactSession queries runtime.ContextUsage and passes TokenUsage to postCompactDone; compact-done async event carries usage in payload; applyCompactDone applies received usage via snapshot-mode; handleCompactAsyncEvent treats snapshot events as non-compact; tests validate usage presence and application and allow nil usage.
Prompt flow token usage management
internal/terminal/prompt_send.go, internal/terminal/prompt_send_test.go
Removed model.EmptyTokenUsage() initialization in sendPrompt so tokenUsage is not reset; test verifies tokenUsage persists with specified ContextTokens value across prompt send.
Test harness and async tests
internal/assistant/context_post_response_auto_compaction_test.go, internal/terminal/async_events_test.go, internal/terminal/compact_commands_test.go, internal/terminal/prompt_send_test.go
Tests updated/added to assert snapshot emission, snapshot application, compact-done usage behavior (including nil usage), and refactored test setup helpers for prompt-send tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • omarluq/librecode#84: Modifies post-response auto-compaction implementation; closely related to the autoCompactAfterResponse signature changes.
  • omarluq/librecode#87: Changes provider context overflow recovery; related to emitting usage after rebuild.
  • omarluq/librecode#93: Touches token-usage formatting logic; overlaps with formatContextUsage changes and tests.

Poem

A rabbit nudges code at night,
Snaps usage clean and sets it right —
Deep clones keep views soft and neat,
Tokens counted, snapshot-sweet. 🐰✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(context): stabilize usage status updates' directly summarizes the main change—stabilizing usage status updates through snapshot emissions and improved handling of context usage visibility.
Description check ✅ Passed The description clearly relates to the changeset by explaining the three key improvements: keeping previous context usage visible during prompts, hiding misleading zero-token usage, and emitting usage snapshots after compaction.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/context-usage-stability

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.04110% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.94%. Comparing base (12cb59f) to head (890a795).

Files with missing lines Patch % Lines
internal/assistant/context_auto_compaction.go 61.53% 4 Missing and 1 partial ⚠️
internal/terminal/compact_commands.go 62.50% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #95      +/-   ##
==========================================
+ Coverage   69.89%   69.94%   +0.05%     
==========================================
  Files         219      219              
  Lines       19610    19660      +50     
==========================================
+ Hits        13706    13752      +46     
- Misses       4738     4741       +3     
- Partials     1166     1167       +1     
Flag Coverage Δ
unittests 69.94% <89.04%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/assistant/context_post_response_auto_compaction_test.go (1)

110-122: 💤 Low value

LGTM!

Optional: Consider more descriptive test failure message.

The current failure message is sufficient, but you could optionally enhance it to indicate what was actually found (e.g., "found N snapshot events but all had ContextTokens == 0" or "found no snapshot events"). This would make test failures easier to diagnose, though the current message works fine for this helper.

💡 Optional enhancement example
 func assertPostResponseUsageSnapshot(t *testing.T, events []assistant.StreamEvent) {
 	t.Helper()
 
+	snapshotCount := 0
 	for _, event := range events {
 		if event.Kind != assistant.StreamEventUsageSnapshot || event.Usage == nil {
 			continue
 		}
+		snapshotCount++
 		if event.Usage.ContextTokens > 0 {
 			return
 		}
 	}
-	assert.Fail(t, "expected post-response auto-compaction usage snapshot")
+	if snapshotCount == 0 {
+		assert.Fail(t, "expected post-response auto-compaction usage snapshot, but found no snapshot events")
+	} else {
+		assert.Fail(t, "expected post-response auto-compaction usage snapshot with ContextTokens > 0, but all snapshots had zero tokens")
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/assistant/context_post_response_auto_compaction_test.go` around
lines 110 - 122, The helper assertPostResponseUsageSnapshot currently fails with
a generic message; update assertPostResponseUsageSnapshot to build and include
more descriptive failure text (e.g., count of snapshot events seen and whether
any had ContextTokens>0 or that no snapshot events were found) so test failures
show either "found X snapshot events but all had ContextTokens == 0" or "found
no snapshot events"; locate the function assertPostResponseUsageSnapshot and
change the final assert.Fail call to include the constructed descriptive
message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/terminal/compact_commands.go`:
- Around line 57-61: The code calls app.postCompactError when
app.runtime.ContextUsage(compactCtx, app.sessionID, app.cwd) fails, which
incorrectly marks a successful compaction as failed; instead, change the error
path to not call postCompactError—log or ignore the usage lookup error and
proceed with the normal success/completion flow for the compact operation
(retain compactID success handling and any UI update that signals compaction
completion). Locate the ContextUsage call and replace the
postCompactError(compactID, err) branch with a non-fatal handling (e.g.,
processLogger.Warn or similar) so the session remains marked compacted while
avoiding routing UI through the error recovery path.

---

Nitpick comments:
In `@internal/assistant/context_post_response_auto_compaction_test.go`:
- Around line 110-122: The helper assertPostResponseUsageSnapshot currently
fails with a generic message; update assertPostResponseUsageSnapshot to build
and include more descriptive failure text (e.g., count of snapshot events seen
and whether any had ContextTokens>0 or that no snapshot events were found) so
test failures show either "found X snapshot events but all had ContextTokens ==
0" or "found no snapshot events"; locate the function
assertPostResponseUsageSnapshot and change the final assert.Fail call to include
the constructed descriptive message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7881b5cf-9abb-4753-93dd-2088df624fe3

📥 Commits

Reviewing files that changed from the base of the PR and between 12cb59f and 72d944f.

📒 Files selected for processing (17)
  • internal/assistant/context_auto_compaction.go
  • internal/assistant/context_overflow_compaction.go
  • internal/assistant/context_post_response_auto_compaction_test.go
  • internal/assistant/export_test.go
  • internal/assistant/runtime.go
  • internal/assistant/runtime_persist.go
  • internal/assistant/usage_events.go
  • internal/terminal/app.go
  • internal/terminal/async_events.go
  • internal/terminal/compact_commands.go
  • internal/terminal/compact_commands_test.go
  • internal/terminal/context_contributors_extra_test.go
  • internal/terminal/prompt_send.go
  • internal/terminal/prompt_send_test.go
  • internal/terminal/token_usage.go
  • internal/terminal/token_usage_export_test.go
  • internal/terminal/token_usage_test.go
💤 Files with no reviewable changes (1)
  • internal/terminal/prompt_send.go

Comment thread internal/terminal/compact_commands.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/terminal/async_events_test.go (1)

531-539: ⚡ Quick win

Consider pre-initializing tokenUsage to verify replacement semantics.

The test name claims "replaces token usage," but the app starts with empty tokenUsage. To confirm snapshot events replace (not merge) prior usage, consider adding:

 {
 	name:    "usage snapshot replaces token usage",
 	payload: asyncTestEventWithUsage(asyncEventPromptUsageSnapshot, usage),
 	assert: func(t *testing.T, app *App) {
 		t.Helper()
+		// Verify replacement: if it were a merge, ContextTokens would be 50 (25+25).
 		assert.Equal(t, 25, app.tokenUsage.ContextTokens)
 	},
 	canceledActive: false,
 },

and in the test body (line 472):

 app := newRenderTestApp(t)
+if testCase.name == "usage snapshot replaces token usage" {
+	app.tokenUsage.ContextTokens = 25  // Pre-existing usage to be replaced
+}
 if testCase.canceledActive {

This would distinguish snapshot-replace from incremental-update behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/terminal/async_events_test.go` around lines 531 - 539,
Pre-initialize the App's tokenUsage before running the "usage snapshot replaces
token usage" test so the test verifies replacement (not merge): set a non-zero
tokenUsage (e.g., App.tokenUsage.ContextTokens = 123) in the test setup, then
call asyncTestEventWithUsage(asyncEventPromptUsageSnapshot, usage) and keep the
assert that checks app.tokenUsage.ContextTokens == 25; this ensures the snapshot
event produced by asyncEventPromptUsageSnapshot replaces the prior tokenUsage
rather than merging with it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/terminal/async_events_test.go`:
- Around line 531-539: Pre-initialize the App's tokenUsage before running the
"usage snapshot replaces token usage" test so the test verifies replacement (not
merge): set a non-zero tokenUsage (e.g., App.tokenUsage.ContextTokens = 123) in
the test setup, then call asyncTestEventWithUsage(asyncEventPromptUsageSnapshot,
usage) and keep the assert that checks app.tokenUsage.ContextTokens == 25; this
ensures the snapshot event produced by asyncEventPromptUsageSnapshot replaces
the prior tokenUsage rather than merging with it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6590dd65-741b-4a5a-9b79-e77e17b40a98

📥 Commits

Reviewing files that changed from the base of the PR and between 72d944f and 9a23c58.

📒 Files selected for processing (5)
  • internal/assistant/context_post_response_auto_compaction_test.go
  • internal/terminal/async_events_test.go
  • internal/terminal/compact_commands.go
  • internal/terminal/compact_commands_test.go
  • internal/terminal/prompt_send_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/assistant/context_post_response_auto_compaction_test.go
  • internal/terminal/compact_commands.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 7, 2026
@sonarqubecloud

sonarqubecloud Bot commented Jun 7, 2026

Copy link
Copy Markdown

@omarluq
omarluq merged commit 4b97c30 into main Jun 7, 2026
18 of 20 checks passed
@omarluq
omarluq deleted the fix/context-usage-stability branch June 7, 2026 23:34
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.

1 participant