fix(web): reset live metrics between connections

This commit is contained in:
Hypatia May
2026-07-28 20:28:01 +08:00
parent 47205cbb82
commit ef12895cf1
8 changed files with 178 additions and 5 deletions

View File

@@ -102,6 +102,53 @@ describe('runtime client apply', () => {
expect(bench.api.callsOf('session.create')).toHaveLength(1)
})
it('clears connection-local Session state on disconnect but not connected', async () => {
const bench = await mount()
const sessions = bench.ctx.get('sessions') as SessionsService
bench.sinks?.onHostEnvelope?.({
rpcId: 'session' as never,
payload: { type: 'host/session-added', blank: true, sessionId: 's-state' } as never,
})
await Promise.resolve()
const session = sessions.binding('s-state' as never)?.session
if (session === undefined) throw new Error('session binding missing')
const currentMetrics = {
projectionRevision: 4,
logRevision: 10,
uncachedInputTokens: 10,
outputTokens: 4,
cacheReadTokens: 90,
cacheWriteTokens: 3,
contextTokens: 35,
}
bench.sinks?.onMuxEnvelope?.({
rpcId: 'metrics' as never,
payload: { type: 'session/metrics', sessionId: 's-state', metrics: currentMetrics } as never,
})
bench.sinks?.onMuxEnvelope?.({
rpcId: 'capacity' as never,
payload: {
type: 'session/model-request',
sessionId: 's-state',
turn: 1,
step: 1,
provider: 'test',
model: 'alpha',
contextWindow: 128_000,
} as never,
})
bench.sinks?.onConnected?.()
expect(session.getSnapshot()).toMatchObject({
metrics: currentMetrics,
modelRequestContextWindow: 128_000,
})
bench.sinks?.onDisconnected?.()
expect(session.getSnapshot().metrics).toBeNull()
expect(session.getSnapshot().modelRequestContextWindow).toBeUndefined()
})
it('stops the stream loop when the plugin fiber unloads', async () => {
const bench = await mount()
const fiber = [...bench.ctx.registry.values()].find(f => f.name?.includes('client'))

View File

@@ -4,7 +4,7 @@
*/
import { describe, expect, it, vi } from 'vitest'
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
import type { SessionId, SessionMetrics } from '@deepseek-ai/dsh-client-connection/client'
import { SessionManager } from '../src/client/sessions/manager.ts'
import { FakeApiClient, deferred, err, ok } from './fake-api.ts'
import { entries, plainTurn } from './event-script.ts'
@@ -162,6 +162,59 @@ describe('instances', () => {
expect(manager.get(S2).getSnapshot().modelRequestContextWindow).toBeUndefined()
})
it('clears resident metrics and capacity plus lazy capacity before reconnect', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)
const session = manager.get(S1)
const currentMetrics: SessionMetrics = {
projectionRevision: 4,
logRevision: 10,
uncachedInputTokens: 10,
outputTokens: 4,
cacheReadTokens: 90,
cacheWriteTokens: 3,
contextTokens: 35,
}
manager.handleMuxEnvelope({
rpcId: 'metrics' as never,
payload: { type: 'session/metrics', sessionId: S1, metrics: currentMetrics },
})
manager.handleMuxEnvelope({
rpcId: 'resident-capacity' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'resident',
contextWindow: 128_000,
},
})
manager.handleMuxEnvelope({
rpcId: 'lazy-capacity' as never,
payload: {
type: 'session/model-request',
sessionId: S2,
turn: 1,
step: 1,
provider: 'test',
model: 'lazy',
contextWindow: 256_000,
},
})
expect(session.getSnapshot()).toMatchObject({
metrics: currentMetrics,
modelRequestContextWindow: 128_000,
})
manager.handleReconnecting()
expect(session.getSnapshot().metrics).toBeNull()
expect(session.getSnapshot().modelRequestContextWindow).toBeUndefined()
expect(manager.get(S2).getSnapshot().modelRequestContextWindow).toBeUndefined()
})
it('caps the pending buffer at 32 keeping the newest, and drops it on session-removed', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)