Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
2750598
πŸ€– feat: define token-budget context window contracts
ThomasK33 Sep 5, 2026
3058044
πŸ€– feat: wire context-budget rollover lifecycle
ThomasK33 Sep 5, 2026
0d751d7
πŸ€– feat: present token-budget context windows and document rollover po…
ThomasK33 Sep 5, 2026
49cd04a
πŸ€– feat: complete token-budget presentation metadata contracts
ThomasK33 Sep 5, 2026
4dda23e
πŸ€– fix: refresh context notes after memory tools and clean budget refu…
ThomasK33 Sep 5, 2026
f2419f0
πŸ€– feat: add bounded session history recovery across context windows
ThomasK33 Sep 5, 2026
4503008
πŸ€– fix: guard budget continuations against interrupt supersession
ThomasK33 Sep 5, 2026
e666e28
πŸ€– docs: describe atomic token-budget history batches accurately
ThomasK33 Sep 5, 2026
baee222
πŸ€– feat: reserve context notes and preflight assembled token budgets
ThomasK33 Sep 5, 2026
f81098c
πŸ€– fix: preserve structured budget errors and suppress unchanged retries
ThomasK33 Sep 5, 2026
3c1adb2
πŸ€– fix: pass effective memory permissions to budget settlement
ThomasK33 Sep 5, 2026
eae3d1d
πŸ€– fix: preserve flush opportunity and sync token-budget documentation
ThomasK33 Sep 5, 2026
a71068c
πŸ€– tests: cover token-budget lifecycle and settled step stopping
ThomasK33 Sep 5, 2026
8c0f945
πŸ€– tests: align rollover fixtures with settled budget contracts
ThomasK33 Sep 5, 2026
39c74e0
πŸ€– fix: open collapsed sidebar in token-budget settings story
ThomasK33 Sep 5, 2026
e4489c7
πŸ€– fix: preserve explicit compaction recovery with token budgets
ThomasK33 Sep 5, 2026
90ae593
πŸ€– fix: align session history inputs and paging with D9
ThomasK33 Sep 5, 2026
c90c03e
πŸ€– fix: finalize rollover recovery and token-budget presentation
ThomasK33 Sep 5, 2026
c0d737e
πŸ€– fix: enforce malformed reset privacy and rotate published history b…
ThomasK33 Sep 5, 2026
3ce1127
πŸ€– fix: preserve policy and request context across token-budget rollovers
ThomasK33 Sep 5, 2026
b176141
πŸ€– fix: scale token-budget reserves for small context windows
ThomasK33 Sep 5, 2026
546bf05
πŸ€– fix: display the effective token-budget rollover threshold
ThomasK33 Sep 5, 2026
32fb9a3
πŸ€– fix: retain accepted rollover inputs and isolate rejected context
ThomasK33 Sep 5, 2026
2b18a51
πŸ€– fix: bound history identifiers without stalling recovery cursors
ThomasK33 Sep 5, 2026
d8bdae6
πŸ€– fix: recover from terminal budget rejection and damaged preludes
ThomasK33 Sep 5, 2026
05c3f4d
πŸ€– fix: require complete rollover validation for history privacy excep…
ThomasK33 Sep 5, 2026
ba06f05
πŸ€– fix: atomically reject budget request payloads
ThomasK33 Sep 5, 2026
af7406c
πŸ€– fix: preserve reset floors and reject asynchronous budget failures
ThomasK33 Sep 5, 2026
d9d600e
πŸ€– fix: sanitize persisted token-budget counters
ThomasK33 Sep 5, 2026
9d2051d
πŸ€– merge: preserve routing-aware token budgets on current main
ThomasK33 Sep 5, 2026
df8ee64
πŸ€– fix: detect escaped reset markers in bounded history scans
ThomasK33 Sep 5, 2026
f3681fb
πŸ€– fix: preserve reset privacy across malformed history fragments
ThomasK33 Sep 5, 2026
e06b1a0
πŸ€– fix: keep legacy window IDs out of rollover instructions
ThomasK33 Sep 5, 2026
ec29277
πŸ€– fix: require history access only for eligible context rollovers
ThomasK33 Sep 5, 2026
23bd88c
πŸ€– fix: preserve reset privacy through corrupt separators and history …
ThomasK33 Sep 5, 2026
52971d3
πŸ€– fix: recognize reset tokens across arbitrary malformed separators
ThomasK33 Sep 5, 2026
b7f2081
πŸ€– fix: normalize persisted request prelude references
ThomasK33 Sep 5, 2026
be6e1f0
πŸ€– fix: terminate rejected retries and preserve append-only budget sends
ThomasK33 Sep 5, 2026
5d0e8ea
πŸ€– fix: certify history cursor appends with durable cross-process rece…
ThomasK33 Sep 5, 2026
00a1560
πŸ€– tests: cover terminal rejected-tail replay and document cursor prov…
ThomasK33 Sep 5, 2026
e153c3c
πŸ€– merge: reconcile current main with token-budget context windows
ThomasK33 Sep 5, 2026
a231fd6
πŸ€– fix: reject special-file history receipts without blocking
ThomasK33 Sep 5, 2026
96b9245
πŸ€– fix: preserve raw history reset floors and sanitize request preludes
ThomasK33 Sep 5, 2026
1cbd1f2
πŸ€– fix: retain unreadable reset floors through partial history truncation
ThomasK33 Sep 5, 2026
12ea025
πŸ€– fix: separate unterminated archive rows during truncation
ThomasK33 Sep 5, 2026
730d649
πŸ€– fix: recover budget usage and own copied retry skill snapshots
ThomasK33 Sep 5, 2026
416b79e
πŸ€– fix: harden history rewrites and truncation marker compatibility
ThomasK33 Sep 5, 2026
2828ad5
πŸ€– fix: validate persisted message parts before history operations
ThomasK33 Sep 5, 2026
fb2b82a
πŸ€– fix: quarantine rejected context payloads in downgrade-safe capsules
ThomasK33 Sep 6, 2026
a5eb5ef
πŸ€– tests: verify copied rejection capsules and document downgrade safety
ThomasK33 Sep 6, 2026
c77d0d8
πŸ€– fix: reject ambiguous reset keys and select the newest request iden…
ThomasK33 Sep 6, 2026
d3c5840
πŸ€– fix: honor inherited tool policy for session history
ThomasK33 Sep 6, 2026
1472e6b
πŸ€– fix: slice durable context boundaries before filtering hidden rows
ThomasK33 Sep 6, 2026
1224e85
πŸ€– fix: recognize hex-escaped history reset privacy floors
ThomasK33 Sep 6, 2026
255a7fd
πŸ€– fix: clamp provider history to unreadable reset floors
ThomasK33 Sep 6, 2026
e99a2f2
πŸ€– tests: preserve replay-boundary coverage after provider clamping
ThomasK33 Sep 6, 2026
a575706
πŸ€– fix: stop treating historical input usage as system overhead
ThomasK33 Sep 6, 2026
939a1bf
πŸ€– fix: retain active history without verified replay proof
ThomasK33 Sep 6, 2026
a01ca86
πŸ€– docs: explain conservative replay retention
ThomasK33 Sep 6, 2026
b4fcc8f
πŸ€– fix: tolerate corrupted persisted step boundaries
ThomasK33 Sep 6, 2026
d24f321
πŸ€– fix: pin workspace request middleware before context rollover
ThomasK33 Sep 6, 2026
b386a77
πŸ€– fix: apply goal safety when manual token-budget input is rejected
ThomasK33 Sep 6, 2026
be64254
πŸ€– fix: identify exact history rows and preserve Unicode search offsets
ThomasK33 Sep 6, 2026
21be114
πŸ€– fix: bind exact history row references to append epochs
ThomasK33 Sep 6, 2026
5e17c08
πŸ€– fix: recover readable rows through exact history references
ThomasK33 Sep 6, 2026
4d112b8
πŸ€– fix: enforce token-budget hard ceilings across dense input and sett…
ThomasK33 Sep 6, 2026
e968cb8
πŸ€– docs: describe real-encoding guards and settled hard stops
ThomasK33 Sep 6, 2026
67fa40a
πŸ€– fix: repair rotation retry tails and distinguish reset data from bo…
ThomasK33 Sep 6, 2026
15baf40
πŸ€– fix: reconcile main delivered-completion lifecycle
ThomasK33 Sep 6, 2026
36e6181
πŸ€– fix: preserve surrogate pairs in history character pages
ThomasK33 Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs/adr/0005-token-budget-context-windows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: Token-Budget Context Windows
description: An opt-in automatic reset policy with bounded retrieval and a manual-reset privacy floor
---

