Typing /context in the composer opens a centered dialog with the current composition (provider-anchored headline, stacked bar, legend) and the last-10-turn trend chart — the same pushed contextTimeline projection the tab renders, no RPC, no polling. The command is the plugin's own '/' trigger source, fully client-side: no host descriptor, no session log records, nothing model-visible. The composer token is consumed only when the modal closes (deferred slash/input-consume-token with span / bare-token guards, fail-soft if the draft changed meanwhile). Esc, backdrop click, and the close button all close it and restore composer focus. Also extracts the provider-anchored headline derivation shared by the tab and the modal (headline.ts).
43 lines
2.1 KiB
TypeScript
43 lines
2.1 KiB
TypeScript
/**
|
|
* Provider-anchored headline derivation, shared by the Context tab and the
|
|
* /context popup: the best-known occupancy of the next request, the route
|
|
* capacity it scales against, and the composition parts anchored to that
|
|
* total (heuristic ratios, provider-anchored sum — the same trick the
|
|
* official ContextMeter uses).
|
|
*/
|
|
|
|
import type { ContextTimeline } from '../shared/types'
|
|
import { anchoredParts, partsOf, type PartsPart } from './categories'
|
|
|
|
export interface Headline {
|
|
/** Best-known occupancy of the next request (projected ?? derived ?? heuristic total). */
|
|
tokens: number
|
|
/** Route capacity the headline scales against (may be unknown). */
|
|
window?: number
|
|
/** tokens / window, clamped to 100; null without a window. */
|
|
pct: number | null
|
|
/** Composition parts anchored to the provider total when one exists. */
|
|
parts: PartsPart[]
|
|
/** True when no provider anchor applied (parts sum to the heuristic total). */
|
|
estimated: boolean
|
|
}
|
|
|
|
export function headlineOf(data: ContextTimeline): Headline {
|
|
const current = data.current
|
|
const occ = data.occupancy
|
|
const projected = occ !== undefined && typeof occ.projectedTokens === 'number' ? occ.projectedTokens : undefined
|
|
const requests = data.requests || []
|
|
const lastReq = requests.length > 0 ? requests[requests.length - 1] : null
|
|
// Fallback anchor: the newest request's provider prompt plus the heuristic
|
|
// surface movement since it was logged.
|
|
const derived = lastReq !== null && typeof lastReq.prompt === 'number'
|
|
? lastReq.prompt + (current.total - lastReq.total)
|
|
: undefined
|
|
const occupancyTokens = projected ?? derived ?? null
|
|
const window = occ !== undefined && typeof occ.contextWindow === 'number' ? occ.contextWindow : data.contextWindow
|
|
const tokens = occupancyTokens ?? current.total
|
|
const pct = window !== undefined && window > 0 ? Math.min(100, Math.round(tokens / window * 100)) : null
|
|
const parts = anchoredParts(partsOf(current), occupancyTokens !== null && tokens > 0 ? tokens : null)
|
|
return { tokens, window, pct, parts, estimated: occupancyTokens === null }
|
|
}
|