review: address ds-review-bot findings on session-stats
- stateVersion starts at 1: the package is new, no persisted rows predate it - pendingCalls pairs by own key so a provider callId naming a prototype property cannot fold toolMs to NaN on an unmatched crash-recovery result - StatsLine folds the window fallback only when no sessionStats value is served, and gates the token group on actual token activity instead of steps, so failed-only sessions drop the zero-token group - correct the crash-step counting semantics in the README and Agent Note: recovery closes interrupted steps with a synthetic step/end on reload - reword the window-scoped alternative as a plain rejected option and name isTokenDelta's home beside the StreamChunk type
This commit is contained in:
@@ -6,7 +6,7 @@ import { isTokenDelta } from '@deepseek-ai/dsh-llm/message'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
|
||||
import type { AssistantTiming } from './conversation.ts'
|
||||
|
||||
// The first-token predicate lives with the StreamChunk vocabulary in dsh-llm;
|
||||
// The first-token predicate lives beside the StreamChunk type in dsh-llm;
|
||||
// re-exported here so Chat Definitions keep their client-runtime import.
|
||||
export { isTokenDelta } from '@deepseek-ai/dsh-llm/message'
|
||||
|
||||
|
||||
@@ -162,12 +162,13 @@ export interface StatsLineProps {
|
||||
|
||||
export const StatsLine = memo(function StatsLine({ useSession, useProjection, t }: StatsLineProps) {
|
||||
const settledNodes = useSession(s => s.chat.legacy.nodes)
|
||||
const windowStats = useMemo(() => deriveStats(settledNodes), [settledNodes])
|
||||
const usage = useProjection('tokenUsage')
|
||||
// Every figure rides the durable sessionStats projection, so paging and
|
||||
// compaction cannot change any of them; an assembly without the unit falls
|
||||
// back to the window-scoped fold wholesale (same field names).
|
||||
const stats = useProjection('sessionStats') ?? windowStats
|
||||
// back to the window-scoped fold wholesale (same field names), paid only
|
||||
// while no projection value is served.
|
||||
const projected = useProjection('sessionStats')
|
||||
const stats = useMemo(() => projected ?? deriveStats(settledNodes), [projected, settledNodes])
|
||||
// Pipe-separated groups (figma stats strip); a group with no data drops out whole.
|
||||
const groups: string[] = []
|
||||
if (stats.steps > 0) {
|
||||
@@ -190,9 +191,11 @@ export const StatsLine = memo(function StatsLine({ useSession, useProjection, t
|
||||
// Context occupancy deliberately lives on the composer's ContextMeter ring,
|
||||
// not here — one home per fact.
|
||||
// Billing rides the durable projection, so these survive paging and
|
||||
// compaction. Suppress the empty projection on a brand-new session.
|
||||
// compaction. Gated on actual token activity: a session whose steps all
|
||||
// settled without billing (e.g. every request failed) shows its counts
|
||||
// without a zero-token group.
|
||||
if (usage !== undefined
|
||||
&& (stats.steps > 0 || billedInputTokens(usage) > 0 || usage.outputTokens > 0)) {
|
||||
&& (billedInputTokens(usage) > 0 || usage.outputTokens > 0)) {
|
||||
const cacheHit = cacheHitPercent(usage)
|
||||
if (cacheHit !== null) groups.push(t('stats.cacheHit', { percent: cacheHit }))
|
||||
groups.push(t('stats.tokens', {
|
||||
|
||||
@@ -314,6 +314,17 @@ describe('StatsLine', () => {
|
||||
expect(view.container.textContent).toBe('')
|
||||
})
|
||||
|
||||
it('hides the zero-token group when steps closed without any billed activity', () => {
|
||||
// A session whose only turn failed before billing (e.g. an auth error):
|
||||
// the counts group renders alone, not an uninformative zero-token group.
|
||||
const { source } = makeSource()
|
||||
const view = render(<StatsLine {...props(source, {
|
||||
tokenUsage: { uncachedInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 },
|
||||
sessionStats: sessionStats({ turns: 1, steps: 1 }),
|
||||
})} />)
|
||||
expect(view.container.textContent).toBe('1 turns · 1 steps')
|
||||
})
|
||||
|
||||
it('keeps the counts group over an empty visible window when the projection carries totals', () => {
|
||||
// Extends the durable-groups guarantee: full-session counts survive a
|
||||
// window that compaction (or paging) left without assistant nodes.
|
||||
|
||||
Reference in New Issue
Block a user