# 0005. Automatic Rollover Can Retrieve Earlier Context Windows

## Status

Accepted. Amends only consequence 2 of [ADR 0003](./0003-context-boundaries-for-compaction-and-reset.md) for automatic token-budget rollover.

## Context

Repeated automatic summaries lose detail and consume inference tokens. An opt-in policy can instead start a fresh Active Conversation Context while retaining Transcript History for explicit, bounded retrieval. Manual resets must keep their privacy semantics.

## Decision

Automatic rollover uses a provider-invisible Context Reset Boundary followed by a provider-visible synthetic lead-in. The lead-in identifies the new window and offers `session_history` retrieval; it does not summarize old messages. Earlier windows are retrievable only while the experiment is enabled and never across the newest manual reset. Manual `/clear --soft` remains provider-invisible, adds no lead-in, and establishes that privacy floor.

Manual `/compact`, idle compaction, continuous compaction, and effective RLM retain their existing behavior and take precedence over rollover. Existing edited-file carryover is unchanged. With automatic handling disabled, no rollover or flush warning is emitted, but hard assembled-request preflight still blocks oversized requests. `session_history` follows ordinary inherited agent and caller tool policy: an explicit tool name or matching wildcard must grant access, and later matching rules can remove it. The experiment does not widen narrow allowlists; built-in Exec and Plan grant access through `.*`, and Explore inherits that grant. If effective policy omits or disables history access, a rollover that would seal existing context is blocked rather than falling back to lossy summaries. A fitting first request in an empty or internal-only window does not require history access.

