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, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop from '@deepseek-ai/dsh-agent-loop' import LocalFileSystem from '@deepseek-ai/dsh-fs-local' import * as FsPolicy from '@deepseek-ai/dsh-fs-policy' import * as ToolFs from '@deepseek-ai/dsh-tool-fs' import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek' /** * Shared harness for the fs-tools with-key e2e: a minimal real agent stack (the * DeepSeek adapter + the real fs provider + the read-before-write/edit policy + * the model-facing read/write/edit tools). Lives outside the *.e2e.ts pattern so * importing it never re-registers another file's tests. * * `fsCwd` is the local backend's default base; a per-session cwd (set via a * session header) overrides it, but this harness creates agents without a * session cwd, so the provider default IS the workspace. */ export async function fsHarness(fsCwd: string): Promise { const ctx = new Context() await ctx.plugin(LlmService) await ctx.plugin(SessionStore) await ctx.plugin(SystemPrompt) await ctx.plugin(ToolRegistry) await ctx.plugin(AgentRegistry) await ctx.plugin(AgentLoop, { agents: [] }) await ctx.plugin(LlmDeepSeek, { models: ['deepseek-v4-flash'] }) await ctx.plugin(LocalFileSystem, { cwd: fsCwd }) await ctx.plugin(FsPolicy) await ctx.plugin(ToolFs) return ctx } export function waitForIdle(ctx: Context, agent: Agent): Promise { return new Promise((resolve) => { const dispose = ctx.on('agent/status', (subject, status) => { if (subject === agent && status === 'idle') { dispose() resolve() } }) }) }