Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions apps/desktop/electron/main/runtime/session-launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,16 @@ export function createSessionLaunchRuntime({
supportsVision: visionFromModelConfig(modelConfig),
supportedThinkingLevels: [...thinkingCapabilities.supportedThinkingLevels],
...(modelConfig ? { modelConfig } : {}),
// Per-model context/compaction settings ride the launch payload, so a
// settings change applies to the next prompt without a restart (ADR 0301
// / D447). Absent keeps the runtime's own defaults.
...(storedModel?.dynamicContext
? { dynamicContext: storedModel.dynamicContext }
: {}),
...(storedModel?.earlyCompaction
? { earlyCompaction: storedModel.earlyCompaction }
: {}),
...(storedModel?.sleepTime ? { sleepTime: storedModel.sleepTime } : {}),
},
pluginTools: [
...plugins
Expand Down
30 changes: 24 additions & 6 deletions apps/desktop/src/components/ContextUsageInspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function ContextUsageInspector({
responseDurationMs,
responseOutputTokens,
responseOutputEstimated = false,
estimatedOccupancyTokens,
}: {
usage: MessageUsage;
turnUsage: MessageUsage;
Expand All @@ -48,6 +49,12 @@ export function ContextUsageInspector({
responseDurationMs?: number;
responseOutputTokens?: number;
responseOutputEstimated?: boolean;
/**
* Post-compaction occupancy from the newest checkpoint, while it is newer
* than the latest usage-bearing message. The ring leads with it; the
* popover's provider rows keep the last real request.
*/
estimatedOccupancyTokens?: number;
}) {
const { t } = useTranslation();
const panelId = useId();
Expand All @@ -63,7 +70,18 @@ export function ContextUsageInspector({
const [open, setOpen] = useState(false);
const [popoverPosition, setPopoverPosition] =
useState<ContextInspectorPlacement | null>(null);
const context = calculateContextUsage(usage, contextWindow);
// A freshly compacted window has no request usage of its own: lead with the
// checkpoint's estimate until the next provider response lands.
const context =
estimatedOccupancyTokens !== undefined
? calculateContextUsage(
{ totalTokens: estimatedOccupancyTokens } as MessageUsage,
contextWindow,
)
: calculateContextUsage(usage, contextWindow);
// The estimate is not a measurement: mark it, so the number reads as an
// estimate rather than pretending to be the last request's real usage.
const occupancyPrefix = estimatedOccupancyTokens !== undefined ? "≈" : "";
// The display preference flips the leading figure only; capacity colors
// still follow remaining space so the warning state keeps one meaning.
const usageDisplay = useAppStore((state) =>
Expand Down Expand Up @@ -98,7 +116,7 @@ export function ContextUsageInspector({
// tooltip contract while `percent`/`count` stay numeric.
const ariaArguments = {
percent: display.percent,
count: formatCompactTokenCount(display.tokens),
count: occupancyPrefix + formatCompactTokenCount(display.tokens),
state:
display.display === "used"
? t("chat.usageContextAriaUsed")
Expand Down Expand Up @@ -261,14 +279,14 @@ export function ContextUsageInspector({
<strong className="context-inspector-heading-value">
{display.display === "used"
? t("chat.usageContextSpent", {
count: formatCompactTokenCount(display.tokens),
count: occupancyPrefix + formatCompactTokenCount(display.tokens),
})
: t("chat.usageContextLeft", {
count: formatCompactTokenCount(display.tokens),
count: occupancyPrefix + formatCompactTokenCount(display.tokens),
})}
</strong>
<strong className="context-inspector-heading-percent">
{display.percent}%
{occupancyPrefix}{display.percent}%
</strong>
</div>
<div className="context-inspector-window">
Expand Down Expand Up @@ -400,7 +418,7 @@ export function ContextUsageInspector({
/>
</svg>
<span className="context-inspector-ring-value">
{display.percent}%
{occupancyPrefix}{display.percent}%
</span>
</TooltipButton>
{popover && typeof document !== "undefined"
Expand Down
Loading
Loading