Before a rollover can clear context state or append a boundary, request admission reconciles the workspace's lazy plugin hooks and captures an immutable, ordered snapshot of the applicable request-assembly registrations. Unrestricted middleware is uncertified even when it appears benign: it could remove a tool or mutate its implementation/schema in place. Such middleware blocks rollover; it is never overridden by restoring a denied tool. Explicit workspace scopes are enforced during dispatch, so registrations for other workspaces do not block admission. Only the context-only registration adapter certifies toolset preservation: it receives no tool references and writes back system text alone. The sandboxed plugin context adapter uses this path.

The rollover turn's primary and fallback requests run the admitted snapshot; thinking rebuilds retain that assembled context and toolset. Neither consults later registry changes or constructs the toolset before cleanup. In-process automatic retries retain the same snapshot; it is never serialized into history or send options. Registration/unregistration changes affect subsequent admissions. Plugin disposal and managed-plugin mutation epochs remain live revocation checks, and hook execution reacquires sandbox mounts rather than retaining a disposed kernel. Ordinary non-rollover requests retain live middleware filtering.

A once-per-window warning offers a settled tool step to write the conventional `workspace/context-notes.md` file (up to 8 KiB, if writable). Its reserved hot-set slot still requires both Memory and Memory Hot Set. Rollover waits for a settled tool step, preserves tool call/result pairs, and allows only one pending rollover to be handled on the next send. Restart stays paused: it does not resurrect a queued continuation; the next message derives context pressure from persisted history.

The reset, lead-in, and triggering message or continuation are committed as one all-or-nothing batch before continuation. `HistoryService.appendManyToHistory` uses `writeFileAtomic` (temporary file and rename) under the cross-process history lock, rather than `fs.appendFile`; the current writer does not expose a torn batch prefix on crash. Recovery tests must still cover partial prefixes from legacy or externally modified histories without duplicating rollover or resurrecting queued work. A payload estimated not to fit even in a fresh window is rejected before a provider request.

Fresh-request, assembled-request, and settled-tool-output hard guards use the resolved model/capability encoding, bypassing approximation mode only for those counts. Large strings are counted in codepoint-safe chunks with boundary slack to bound long-run encoding work; encoding failures do not silently fall back to character ratios. Provider-family encodings and media/framing allowances remain estimates, so provider context-overflow handling remains a backstop. At a settled hard ceiling with automatic handling disabled, the turn stops without warning, rollover, continuation, or preflight quarantine; completed sibling tool results remain durable.

Only context-scoped cache, persisted carryover, and sandbox clearing runs before append. This ordering is deliberately fail-closed: a crash after publication must not reopen a fresh window with stale pre-reset carryover or kernel state. If cleanup succeeds but cancellation or append failure prevents publication, the old transcript remains with that disposable state cleared; it is not restored because a failed acknowledgment may still mean publication succeeded. Cancellation and admission are checked before cleanup and again before append. Branch-summary clearing and epoch notification run after append; cleanup failure must prevent a provider request. When rollover invalidates other sends, its own caller must adopt the updated epoch before continuing.

