| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'
- import { tmpdir } from 'node:os'
- import { join } from 'node:path'
- import { fileURLToPath, pathToFileURL } from 'node:url'
- import { execa } from 'execa'
- import { describe, expect, it } from 'vitest'
- import { resolveExampleLaunch } from '@deepseek-ai/dsh-loader-smoke'
- const dshBinScript = fileURLToPath(new URL('../src/bin.ts', import.meta.url))
- const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
- const fixturePlugin = pathToFileURL(fileURLToPath(
- new URL('./profiles/headless/tests/fixtures/team-llm.mjs', import.meta.url),
- )).href
- function records(content: string): Record<string, unknown>[] {
- return content.split('\n').filter(Boolean).map(line => JSON.parse(line) as Record<string, unknown>)
- }
- describe('dsh run with Agent Teams enabled', () => {
- it('runs two teammates, durable peer mail, dependent tasks, waiting, and final aggregation', async () => {
- const cwd = await mkdtemp(join(tmpdir(), 'dsh-agent-team-headless-'))
- try {
- const home = join(cwd, '.dsh')
- const sessions = join(home, 'sessions')
- const profileDir = join(home, 'profiles', 'headless')
- await mkdir(profileDir, { recursive: true })
- await writeFile(join(profileDir, 'package.json'), JSON.stringify({
- name: 'dsh-profile-headless',
- private: true,
- dependencies: {
- '@deepseek-ai/dsh-experimental-agent-team-profile': 'workspace:^',
- },
- dsh: {
- profile: {
- bundles: [
- '@deepseek-ai/dsh-base',
- '@deepseek-ai/dsh-headless',
- '@deepseek-ai/dsh-experimental-agent-team-profile',
- ],
- },
- },
- }, undefined, 2) + '\n')
- await writeFile(join(profileDir, 'cordis.patch.yml'), [
- '- id: llm-deepseek',
- ' disabled: true',
- '- id: session-persistence-jsonl',
- ' config:',
- ` root: '${sessions}'`,
- ' compression: none',
- '- insert:',
- ' - id: team-fixture-llm',
- ` name: '${fixturePlugin}'`,
- '',
- ].join('\n'))
- const launch = resolveExampleLaunch({
- srcBin: dshBinScript,
- configArgs: ['--profile', 'headless', '请明确使用 Agent Teams,把调研和实现拆给两个 teammate,等待完成后汇总。'],
- tsconfigPath,
- env: {
- DSH_HOME: home,
- DSH_AGENTS_HOME: join(cwd, '.agents'),
- DSH_TELEMETRY_DISABLED: '1',
- DEEPSEEK_API_KEY: '',
- NODE_OPTIONS: [
- process.env.NODE_OPTIONS,
- '--disable-warning=ExperimentalWarning',
- '--disable-warning=MODULE_TYPELESS_PACKAGE_JSON',
- ].filter(Boolean).join(' '),
- },
- })
- const result = await execa(launch.command, launch.args, {
- cwd,
- env: launch.env,
- input: '',
- timeout: 90_000,
- killSignal: 'SIGKILL',
- reject: false,
- })
- expect(
- result.exitCode,
- `dsh headless profile exited unexpectedly.\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
- ).toBe(0)
- expect(result.stderr).toBe('')
- expect(result.stdout).toContain('TEAM_WORKFLOW_OK')
- const files = (await readdir(sessions, { recursive: true }))
- .filter(file => file.endsWith('.jsonl'))
- expect(files).toHaveLength(3)
- const logs = await Promise.all(files.map(file => readFile(join(sessions, file), 'utf8')))
- const parsed = logs.map(records)
- const root = parsed.find((log) => {
- const header = log[0]
- return header?.type === 'session' && typeof header.parentSession !== 'string'
- })
- expect(root).toBeDefined()
- const eventTypes = root!.map(record => record.type)
- expect(eventTypes.filter(type => type === 'team/member')).toHaveLength(4)
- expect(eventTypes).toContain('team/message/queued')
- expect(eventTypes).toContain('team/message/delivered')
- const taskEvents = root!.filter(record => record.type === 'team/task')
- expect(taskEvents.filter((record) => {
- const data = record.data as { task?: { status?: string } } | undefined
- return data?.task?.status === 'completed'
- })).toHaveLength(2)
- const toolNames = root!.filter(record => record.type === 'tool/call')
- .map(record => (record.data as { name?: string } | undefined)?.name)
- expect(toolNames).toContain('wait_agent')
- expect(toolNames).toContain('team_task_list')
- expect(toolNames).toContain('list_agents')
- } finally {
- await rm(cwd, { recursive: true, force: true })
- }
- }, 105_000)
- })
|