assistant-stream.host.spec.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import { describe, expect, it } from 'vitest'
  2. import { LlmAttemptId } from '@deepseek-ai/dsh-llm'
  3. import { SessionSeq } from '@deepseek-ai/dsh-session'
  4. import { SessionAssistantStreamAccumulator } from '../src/assistant-stream.ts'
  5. describe('SessionAssistantStreamAccumulator', () => {
  6. it('replaces stale lifecycles, rejects frame gaps, and caches each baseline', () => {
  7. const accumulator = new SessionAssistantStreamAccumulator()
  8. const empty = accumulator.snapshot()
  9. expect(accumulator.snapshot()).toBe(empty)
  10. accumulator.accept({
  11. type: 'start', attemptId: LlmAttemptId('stale'), revision: 2,
  12. startedTime: 1, turn: 1, step: 1,
  13. }, -1)
  14. expect(accumulator.snapshot()).toEqual({ revision: 2 })
  15. accumulator.accept({
  16. type: 'start', attemptId: LlmAttemptId('current'), revision: 1,
  17. startedTime: 2, turn: 2, step: 3,
  18. }, SessionSeq(5))
  19. expect(accumulator.snapshot()).toMatchObject({
  20. revision: 1,
  21. activeAttempt: {
  22. attemptId: 'current', startedAfterSeq: 5, turn: 2, step: 3, nextIndex: 0, stream: [],
  23. },
  24. })
  25. accumulator.accept({
  26. type: 'chunk', attemptId: LlmAttemptId('other'), revision: 2, index: 0,
  27. time: 4, chunk: { type: 'text-delta', index: 0, text: 'lost' },
  28. }, SessionSeq(5))
  29. expect(accumulator.snapshot()).toEqual({ revision: 2 })
  30. accumulator.accept({
  31. type: 'start', attemptId: LlmAttemptId('settled'), revision: 3,
  32. startedTime: 3, turn: 2, step: 4,
  33. }, SessionSeq(8))
  34. accumulator.accept({
  35. type: 'chunk', attemptId: LlmAttemptId('settled'), revision: 4, index: 0,
  36. time: 5, chunk: { type: 'text-delta', index: 0, text: 'ok' },
  37. }, SessionSeq(8))
  38. const active = accumulator.snapshot()
  39. expect(active).toMatchObject({
  40. revision: 4,
  41. activeAttempt: {
  42. attemptId: 'settled', startedAfterSeq: 8, nextIndex: 1,
  43. stream: [{ type: 'text-chunks', time0: 5, index: 0, dt: [], texts: ['ok'] }],
  44. },
  45. })
  46. expect(accumulator.snapshot()).toBe(active)
  47. accumulator.accept({
  48. type: 'end', attemptId: LlmAttemptId('settled'), revision: 5, index: 1,
  49. outcome: { kind: 'abandoned' },
  50. }, SessionSeq(9))
  51. expect(accumulator.snapshot()).toEqual({ revision: 5 })
  52. })
  53. })