### Rejected request retention across downgrades

Rejected inputs and their owned snapshots are transcript-only. They are stored as empty, non-partial assistant records, retaining their identity and sequence; the original role, content, and display metadata live inside a new opaque metadata field. No original skill, file, command, or peer control metadata remains active on the outer record. Current display/export code can recover the original transcript projection without restoring it to provider history.

The preceding request assembler already excludes empty assistant records, so downgrading cannot replay rejected payloads merely because it ignores the new rejection flag. Older builds may not display the quarantined original content, but preserve it for a subsequent upgrade. Partial-truncation transaction markers likewise retain legacy decoded-text digests in their existing fields and add separately versioned byte digests, allowing both versions to recognize an accepted rewrite containing invalid UTF-8.

### Append-stable retrieval cursors

Head/tail hashes alone cannot distinguish an append from an interior rewrite followed by an append. Retrieval therefore uses a constant-size durable append receipt in addition to the bounded scan cursor. This receipt is cursor-safety metadata, not a rollover journal or a second copy of the transcript.

All cooperative history writers share the existing cross-process history lock. Before changing transcript files, a writer publishes a pending receipt; failure to invalidate the old receipt aborts the mutation. Only positively verified append operations may retain the receipt's epoch; a rewrite, truncation, rotation, recovery, or unexplained file change invalidates it. A stable receipt binds the epoch to the resulting chat and archive file stamps. Failure to finalize the receipt after accepting a history write expires cursors rather than reporting the accepted write as failed. Readers hold the same lock and validate the receipt and stamps before and after each bounded page, without running recovery during the scan. The bounded append scan still checks for newly added manual-reset privacy floors.

Append stability is guaranteed for tracked `HistoryService` appends, including tool-result appends and appends made by another backend process. Direct filesystem edits or appends observed outside a tracked transaction are untracked: existing cursors fail closed instead of treating file growth as proof of append-only history. Missing, malformed, pending, or mismatched receipts also expire existing cursors. A new query can establish a fresh baseline under the same history lock; it cannot revive an old cursor. Backend restarts continue to expire authenticated cursors.

The receipt assumes transcript writers honor the history lock during a tracked transaction. It detects an untracked edit between transactions or pages, including an interior rewrite followed by an append; it is not a defense against a process with filesystem write access racing an interior edit inside another writer's append/stat interval. Protecting against that adversary requires filesystem access isolation or verification of the entire prior prefix, not bounded file stamps.

The receipt does not turn history readers into unbounded prefix verifiers. Transcript scan and result budgets remain unchanged, and the receipt itself has a fixed-size read limit. Raw malformed reset candidates must also survive automatic history rewrites: invalidating an old cursor cannot repair a privacy floor that a writer erased before a new query.

Archived sequence coverage is not proof that an active row is a replay. Retrieval retains rows with reused sequences so repaired or imported content remains accessible; possible physical replay duplicates may therefore appear in results.

## Consequences

- `session_history` list/search/read is bounded: 16 KiB per tool result, 2 MiB scanned, 500 rows, and a 1 MiB per-line cap. Retrieval is scoped to the calling workspace and the manual-reset privacy floor.
- Old windows remain on disk and in transcript display/export. The lead-in stays hidden in normal transcript display; warnings render as machine messages, not human prompts.
- Opting out disables retrieval, not retention. ADR 0003's remaining decisions and consequences are unchanged.
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"workspaces/compaction",
"workspaces/compaction/manual",
"workspaces/compaction/automatic",
"workspaces/compaction/token-budget",
"workspaces/compaction/customization"
]
},
Expand Down
16 changes: 16 additions & 0 deletions docs/hooks/tools.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,22 @@ If a value is too large for the environment, it may be omitted (not set). Xum al

</details>

<details>
<summary>session_history (8)</summary>

