keyless-smoke.e2e.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { readFile, readdir } from 'node:fs/promises'
  2. import { zstdDecompress } from 'node:zlib'
  3. import { promisify } from 'node:util'
  4. import { join } from 'node:path'
  5. import { fileURLToPath } from 'node:url'
  6. import { describe, expect, it } from 'vitest'
  7. import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke'
  8. import type { SessionEvent } from '@deepseek-ai/dsh-session'
  9. const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
  10. const configPath = fileURLToPath(new URL('./fixtures/cli.cordis.yml', import.meta.url))
  11. const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
  12. const decompress = promisify(zstdDecompress)
  13. describe('headless-agent keyless smoke', () => {
  14. it('boots the real Loader tree, runs a real bash tool round trip, and persists the turn', async () => {
  15. let persistedHeader: Record<string, unknown> | undefined
  16. const { stdout, stderr } = await runLoaderSmoke({
  17. label: 'headless-agent',
  18. tempDirPrefix: 'headless-agent-smoke-',
  19. binScript,
  20. configPath,
  21. binArgs: ['--config', configPath, '--output-format', 'stream-json', 'prove the tool path'],
  22. tsconfigPath,
  23. inspect: async (cwd) => {
  24. const files = await readdir(cwd, { recursive: true })
  25. const relativePath = files.find(file => file.endsWith('.jsonl.zstd'))
  26. if (relativePath === undefined) return
  27. const compressed = await readFile(join(cwd, relativePath))
  28. expect(compressed.subarray(0, 4).toString('hex')).toBe('28b52ffd')
  29. persistedHeader = JSON.parse((await decompress(compressed)).toString()) as Record<string, unknown>
  30. },
  31. })
  32. const lines = stdout.trimEnd().split('\n').map(line => JSON.parse(line) as Record<string, unknown>)
  33. const events = lines.slice(0, -1).map(line => line['event'] as SessionEvent)
  34. const result = lines.at(-1)
  35. expect(stderr).toBe('')
  36. expect(events.some(event => event.type === 'tool/call' && event.data.name === 'bash')).toBe(true)
  37. const toolResult = events.find(event => event.type === 'tool/result')
  38. expect(JSON.stringify(toolResult)).toContain('CLI_TOOL_ROUND_TRIP')
  39. expect(result).toMatchObject({
  40. type: 'result',
  41. success: true,
  42. turn: 1,
  43. reason: { kind: 'completed' },
  44. usage: { inputTokens: 18, outputTokens: 8, cacheReadTokens: 2, reasoningTokens: 1 },
  45. })
  46. expect(String(result?.['result'])).toContain('CLI_TOOL_ROUND_TRIP')
  47. expect(persistedHeader).toMatchObject({ type: 'session' })
  48. }, LOADER_SMOKE_TEST_TIMEOUT_MS)
  49. })