| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- import { afterEach, describe, expect, it } from 'vitest'
- import { Context } from '@deepseek-ai/cordis'
- import SessionStore, { Session, SessionId, type CreateSessionOptions, type SessionEvent } from '@deepseek-ai/dsh-session'
- import DeepSeekLlmApiExtensionRegistry from '@deepseek-ai/dsh-deepseek-llm-api-extensions'
- import * as SessionLogDeepSeek from '../src/index.ts'
- const contexts: Context[] = []
- const SIGNAL = new AbortController().signal
- afterEach(async () => {
- await Promise.all(contexts.splice(0).map(ctx => ctx.fiber.dispose()))
- })
- async function harness(id: string, seed?: readonly SessionEvent[], meta?: CreateSessionOptions['meta']): Promise<{
- ctx: Context
- session: Session
- disposeUpload: () => Promise<void>
- }> {
- const ctx = new Context()
- contexts.push(ctx)
- await ctx.plugin(SessionStore)
- await ctx.plugin(DeepSeekLlmApiExtensionRegistry)
- const upload = ctx.plugin(SessionLogDeepSeek, { enabled: true })
- await upload
- const options = seed === undefined
- ? undefined
- : { seed, ...meta === undefined ? {} : { meta } }
- const session = ctx.sessions.create(SessionId(id), options)
- return { ctx, session, disposeUpload: () => upload.dispose() }
- }
- function body(text = 'x'.repeat(300)) {
- return { messages: [{ role: 'user', content: text }] }
- }
- describe('incremental DeepSeek session-log upload', () => {
- it('does not contribute the session log under its default configuration', async () => {
- const ctx = new Context()
- contexts.push(ctx)
- await ctx.plugin(SessionStore)
- await ctx.plugin(DeepSeekLlmApiExtensionRegistry)
- await ctx.plugin(SessionLogDeepSeek)
- const session = ctx.sessions.create(SessionId('default-off'))
- session.append('turn/start', { turn: 1 })
- const prepared = await ctx.deepseekLlmApiExtensions.prepare({
- body: body(), signal: SIGNAL, sessionId: session.id,
- })
- expect(prepared.fields).not.toHaveProperty('dsh_session_log')
- })
- it('uploads the full first prefix, records acceptance, then sends only the appended suffix', async () => {
- const { ctx, session } = await harness('incremental')
- session.append('turn/start', { turn: 1 })
- session.append('step/start', { turn: 1, step: 1 })
- const first = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- const firstPayload = first.fields.dsh_session_log
- expect(firstPayload).toMatchObject({ afterSeq: -1, throughSeq: 1 })
- expect(firstPayload?.events).toHaveLength(2)
- await first.accept()
- expect(SessionLogDeepSeek.acceptedThrough(session)).toBe(1)
- session.append('step/end', { turn: 1, step: 1 })
- const second = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- expect(second.fields.dsh_session_log).toMatchObject({ afterSeq: 1, throughSeq: 3 })
- expect(second.fields.dsh_session_log?.events).toHaveLength(2)
- expect(second.fields.dsh_session_log?.events[0]).toMatchObject({
- type: 'session-log-deepseek/delivery-accepted',
- seq: 2,
- })
- })
- it('reconstructs a persisted cursor and ignores an inherited parent watermark in a fork', async () => {
- const first = await harness('parent')
- first.session.append('turn/start', { turn: 1 })
- const prepared = await first.ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: first.session.id })
- await prepared.accept()
- const seed = first.session.events
- const resumed = await harness('parent', seed)
- expect(SessionLogDeepSeek.acceptedThrough(resumed.session)).toBe(0)
- const resumedPayload = await resumed.ctx.deepseekLlmApiExtensions.prepare({
- body: body(), signal: SIGNAL, sessionId: resumed.session.id,
- })
- expect(resumedPayload.fields.dsh_session_log?.afterSeq).toBe(0)
- const fork = await harness('child', seed, { parentSession: first.session.id, seedLength: seed.length })
- expect(SessionLogDeepSeek.acceptedThrough(fork.session)).toBe(-1)
- const forkPayload = await fork.ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: fork.session.id })
- expect(forkPayload.fields.dsh_session_log).toMatchObject({ afterSeq: -1, throughSeq: fork.session.seq - 1 })
- })
- it('takes the maximum watermark when concurrent acceptances settle out of order', async () => {
- const { ctx, session } = await harness('concurrent')
- session.append('turn/start', { turn: 1 })
- const earlier = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- session.append('step/start', { turn: 1, step: 1 })
- const later = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- await later.accept()
- await earlier.accept()
- expect(SessionLogDeepSeek.acceptedThrough(session)).toBe(1)
- })
- it('folds only events appended after the cached acceptance scan', () => {
- const id = SessionId('incremental-fold')
- const events: SessionEvent[] = [
- { type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } },
- { type: 'session-log-deepseek/delivery-accepted', seq: 1, time: 2, data: { sessionId: id, throughSeq: 0 } },
- ]
- let reads = 0
- const observed = new Proxy(events, {
- get(target, property, receiver) {
- if (typeof property === 'string' && /^\d+$/.test(property)) reads++
- return Reflect.get(target, property, receiver) as unknown
- },
- })
- const session = { id, get events() { return observed } } as unknown as Session
- expect(SessionLogDeepSeek.acceptedThrough(session)).toBe(0)
- expect(reads).toBe(2)
- reads = 0
- expect(SessionLogDeepSeek.acceptedThrough(session)).toBe(0)
- expect(reads).toBe(0)
- events.push(
- { type: 'step/start', seq: 2, time: 3, data: { turn: 1, step: 1 } },
- { type: 'session-log-deepseek/delivery-accepted', seq: 3, time: 4, data: { sessionId: id, throughSeq: 2 } },
- )
- expect(SessionLogDeepSeek.acceptedThrough(session)).toBe(2)
- expect(reads).toBe(2)
- })
- it('omits the field for direct or stale requests and uploads the prior acceptance marker next', async () => {
- const { ctx, session } = await harness('edges')
- await expect(ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL }))
- .resolves.toMatchObject({ fields: {} })
- await expect(ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: 'missing' }))
- .resolves.toMatchObject({ fields: {} })
- await expect(ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id }))
- .resolves.toMatchObject({ fields: {} })
- session.append('turn/start', { turn: 1 })
- const first = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- await first.accept()
- const current = await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })
- expect(current.fields.dsh_session_log).toMatchObject({
- afterSeq: 0,
- throughSeq: 1,
- events: [{ type: 'session-log-deepseek/delivery-accepted' }],
- })
- })
- it('contributes complete events without reading request messages', async () => {
- const { ctx, session } = await harness('direct-events')
- session.append('turn/start', { turn: 1 })
- const prepared = await ctx.deepseekLlmApiExtensions.prepare({ body: {}, signal: SIGNAL, sessionId: session.id })
- expect(prepared.fields.dsh_session_log?.events).toEqual(session.events)
- })
- it('fails closed on a malformed persisted acceptance watermark', async () => {
- const malformed = [{
- type: 'session-log-deepseek/delivery-accepted',
- seq: 0,
- time: 1,
- data: { sessionId: 'malformed', throughSeq: 0 },
- }] as unknown as SessionEvent[]
- const session = Session.create(SessionId('malformed'), malformed)
- expect(() => SessionLogDeepSeek.acceptedThrough(session)).toThrow(/malformed acceptance watermark/)
- })
- it('withdraws its request field when the contributing plugin reloads', async () => {
- const { ctx, session, disposeUpload } = await harness('hmr')
- session.append('turn/start', { turn: 1 })
- expect((await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })).fields)
- .toHaveProperty('dsh_session_log')
- await disposeUpload()
- expect((await ctx.deepseekLlmApiExtensions.prepare({ body: body(), signal: SIGNAL, sessionId: session.id })).fields)
- .not.toHaveProperty('dsh_session_log')
- })
- })
|