| Env var | JSON path | Type | Description |
| ----------------------------- | -------------- | ------ | ----------- |
| `XUM_TOOL_INPUT_ACTION` | `action` | enum | β€” |
| `XUM_TOOL_INPUT_CURSOR` | `cursor` | string | β€” |
| `XUM_TOOL_INPUT_ITEM_ID` | `item_id` | string | β€” |
| `XUM_TOOL_INPUT_LIMIT` | `limit` | number | β€” |
| `XUM_TOOL_INPUT_LIMIT_CHARS` | `limit_chars` | number | β€” |
| `XUM_TOOL_INPUT_OFFSET_CHARS` | `offset_chars` | number | β€” |
| `XUM_TOOL_INPUT_QUERY` | `query` | string | β€” |
| `XUM_TOOL_INPUT_WINDOW_ID` | `window_id` | string | β€” |

</details>

<details>
<summary>set_goal (5)</summary>

Expand Down
2 changes: 2 additions & 0 deletions docs/workspaces/compaction/automatic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Xum can run `/compact` for you to keep context size manageable. There are two ty
- **Usage-based**: Compacts when your conversation reaches a configurable percentage of the model's context window
- **Idle-based**: Optionally compacts inactive workspaces after a period of time

The opt-in [token-budget context windows experiment](/workspaces/compaction/token-budget) replaces usage-triggered summaries with fresh windows and on-demand history retrieval. Manual and idle compaction are unchanged.

## Usage-based auto-compaction

When enabled, Xum monitors your context usage and:
Expand Down
31 changes: 31 additions & 0 deletions docs/workspaces/compaction/token-budget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: Token-Budget Context Windows
description: Start fresh context windows without automatic summaries and retrieve earlier work on demand
---

Enable **Token-budget context windows** in **Settings β†’ Experiments** to replace usage-triggered automatic summaries with fresh context windows. The experiment is off by default.

## Threshold and precedence

Use the existing context-usage slider to choose the per-model threshold. The **Rolls over by N%** label includes the five-percentage-point force buffer: a 70% slider setting displays **Rolls over by 75%**. Automatic rollover is evaluated when sending and after a settled tool step. The displayed percentage is an upper bound; the hard request ceiling takes precedence if reached first. Rollover starts a fresh window without summarizing earlier messages. The transcript shows a **Context window rollover** divider; earlier messages remain on disk, in the UI, and in exports.

- Manual `/compact` and idle compaction still summarize normally.
- Continuous compaction and effective RLM take precedence over rollover.
- Setting the usage threshold to **100%** disables automatic rollover and its warning. Hard request-size checks still apply, including after settled tool steps: the turn can pause without queuing a rollover or discarding completed tool results.
- `session_history` must be allowed by the agent's inherited tool policy and any caller restrictions. Built-in Exec, Plan, and Explore already allow it. Narrow custom agents can add `session_history` or a matching wildcard to `tools.add`. If access is omitted or disabled, rollover pauses before sealing existing context instead of falling back to a lossy summary.

Rollover also pauses when applicable request middleware can change the toolset, before clearing context state or saving a boundary. Context-only integrations, including sandboxed plugin context hooks, remain supported. Xum pins the workspace's applicable hook registrations when admitting a rollover and uses that snapshot throughout the turn and its fallback attempts; later registration changes apply to subsequent requests. Plugin revocation still takes effect. Hooks explicitly scoped to another workspace do not block rollover. Ordinary requests and manual `/compact` retain their existing middleware behavior.

## Keeping useful context

Once per window, a machine-authored warning asks the agent to write important context to the conventional `workspace/context-notes.md` file, up to **8 KiB**, if the workspace is writable. This is an opportunity to preserve notes, not a guarantee that the agent writes them. The notes' reserved hot-set slot still requires both **Memory** and **Memory Hot Set**; this experiment does not enable either.

The next window receives a model-only lead-in, not a summary. While the experiment is enabled, the agent can use `session_history` to list windows, search, or read earlier messages in the same workspace. Results are capped at **16 KiB** per call, with scans bounded to **2 MiB**, **500 rows**, and **1 MiB per line**. Large histories may require further bounded calls.

The newest manual `/clear --soft` is a privacy floor: the tool cannot retrieve messages before it. Manual reset behavior and edited-file carryover are unchanged. Turning the experiment off removes retrieval access without deleting old windows.

## Pauses and size limits

Rollover stops only after a tool step settles, preserving tool call/result pairs. Only one rollover may be pending; it is handled on the next send. Restart leaves the workspace paused rather than resurrecting a queued continuation, and the next message re-evaluates pressure from history.

