import { afterEach, describe, expect, it } from 'vitest' import { Context } from 'cordis' import LlmService from '@deepseek-ai/dsh-llm' import SessionStore from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import ToolRegistry from '@deepseek-ai/dsh-tools' import AgentRegistry, { AgentId } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek' import SubagentService from '@deepseek-ai/dsh-subagent' import * as Spawn from '@deepseek-ai/dsh-subagent-spawn' import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow' import { CallId } from '@deepseek-ai/dsh-llm' import VmWorkflowEngine from '../src/index.ts' /** * With-key e2e for the workflow engine: a REAL script drives REAL spawn * children against the live DeepSeek API — one plain child and one schema'd * child through the real structured-output runtime — and the run's value, * events, and child sessions are asserted from the outside (never the * script's self-report alone). Key-gated (self-skips without * DEEPSEEK_API_KEY). */ let ctx: Context | undefined afterEach(async () => { await ctx?.fiber.dispose() ctx = undefined }) async function harness(): Promise { const built = new Context() await built.plugin(LlmService) await built.plugin(SessionStore) await built.plugin(SystemPrompt) await built.plugin(ToolRegistry) await built.plugin(AgentRegistry) await built.plugin(AgentLoop, { agents: [] }) await built.plugin(LlmDeepSeek, { models: ['deepseek-v4-flash'] }) await built.plugin(SubagentService) await built.plugin(Spawn, { providerName: 'spawn', structuredNudgeRetries: 1 }) await built.plugin(VmWorkflowEngine, { provider: 'spawn' }) await built.plugin(ToolWorkflow, {}) return built } const SCRIPT = `export const meta = { name: 'e2e-arithmetic', description: 'two real children: one prose, one structured', phases: [{ title: 'Ask' }, { title: 'Judge' }], } phase('Ask') log('asking the prose child') const prose = await agent('Reply with exactly one short sentence: what is 2 + 2?') phase('Judge') const judged = await agent( 'Here is an answer to the question "what is 2+2": ' + prose + ' — report whether it contains the number 4 and your confidence between 0 and 1.', { schema: { type: 'object', properties: { containsFour: { type: 'boolean' }, confidence: { type: 'number' } }, required: ['containsFour'] } }, ) return { prose, containsFour: judged === null ? null : judged.containsFour }` describe.skipIf(!process.env.DEEPSEEK_API_KEY)('workflow engine with-key e2e', () => { it('runs a two-phase script over real children, one through the structured runtime', async () => { ctx = await harness() const parentHandle = ctx.agents.create({ agentId: AgentId('wf-e2e-parent'), sessionId: 'wf-e2e-session' as never, agentOptions: { model: 'deepseek-v4-flash' }, }) const events: string[] = [] const childIds: string[] = [] for (const name of ['workflow/start', 'workflow/phase', 'workflow/log', 'workflow/agent-start', 'workflow/agent-end', 'workflow/end'] as const) { ctx.on(name, (...payload: unknown[]) => { events.push(name) if (name === 'workflow/agent-start') childIds.push((payload[1] as { childId: string }).childId) }) } const run = ctx.workflows.start({ script: SCRIPT, parent: parentHandle.agent }) const result = await run.result await run.dispose() expect(result.stopReason).toBe('completed') expect(result.agentsStarted).toBe(2) const value = result.value as { prose: string; containsFour: boolean | null } // World checks: the prose child really answered (a real completion), and // the structured child judged it against the REAL schema-forced tool. expect(value.prose.length).toBeGreaterThan(0) expect(value.containsFour).toBe(true) expect(events[0]).toBe('workflow/start') expect(events.at(-1)).toBe('workflow/end') expect(events.filter(name => name === 'workflow/phase').length).toBe(2) expect(events.filter(name => name === 'workflow/agent-start').length).toBe(2) expect(childIds.length).toBe(2) // The children were disposed to quiescence after collection. for (const childId of childIds) { expect(ctx.agents.get(AgentId(childId))).toBeUndefined() } await parentHandle.dispose() }, 240_000) it('the workflow TOOL runs the same path through the real registry pipeline', async () => { ctx = await harness() const parentHandle = ctx.agents.create({ agentId: AgentId('wf-e2e-tool-parent'), sessionId: 'wf-e2e-tool-session' as never, agentOptions: { model: 'deepseek-v4-flash' }, }) const result = await ctx.tools.execute({ callId: CallId('wf-e2e-call'), name: 'workflow', arguments: { script: `export const meta = { name: 'e2e-tool', description: 'one real child via the tool' } const answer = await agent('Reply with exactly one word: the capital of France.') return { answer }`, }, agent: parentHandle.agent, }) expect(result.isError).toBe(false) const text = (result.content[0] as { text: string }).text expect(text).toContain('workflow "e2e-tool" completed (1 agent)') expect(text.toLowerCase()).toContain('paris') await parentHandle.dispose() }, 240_000) })