fix(web): hide verified cold blank sessions
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* pushed to mux consumers as a session/projection frame minted here.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import { z } from 'zod'
|
||||
import AgentRegistry, { Inbox } from '@deepseek-ai/dsh-agent'
|
||||
@@ -163,10 +163,29 @@ describe('session.history projections block', () => {
|
||||
dispose()
|
||||
const after = await proxy.sessions.history(request({ sessionId: session.id }))
|
||||
if (!after.result.ok) throw new Error('unreachable')
|
||||
// The registry is still mounted, so the block itself stays (asOfSeq cut
|
||||
// with zero keys); the disposed key reads as capability absence.
|
||||
// The registry stays mounted; only the disposed key leaves while the
|
||||
// gateway-owned Session-list unit remains.
|
||||
expect(after.result.value.projections?.asOfSeq).toBe(session.seq - 1)
|
||||
expect(after.result.value.projections?.values).toEqual({})
|
||||
expect('test/last-user' in (after.result.value.projections?.values ?? {})).toBe(false)
|
||||
expect(after.result.value.projections?.values.sessionListMetadata).toEqual({
|
||||
blank: true,
|
||||
lastPromptAt: session.events.at(-1)?.time,
|
||||
})
|
||||
})
|
||||
|
||||
it('removes the gateway-owned Session-list unit when the gateway fiber unloads', async () => {
|
||||
const { ctx, session } = await harness(true)
|
||||
expect('sessionListMetadata' in ctx.sessionProjections.snapshot(session).values).toBe(false)
|
||||
const fiber = ctx.plugin(Object.assign((gatewayCtx: Context) => {
|
||||
createApiProxy(gatewayCtx, { defaultModelSelection: () => ({ provider: 'p', model: 'm' }), cwd: '/tmp' })
|
||||
}, { inject: ['sessions', 'agents', 'userQuestions', 'sessionProjections'] }))
|
||||
await fiber.await()
|
||||
await vi.waitFor(() => {
|
||||
expect(ctx.sessionProjections.snapshot(session).values.sessionListMetadata)
|
||||
.toEqual({ blank: true, lastPromptAt: null })
|
||||
})
|
||||
await fiber.dispose()
|
||||
expect('sessionListMetadata' in ctx.sessionProjections.snapshot(session).values).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -174,11 +193,18 @@ describe('session.list projections column', () => {
|
||||
it('serves attached rows from the live registry cut, watermarked for client seeding', async () => {
|
||||
const { ctx, session } = await harness(true)
|
||||
ctx.sessionProjections.register(lastUserUnit())
|
||||
const gateway = api(ctx)
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
session.append('turn/start', { turn: 1 })
|
||||
seedMessages(session, 1)
|
||||
const response = await api(ctx).sessions.list(request({}))
|
||||
const response = await gateway.sessions.list(request({}))
|
||||
if (!response.result.ok) throw new Error('unreachable')
|
||||
const row = response.result.value.items.find(item => item.sessionId === session.id)
|
||||
expect(row?.projections?.values['test/last-user']).toEqual({ text: 'm0' })
|
||||
expect(row?.projections?.values.sessionListMetadata).toEqual({
|
||||
blank: false,
|
||||
lastPromptAt: session.events.at(-1)?.time,
|
||||
})
|
||||
expect(row?.projections?.asOfSeq).toBe(session.seq - 1)
|
||||
})
|
||||
|
||||
@@ -266,21 +292,33 @@ describe('session/projection push frame', () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
const abort = new AbortController()
|
||||
const stream = proxy.events.mux({ rpcId: RpcId('t-proj-mux'), payload: {} }, abort.signal)
|
||||
const collected = collect(stream, 2, abort)
|
||||
const collected = collect(stream, 5, abort)
|
||||
|
||||
const now = vi.spyOn(Date, 'now').mockReturnValue(100)
|
||||
seedMessages(session, 1)
|
||||
// Same-reference apply: turn/start does not concern the unit — no frame.
|
||||
now.mockReturnValue(200)
|
||||
session.append('turn/start', { turn: 1 })
|
||||
now.mockReturnValue(300)
|
||||
seedMessages(session, 1)
|
||||
now.mockRestore()
|
||||
|
||||
const frames = await collected
|
||||
const pushes = frames.filter(
|
||||
(f): f is Extract<MuxFrame, { type: 'session/projection' }> => f.type === 'session/projection',
|
||||
(f): f is Extract<MuxFrame, { type: 'session/projection' }> =>
|
||||
f.type === 'session/projection' && f.key === 'test/last-user',
|
||||
)
|
||||
expect(pushes).toEqual([
|
||||
{ type: 'session/projection', sessionId: session.id, key: 'test/last-user', value: { text: 'm0' }, seq: 0 },
|
||||
{ type: 'session/projection', sessionId: session.id, key: 'test/last-user', value: { text: 'm0' }, seq: 2 },
|
||||
])
|
||||
expect(frames.filter(
|
||||
(f): f is Extract<MuxFrame, { type: 'session/projection' }> =>
|
||||
f.type === 'session/projection' && f.key === 'sessionListMetadata',
|
||||
)).toEqual([
|
||||
{ type: 'session/projection', sessionId: session.id, key: 'sessionListMetadata', value: { blank: true, lastPromptAt: 100 }, seq: 0 },
|
||||
{ type: 'session/projection', sessionId: session.id, key: 'sessionListMetadata', value: { blank: false, lastPromptAt: 100 }, seq: 1 },
|
||||
{ type: 'session/projection', sessionId: session.id, key: 'sessionListMetadata', value: { blank: false, lastPromptAt: 300 }, seq: 2 },
|
||||
])
|
||||
// Frame seq aligns with the tail block's asOfSeq vocabulary (higher-seq-wins compatible).
|
||||
const tail = await proxy.sessions.history(request({ sessionId: session.id }))
|
||||
if (!tail.result.ok) throw new Error('unreachable')
|
||||
|
||||
Reference in New Issue
Block a user