mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
fix(telemetry): stamp a compaction on entering the null window
Claude Code's tracker nulls recache_tokens_if_cold at a compaction or a tool-result clearing and only counts the expected rebuild at the next request, which also closes the window, so no report carried both and the old rule never fired. Stamp on the first warm null report after one that carried a value, carry it through idle re-reports and drop it at the next request; the readout now says "Context compacted at HH:MM" since a clearing opens the same window. Also persist a changed report so a crash restores the latest one, rename the session field to statusLineExporter (statusLineTelemetry is the registry capability) and document its values, word the stake as re-cached, move the readout block above the SSE staleness heading, and drop keep-warm mentions until it lands.
This commit is contained in:
1 parent
551a7f2792
commit
ecb2e3d8f3
16 files changed
+110
-125
No files matched your search
@@ -709,14 +709,12 @@ function computeConnectionLossUi(input) {
|
||||
};
|
||||
}
|
||||
|
||||
// SSE staleness policy: is this stream a zombie?
|
||||
//
|
||||
// Session Options → Respawn → "Prompt cache": one sentence of the main
|
||||
// conversation's cache state as Claude Code reports it on the statusline
|
||||
// (`session.promptCache`, v2.1.251+). A clock time rather than a countdown
|
||||
// because the row refreshes on SSE, not on a timer, and a countdown would sit
|
||||
// stale between turns. Pure: no DOM, `now` is passed in. `statusLine` is the
|
||||
// session's `statusLineTelemetry`: a launch without the exporter never reports, so
|
||||
// session's `statusLineExporter`: a launch without the exporter never reports, so
|
||||
// it says why instead of "not reported yet" forever.
|
||||
const PROMPT_CACHE_NOT_COLLECTED = {
|
||||
'collection-off':
|
||||
@@ -738,18 +736,20 @@ function formatPromptCacheStatus(cache, now, statusLine) {
|
||||
if (cache.warm && Number.isFinite(cache.expiresAt) && cache.expiresAt > now) {
|
||||
const ttl = cache.ttl ? ` (${cache.ttl} cache)` : '';
|
||||
parts.push(`Warm until ${clock(cache.expiresAt)}${ttl}.`);
|
||||
if (tokens) parts.push(`About ${tokens} tokens would be re-read if it goes cold.`);
|
||||
if (tokens) parts.push(`About ${tokens} tokens would be re-cached if it goes cold.`);
|
||||
} else {
|
||||
parts.push(tokens ? `Cold. The next turn re-reads about ${tokens} tokens at the cache-write rate.` : 'Cold.');
|
||||
parts.push(tokens ? `Cold. The next turn re-caches about ${tokens} tokens.` : 'Cold.');
|
||||
}
|
||||
// Claude Code's own idle compaction kept the prefix warm but smaller, so there is no
|
||||
// re-read stake to show; naming when it happened explains the shrink. Never an alert.
|
||||
if (Number.isFinite(cache.compactedAt)) parts.push(`Compacted at ${clock(cache.compactedAt)}.`);
|
||||
// A compaction or a tool-result clearing leaves no re-cache stake to show until the next
|
||||
// request; naming when it happened explains the gap. Never an alert.
|
||||
if (Number.isFinite(cache.compactedAt)) parts.push(`Context compacted at ${clock(cache.compactedAt)}.`);
|
||||
if (Number.isFinite(cache.hitRatio)) parts.push(`${Math.round(cache.hitRatio * 100)}% cache hit rate.`);
|
||||
if (cache.lastMissCauses && cache.lastMissCauses.length) parts.push(`Last miss: ${cache.lastMissCauses.join(', ')}.`);
|
||||
return parts.join(' ');
|
||||
}
|
||||
|
||||
// SSE staleness policy: is this stream a zombie?
|
||||
//
|
||||
// An EventSource that stops delivering does not always error. A proxy that
|
||||
// idle-closed the connection, a laptop resumed from sleep, a tailnet
|
||||
// reconnect: `onerror` never fires, the header dot stays green, and every
|
||||
|
||||
@@ -2795,7 +2795,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
const el = document.getElementById('promptCacheStatus');
|
||||
if (!el || this.editingSessionId !== sessionId) return;
|
||||
const session = this.sessions.get(sessionId);
|
||||
el.textContent = window.CodemanPromptCache.format(session?.promptCache, Date.now(), session?.statusLineTelemetry);
|
||||
el.textContent = window.CodemanPromptCache.format(session?.promptCache, Date.now(), session?.statusLineExporter);
|
||||
},
|
||||
|
||||
_onSessionPromptCache(data) {
|
||||
|
||||
@@ -71,6 +71,8 @@ export function registerStatusTelemetryRoutes(app: FastifyInstance, ctx: Session
|
||||
const promptCache = parsePromptCache(payload);
|
||||
if (promptCache && session?.setPromptCache(promptCache)) {
|
||||
ctx.broadcast(SessionPromptCache, { sessionId, ...session.promptCache });
|
||||
// Persisted on change, like a model change, so a crash restores the latest report.
|
||||
ctx.persistSessionState(session);
|
||||
}
|
||||
|
||||
// Plan-usage limits (account-wide) → broadcast to the header chip, when
|
||||
|
||||
Reference in new issue
Block a user