mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(web): let the context meter see a compaction
The composer ring, percentage, and `~used / capacity` header read
`contextPressure.pressureTokens`, which moves only when a request reports
usage. Compaction reports none — compact-basic summarizes through a direct
`ctx.llm.stream()` call and appends only its own `compact/*` records plus the
replacement `user/message` — so the meter was frozen across the one action
taken to change it. Driving a real `compactNow` through the agent loop:
BEFORE compact: ring=4% header=~4227/100000 rows=[18, 0, 4365]
AFTER compact: ring=4% header=~4227/100000 rows=[18, 0, 286]
The composition rows fell 93%; the ring did not move, and would not until an
entire further turn completed. The panel then contradicted itself by more than
an order of magnitude at exactly the moment a reader opens it.
`contextPressure` now also publishes `projectedTokens`: the provider sample
plus the heuristic repricing of everything the surface gained or lost since
that sample, clamped at zero, folded through the shared `surface-fold.ts`. The
sample is stamped before the same event joins the surface, so an
`assistant/message` anchors against the surface its own request carried. Only
the delta is estimated, so the figure stays provider-anchored — the estimator's
CJK and JSON-schema underpricing stays out of the occupancy number — while
reacting the moment content lands or a span is shadowed. Same run after:
BEFORE compact: ring=4% header=~4323/100000 (pressure=4227, projected=4323)
AFTER compact: ring=0% header=~ 244/100000 (pressure=4227, projected= 244)
`contextOccupancy` prefers the projected figure and falls back to the bare
sample, so a projection restored from a pre-field checkpoint degrades to the
old behavior rather than disappearing. `stateVersion` moves to 3.
This commit is contained in:
@@ -119,25 +119,30 @@ export function billedInputTokens(usage: TokenUsageProjection): number {
|
||||
|
||||
interface ContextOccupancy {
|
||||
percent: number
|
||||
pressureTokens: number
|
||||
usedTokens: number
|
||||
contextWindow: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Approximate context occupancy, using the TUI's integer rounding and upper
|
||||
* clamp. The numerator and capacity are independent last-wins projection
|
||||
* fields, so this is a reference figure rather than an exact measurement of one
|
||||
* request (see the token-meter README).
|
||||
* clamp. The numerator is `projectedTokens` — the provider sample carried
|
||||
* forward over the surface's movement since — so compaction shows immediately
|
||||
* instead of waiting for the next request to report usage; it falls back to the
|
||||
* bare sample only for a log whose projection predates that field. Numerator
|
||||
* and capacity remain independent last-wins projection fields, so this is a
|
||||
* reference figure rather than an exact measurement of one request (see the
|
||||
* token-meter README).
|
||||
* @param pressure - the session's context-pressure projection value.
|
||||
* @returns occupancy with its numerator and denominator, or null until both values are known.
|
||||
*/
|
||||
export function contextOccupancy(
|
||||
pressure: ContextPressureProjection | undefined,
|
||||
): ContextOccupancy | null {
|
||||
if (pressure?.pressureTokens === undefined || pressure.contextWindow === undefined) return null
|
||||
const usedTokens = pressure?.projectedTokens ?? pressure?.pressureTokens
|
||||
if (usedTokens === undefined || pressure?.contextWindow === undefined) return null
|
||||
return {
|
||||
percent: Math.min(100, Math.round(pressure.pressureTokens / pressure.contextWindow * 100)),
|
||||
pressureTokens: pressure.pressureTokens,
|
||||
percent: Math.min(100, Math.round(usedTokens / pressure.contextWindow * 100)),
|
||||
usedTokens,
|
||||
contextWindow: pressure.contextWindow,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ export function ContextMeter({ useProjection, t }: ContextMeterProps) {
|
||||
<span className={css.percent}>{reading}</span>
|
||||
<span className={css.headline}>{headAfter}</span>
|
||||
<span className={css.figures}>
|
||||
{`~${formatTokens(context.pressureTokens)} / ${formatTokens(context.contextWindow)}`}
|
||||
{`~${formatTokens(context.usedTokens)} / ${formatTokens(context.contextWindow)}`}
|
||||
</span>
|
||||
</div>
|
||||
<div className={css.bar}>
|
||||
|
||||
Reference in New Issue
Block a user