subagent-lineage.client.spec.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { describe, expect, it } from 'vitest'
  2. import type { SessionId } from '@deepseek-ai/dsh-session/types'
  3. import type { SessionSummary } from '../src/client/index.ts'
  4. import { indexSubagentDescendants } from '../src/client/index.ts'
  5. const sid = (id: string) => id as SessionId
  6. function summary(
  7. id: string,
  8. parentId?: SessionId,
  9. origin?: 'subagent',
  10. running = false,
  11. ): SessionSummary {
  12. return {
  13. id: sid(id), displayTitle: id, running, blank: false, updatedAt: 0,
  14. ...(parentId === undefined ? {} : { parentId }),
  15. ...(origin === undefined ? {} : { origin }),
  16. }
  17. }
  18. function index(...summaries: SessionSummary[]) {
  19. return indexSubagentDescendants(Object.fromEntries(
  20. summaries.map(item => [item.id, item]),
  21. ))
  22. }
  23. describe('indexSubagentDescendants', () => {
  24. it('counts every nested descendant and its exact running state', () => {
  25. const owner = summary('owner')
  26. const child = summary('child', owner.id, 'subagent')
  27. const grandchild = summary('grandchild', child.id, 'subagent', true)
  28. const result = index(owner, child, grandchild)
  29. expect(result.get(owner.id)).toEqual({ count: 2, runningCount: 1 })
  30. expect(result.get(child.id)).toEqual({ count: 1, runningCount: 1 })
  31. })
  32. it('stops at ordinary forks and fails soft on cycles and missing parents', () => {
  33. const owner = summary('owner')
  34. const child = summary('child', owner.id, 'subagent', true)
  35. const fork = summary('fork', child.id)
  36. const forkChild = summary('fork-child', fork.id, 'subagent', true)
  37. const orphan = summary('orphan', sid('missing'), 'subagent', true)
  38. const cycleA = summary('cycle-a', sid('cycle-b'), 'subagent')
  39. const cycleB = summary('cycle-b', sid('cycle-a'), 'subagent')
  40. const result = index(owner, child, fork, forkChild, orphan, cycleA, cycleB)
  41. expect(result.get(owner.id)).toEqual({ count: 1, runningCount: 1 })
  42. expect(result.get(fork.id)).toEqual({ count: 1, runningCount: 1 })
  43. expect(result.get(sid('missing'))).toEqual({ count: 1, runningCount: 1 })
  44. expect(result.get(cycleA.id)).toEqual({ count: 2, runningCount: 0 })
  45. expect(result.get(cycleB.id)).toEqual({ count: 2, runningCount: 0 })
  46. })
  47. })