The boundary, lead-in, and triggering message or continuation are saved as one atomic, all-or-nothing batch. Recovery also tolerates incomplete batches in legacy or externally modified histories. Requests estimated to exceed a fresh window are blocked before contacting the provider; rollover cannot make oversized attachments or instructions fit. Text guards use real encodings, but provider-family, media, and framing estimates can still differ from the provider's accounting.
11 changes: 7 additions & 4 deletions src/browser/components/ChatPane/ChatPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ const ChatPaneContent: React.FC<ChatPaneContentProps> = (props) => {
// after the transcript is visible.
const chatViewDataReady = useChatViewDataReady(workspaceId);

const { threshold: autoCompactionThreshold } = useAutoCompactionSettings(
const { threshold: autoCompactionThreshold, rolloverEnabled } = useAutoCompactionSettings(
workspaceId,
pendingModel
);
Expand Down Expand Up @@ -763,12 +763,12 @@ const ChatPaneContent: React.FC<ChatPaneContentProps> = (props) => {
const userMessageNavigationByHistoryId = useMemo(() => {
const userHistoryIds: string[] = [];
for (const message of deferredMessages) {
// Monitor wakes and peer-message wake triggers are synthetic machine rows and should not
// interrupt navigation between human prompts (payloads themselves are assistant rows).
// Machine wakes and budget warnings should not interrupt navigation between human prompts.
if (
message.type === "user" &&
message.bashMonitorWake == null &&
message.agentPeerMessageTrigger == null
message.agentPeerMessageTrigger == null &&
message.contextBudgetWarning == null
) {
userHistoryIds.push(message.historyId);
}
Expand Down Expand Up @@ -1714,6 +1714,7 @@ const ChatPaneContent: React.FC<ChatPaneContentProps> = (props) => {
canInterrupt={canInterrupt}
autoCompactionResult={autoCompactionResult}
shouldShowCompactionWarning={shouldShowCompactionWarning}
rolloverEnabled={rolloverEnabled}
contextSwitchWarning={contextSwitchWarning}
onContextSwitchCompact={handleContextSwitchCompact}
onContextSwitchDismiss={handleContextSwitchDismiss}
Expand Down Expand Up @@ -1789,6 +1790,7 @@ interface ChatInputPaneProps {
canInterrupt: boolean;
autoCompactionResult: ReturnType<typeof checkAutoCompaction>;
shouldShowCompactionWarning: boolean;
rolloverEnabled: boolean;
contextSwitchWarning: ContextSwitchWarning | null;
onContextSwitchCompact: () => void;
onContextSwitchDismiss: () => void;
Expand Down Expand Up @@ -1855,6 +1857,7 @@ const ChatInputPane: React.FC<ChatInputPaneProps> = (props) => {
usagePercentage={props.autoCompactionResult.usagePercentage}
thresholdPercentage={props.autoCompactionResult.thresholdPercentage}
isStreaming={props.canInterrupt}
rolloverEnabled={props.rolloverEnabled}
/>
</ChatDockSurface>
),
Expand Down
12 changes: 10 additions & 2 deletions src/browser/components/CompactionWarning/CompactionWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const CompactionWarning: React.FC<{
usagePercentage: number;
thresholdPercentage: number;
isStreaming: boolean;
rolloverEnabled: boolean;
}> = (props) => {
// At threshold or above, next message will trigger compaction
const willCompactNext = props.usagePercentage >= props.thresholdPercentage;
Expand All @@ -31,7 +32,14 @@ export const CompactionWarning: React.FC<{
let text: string;
let isUrgent: boolean;

if (showForceCompactCountdown) {
if (props.rolloverEnabled) {
// Rollover uses the same force threshold on-send and at settled tool steps.
text =
forceCompactRemaining > 0
? `Context rollover in ${Math.round(forceCompactRemaining)}% usage`
: "Next message starts a fresh context window";
Comment thread
ThomasK33 marked this conversation as resolved.
isUrgent = forceCompactRemaining <= 0;
} else if (showForceCompactCountdown) {
text = `Force-compacting in ${Math.round(forceCompactRemaining)}%`;
isUrgent = false;
} else if (willCompactNext) {
Expand All @@ -44,7 +52,7 @@ export const CompactionWarning: React.FC<{

return (
<div
className={`text-right text-[10px] ${
className={`counter-nums text-right text-[10px] ${
isUrgent ? "text-plan-mode font-semibold" : "text-muted"
}`}
>
Expand Down
Loading
Loading