import { mkdir, mkdtemp, readFile, realpath, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join, resolve } from 'node:path' import { describe, expect, it, vi } from 'vitest' import { createCanvas } from '@napi-rs/canvas' import { ToolCallId, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm' import type { RuntimeEvent } from './runtime' import { ModelToolProvider, type ModelToolCallContext } from './model-tool-provider' import type { ResolvedMcpServer } from '../capabilities/capability-service' import { createBoundedNdJsonStream, startControlledDeepSeekHarnessHost, type ControlledHarnessHost } from '../deepseek-harness-host' import { DeepSeekHarnessRuntime, type DeepSeekHarnessChild, type DeepSeekHarnessLaunchOptions } from './deepseek-harness-runtime' import { DshNpmExtensionInstaller } from './dsh-extension-marketplace' import { DEEPSEEK_HARNESS_MAX_FRAME_BYTES } from './deepseek-harness-control-protocol' import { createOpenAIChatCompletionsUrl } from './openai-endpoint' import { createModelRequestProbe } from '../../../tests/support/model-request-probe' import { ExecutionSpaceResolver } from '../execution-space/execution-space-resolver' import { SelectedRuntimeManager } from './selected-runtime-manager' import { LocalRuntimeRegistry } from './local-runtime-registry' import { createAgentRuntime } from './create-runtime' import { defaultRuntimeSettings } from '../../shared/contracts' import type { ResolvedRuntimeSettings } from '../runtime-settings-store' import { AssistantDatabase } from '../assistant/assistant-database' import { ImageGenerationService } from './image-generation-service' vi.mock('electron', () => ({ nativeImage: {} })) it('generates and edits durable images through the controlled Harness Main proxy and refreshes it in Ask', async () => { const root = await realpath(await mkdtemp(join(tmpdir(), 'goodbuddy-dsh-images-'))) const database = new AssistantDatabase(join(root, 'assistant.sqlite')) database.initialize(root) const conversationId = crypto.randomUUID() const profileId = crypto.randomUUID() const fetcher = vi.fn(async () => Response.json({ data: [{ b64_json: 'iVBORw0KGgo=' }] })) const service = new ImageGenerationService({ database, fetcher, getSettings: async () => ({ defaultImageModelProfileId: profileId, modelProfiles: [{ id: profileId, name: 'Image fixture', modelName: 'fixture', protocol: 'openai-images-generations', allowConversationInvocation: true, baseUrl: 'https://image.test/v1', authentication: 'none' }] }) }) let input: Record = { intent: 'create', prompt: 'Blue circle' } const inProcess = createInProcessLaunch(root, { stream(options) { const prompt = latestUserText(options) const tool = options.tools?.find(tool => tool.name === 'generate_image') if (prompt === 'ask-image') { expect(tool).toBeUndefined() return textResponse('Ask is read-only') } expect(tool).toBeDefined() expect(tool?.description).toContain(profileId) if (!toolResultText(options, prompt)) return toolCall(prompt, 'generate_image', input) expect(toolResultText(options, prompt)).toContain('completed') return textResponse('IMAGE_SAVED') } }) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: root, baseUrl: 'https://chat.test/v1', model: 'fixture', launch: inProcess.launch, credentialRefs: { [CREDENTIAL_REF]: 'fixture' }, toolProvider: new ModelToolProvider(root), initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) try { for (const intent of ['create', 'edit'] as const) { const messageId = crypto.randomUUID() const requestId = crypto.randomUUID() database.saveLocalConversations([{ header: { id: conversationId, title: 'Images', updatedAt: Date.now() }, messages: [{ id: messageId, role: 'assistant', content: '', createdAt: Date.now(), state: 'complete' }] }]) const events = await collect(runtime.run({ requestId, conversationId, prompt: `${intent}-${requestId}`, workMode: 'execute', imageToolBinding: service.bind({ conversationId, messageId, requestId, workMode: 'execute' }) }, new AbortController().signal, async () => 'once')) expect(events.at(-1)?.type).toBe('done') const operation = database.getConversation(conversationId).messages.find(message => message.id === messageId)!.imageOperations![0]! expect(operation.state).toBe('completed') input = { intent: 'edit', prompt: 'Turn red', sourceArtifactIds: operation.artifactIds } } await collect(runtime.run({ requestId: crypto.randomUUID(), conversationId, prompt: 'ask-image', workMode: 'ask' }, new AbortController().signal)) expect(fetcher).toHaveBeenCalledTimes(2) expect(String(fetcher.mock.calls[1]![0])).toMatch(/images\/edits$/u) } finally { await runtime.dispose() await service.dispose() database.close() await rm(root, { recursive: true, force: true }) } }, 60_000) const CREDENTIAL_REF = 'GOODBUDDY_HARNESS_MODEL_API_KEY' const SKILL_CALL_ID = 'e2e-skill-call' const MCP_CALL_ID = 'e2e-mcp-call' const ASK_MCP_CALL_ID = 'e2e-ask-mcp-call' const MICRO_DELTA_COUNT = 30_000 const liveModelEnabled = process.env.GOODBUDDY_DSH_MODEL_E2E === '1' const liveApiKey = process.env.GOODBUDDY_DSH_API_KEY ?? '' const liveBaseUrl = process.env.GOODBUDDY_DSH_BASE_URL ?? 'https://api.deepseek.com' const liveModel = process.env.GOODBUDDY_DSH_MODEL ?? 'deepseek-chat' function deferred() { let resolvePromise!: (value: T) => void const promise = new Promise((resolve) => { resolvePromise = resolve }) return { promise, resolve: resolvePromise } } function toolResultText( options: GenerateOptions, callId: string ): string | undefined { for (const message of options.messages) { if (message.role === 'tool' && message.toolCallId === callId) { return message.content .filter( ( content ): content is Extract< (typeof message.content)[number], { type: 'text' } > => content.type === 'text' ) .map((content) => content.text) .join('\n') } } return undefined } function latestUserText(options: GenerateOptions): string { return options.messages .filter( (message) => message.role === 'user' && message.source?.kind === 'user' ) .flatMap((message) => message.content .filter( ( content ): content is Extract< (typeof message.content)[number], { type: 'text' } > => content.type === 'text' ) .map((content) => content.text) ) .at(-1) ?? '' } async function* toolCall( callId: string, name: string, argumentsValue: Record ): AsyncGenerator { const id = ToolCallId(callId) const argumentsText = JSON.stringify(argumentsValue) yield { type: 'block-start', index: 0, blockType: 'tool-call' } yield { type: 'tool-call-delta', index: 0, id, name, argumentsDelta: argumentsText } yield { type: 'block-end', index: 0, block: { type: 'tool-call', id, name, arguments: argumentsText } } yield { type: 'usage', usage: { inputTokens: 10, outputTokens: 5, cacheReadTokens: 0, cacheWriteTokens: 0 } } yield { type: 'finish', reason: { kind: 'tool-calls' } } } async function* textResponse( text: string ): AsyncGenerator { yield { type: 'block-start', index: 0, blockType: 'text' } yield { type: 'text-delta', index: 0, text } yield { type: 'block-end', index: 0, block: { type: 'text', text } } yield { type: 'usage', usage: { inputTokens: 20, outputTokens: 8, cacheReadTokens: 0, cacheWriteTokens: 0 } } yield { type: 'finish', reason: { kind: 'stop' } } } async function* microDeltaResponse(): AsyncGenerator { yield { type: 'block-start', index: 0, blockType: 'reasoning' } for (let index = 0; index < MICRO_DELTA_COUNT; index += 1) { yield { type: 'reasoning-delta', index: 0, text: String(index % 10) } } yield { type: 'block-end', index: 0, block: { type: 'reasoning', text: Array.from( { length: MICRO_DELTA_COUNT }, (_value, index) => String(index % 10) ).join('') } } yield { type: 'usage', usage: { inputTokens: 20, outputTokens: 8_000, cacheReadTokens: 0, cacheWriteTokens: 0 } } yield { type: 'finish', reason: { kind: 'stop' } } } class FakeGameModel { mcpToolName?: string skillResult?: string blueprint?: Record askToolResult?: string executeToolNames: string[] = [] askToolNames: string[] = [] stream(options: GenerateOptions): AsyncIterable { const prompt = latestUserText(options) const toolNames = options.tools?.map((tool) => tool.name) ?? [] if (prompt.includes('ASK_BOUNDARY_PROBE')) { this.askToolNames = toolNames const result = toolResultText(options, ASK_MCP_CALL_ID) if (!result) { if (!this.mcpToolName) { throw new Error('Fake model has no prior MCP tool identity') } return toolCall(ASK_MCP_CALL_ID, this.mcpToolName, { theme: 'neon-ruins', seed: 'ask-must-not-execute', targetCount: 5 }) } this.askToolResult = result return textResponse('Ask mode MCP proxy unavailable as required.') } this.executeToolNames = toolNames const skillResult = toolResultText(options, SKILL_CALL_ID) if (!skillResult) { return toolCall(SKILL_CALL_ID, 'skill', { name: 'web-3d-game' }) } this.skillResult = skillResult const blueprintResult = toolResultText(options, MCP_CALL_ID) if (!blueprintResult) { const mcpTool = options.tools?.find((tool) => tool.name.endsWith('_create_game_blueprint') ) if (!mcpTool) { throw new Error( 'Main-mediated 3D blueprint MCP tool was not exposed' ) } this.mcpToolName = mcpTool.name return toolCall(MCP_CALL_ID, mcpTool.name, { theme: 'neon-ruins', seed: 'goodbuddy-0.9.0', targetCount: 5 }) } this.blueprint = JSON.parse( blueprintResult ) as Record return textResponse( 'Loaded the Web 3D Game Skill and the approved Prism Relay blueprint.' ) } } type HarnessModel = { stream(options: GenerateOptions): AsyncIterable } async function collect( stream: AsyncGenerator ): Promise { const events: RuntimeEvent[] = [] for await (const event of stream) { events.push(event) } return events } function createInProcessLaunch( dshHome: string, model?: HarnessModel, observeStream?: (options: GenerateOptions) => void ): { launch( options: DeepSeekHarnessLaunchOptions ): Promise hosts: ControlledHarnessHost[] } { const hosts: ControlledHarnessHost[] = [] return { hosts, async launch(options) { const clientToHost = new TransformStream() const hostToClient = new TransformStream() const exited = deferred<{ exitCode: number | null signal?: string | null }>() const host = await startControlledDeepSeekHarnessHost({ workspace: options.cwd, dshHome, baseUrl: options.baseUrl, api: 'openai-completions', provider: 'goodbuddy', model: options.model, supportsImageInput: options.supportsImageInput, requestHeaders: options.requestHeaders, harnessVersion: '0.1.7-rc.2', credentialRefs: options.credentialRefs, skillPackages: options.skillPackages, extensionPackages: options.extensionPackages, stream: createBoundedNdJsonStream( hostToClient.writable, clientToHost.readable, DEEPSEEK_HARNESS_MAX_FRAME_BYTES ) }) hosts.push(host) if (observeStream) { host.context.on( 'llm/stream', (request, next) => { observeStream(request) return next() }, { global: true, prepend: true } ) } if (model) { host.context.on( 'llm/stream', (request) => model.stream(request), { global: true, prepend: true } ) } let terminated = false return { stdin: clientToHost.writable, stdout: hostToClient.readable, exited: exited.promise, async terminate() { if (terminated) { return } terminated = true await host.dispose().catch(() => undefined) await Promise.allSettled([ clientToHost.writable.close(), hostToClient.writable.close() ]) exited.resolve({ exitCode: 0 }) } } } } } describe('DeepSeek Harness real ACP control-plane E2E', () => { it.each([2, 10])('shares one production-composed Host across %i projects with independent native file and shell tools', async (projectCount) => { const root = await realpath(await mkdtemp(join(tmpdir(), 'goodbuddy-dsh-reuse-'))) const directories = Array.from( { length: projectCount }, (_, index) => join(root, `project-${index}`) ) await Promise.all(directories.map(async (directory, index) => { await mkdir(directory) await writeFile(join(directory, 'marker.txt'), `PROJECT_${index}`) })) const inProcess = createInProcessLaunch(root, { stream(options) { const id = latestUserText(options) const read = toolResultText(options, `${id}-read`) if (read === undefined) return toolCall(`${id}-read`, 'read', { file_path: 'marker.txt' }) const write = toolResultText(options, `${id}-write`) if (write === undefined) return toolCall(`${id}-write`, 'write', { file_path: `${id}.txt`, content: read }) const shell = toolResultText(options, `${id}-shell`) if (shell === undefined) return toolCall(`${id}-shell`, process.platform === 'win32' ? 'pwsh' : 'bash', { command: process.platform === 'win32' ? 'Get-Content marker.txt' : 'cat marker.txt', description: 'Read the session workspace fixture' }) return textResponse(shell) } }) const launch = vi.fn(inProcess.launch) const registry = new LocalRuntimeRegistry() const resolver = new ExecutionSpaceResolver() const profile = { id: '00000000-0000-4000-8000-000000000009', name: 'Reuse fixture', baseUrl: 'http://127.0.0.1:9', modelName: 'reuse', protocol: 'openai-chat-completions' as const, authentication: 'api-key' as const, apiKey: 'unused-deterministic-model' } const settings = { ...defaultRuntimeSettings, provider: 'deepseek-harness', modelProfiles: [profile], deepseekHarnessModelProfile: profile } as ResolvedRuntimeSettings const manager = new SelectedRuntimeManager(async (_selection, space) => createAgentRuntime(root, settings, { executionSpace: space, localRuntimeRegistry: registry, deepseekHarnessLauncher: launch }), 1, 1, undefined, undefined, (id) => registry.releaseConversation(id)) try { const selection = { provider: 'deepseek-harness' as const } for (let wave = 0; wave < 2; wave++) { const outputs = await Promise.all(directories.flatMap((directory, project) => [0, 1].map(async (conversation) => { const runtime = await manager.getRuntime(selection, resolver.resolveLocal(directory)) const id = `p${project}-c${conversation}-w${wave}` const events = await collect(runtime.run({ requestId: id, conversationId: `p${project}-c${conversation}`, prompt: id, workMode: 'execute' }, AbortSignal.timeout(20_000))) expect(events.at(-1)?.type).toBe('done') expect(await readFile(join(directory, `${id}.txt`), 'utf8')).toContain(`PROJECT_${project}`) expect(events.filter((event) => event.type === 'text').map((event) => event.delta).join('')) .toContain(`PROJECT_${project}`) return events }) )) expect(outputs).toHaveLength(projectCount * 2) expect(launch).toHaveBeenCalledOnce() } await manager.releaseConversation('p0-c0') expect(launch).toHaveBeenCalledOnce() expect(inProcess.hosts).toHaveLength(1) } finally { await manager.dispose() await registry.dispose() await rm(root, { recursive: true, force: true }) } }, 60_000) it.skipIf(process.platform !== 'win32')('reuses a working runtime for mixed-separator and canonical Windows paths', async () => { const root = await realpath(await mkdtemp(join(tmpdir(), 'goodbuddy-dsh-path-'))) const workspace = join(root, 'workspace') const dshHome = join(root, 'home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) const canonical = await realpath(workspace) const mixed = `${root.replaceAll('\\', '/')}\\workspace` const resolver = new ExecutionSpaceResolver() const inProcess = createInProcessLaunch(dshHome, { stream: () => textResponse('PATH_OK') }) const launch = vi.fn(inProcess.launch) const manager = new SelectedRuntimeManager(async (_selection, space) => { if (space?.kind !== 'local') throw new Error('local workspace required') return new DeepSeekHarnessRuntime({ defaultWorkspace: space.rootPath, baseUrl: 'https://api.deepseek.com', model: 'path-test', launch, credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) }) try { expect(mixed).not.toBe(canonical) expect(await realpath(mixed)).toBe(canonical) const first = await manager.getRuntime({ provider: 'deepseek-harness' }, resolver.resolveLocal(mixed)) for (const [index, spelling] of [mixed, canonical].entries()) { const runtime = await manager.getRuntime({ provider: 'deepseek-harness' }, resolver.resolveLocal(spelling)) expect(runtime).toBe(first) const events = await collect(runtime.run({ requestId: `path-${index}`, conversationId: `path-${index}`, workMode: 'ask', prompt: 'Return PATH_OK.' }, AbortSignal.timeout(20_000))) expect(events.at(-1)).toMatchObject({ type: 'done' }) expect(events.filter(event => event.type === 'text').map(event => event.delta).join('')).toBe('PATH_OK') } expect(launch).toHaveBeenCalledOnce() expect(launch.mock.calls[0]?.[0].cwd).toBe(canonical) } finally { await manager.dispose() await rm(root, { recursive: true, force: true }) } }) it('keeps native Skills, plugin inventory, MCP calls and images scoped across shared projects', async () => { const root = await realpath(await mkdtemp(join(tmpdir(), 'goodbuddy-dsh-shared-capabilities-'))) const directories = [join(root, 'one'), join(root, 'two')] await Promise.all(directories.map(directory => mkdir(directory))) const plugin = join(root, 'inventory-plugin.mjs') await writeFile(plugin, [ "export const name = 'shared-inventory'", "export const inject = ['skills']", 'export function apply(ctx) {', "ctx.skills.register({ name: 'shared-plugin-skill', description: 'Shared plugin fixture', content: '# Shared plugin', source: 'custom' })", '}' ].join('\n')) const models = [new FakeGameModel(), new FakeGameModel()] const images = [createCanvas(1, 1).toBuffer('image/png'), createCanvas(2, 1).toBuffer('image/png')] const seenImages = new Map() const inProcess = createInProcessLaunch(root, { stream(options) { const project = latestUserText(options).includes('PROJECT_1') ? 1 : 0 seenImages.set(project, options.messages.flatMap(message => message.content).filter(block => block.type === 'image')) return models[project]!.stream(options) } }) const launch = vi.fn(inProcess.launch) const calls = vi.spyOn(ModelToolProvider.prototype, 'callTool') const registry = new LocalRuntimeRegistry() const profile = { id: '00000000-0000-4000-8000-000000000010', name: 'Capabilities fixture', baseUrl: 'http://127.0.0.1:9', modelName: 'capabilities', protocol: 'openai-chat-completions' as const, authentication: 'api-key' as const, apiKey: 'unused-deterministic-model', supportsImageInput: true } const resolver = new ExecutionSpaceResolver() const runtimes = directories.map(directory => createAgentRuntime(root, { ...defaultRuntimeSettings, provider: 'deepseek-harness', modelProfiles: [profile], deepseekHarnessModelProfile: profile } as ResolvedRuntimeSettings, { executionSpace: resolver.resolveLocal(directory), localRuntimeRegistry: registry, deepseekHarnessLauncher: launch, skillPackages: [{ id: 'web-3d-game', directory: resolve('tests/fixtures/web-3d-game-skill') }], deepseekHarnessExtensions: [{ id: 'shared-inventory', entrypoint: plugin, configuration: {} }], mcpServers: [{ id: 'fbf42200-4e60-48d0-b5f2-e816db38ac54', name: 'Shared blueprint', description: '', enabled: true, allowDynamicTools: false, assignments: ['deepseek-harness'], secretConfigured: false, transport: 'stdio', command: process.versions.electron ? 'node' : process.execPath, args: [resolve('tests/fixtures/web-3d-game-mcp.mjs')] }] })) try { for (const mode of ['execute', 'ask'] as const) { await Promise.all(runtimes.map(async (runtime, project) => { const events = await collect(runtime.run({ requestId: `capabilities-${project}-${mode}`, conversationId: `capabilities-${project}`, workMode: mode, prompt: `${mode === 'ask' ? 'ASK_BOUNDARY_PROBE' : 'Use Skill and MCP'} PROJECT_${project}`, ...(mode === 'execute' ? { images: [{ name: `project-${project}.png`, mediaType: 'image/png', data: images[project]!.toString('base64') }] } : {}) }, AbortSignal.timeout(30_000), async () => 'once')) expect(events.at(-1)?.type).toBe('done') const model = models[project]! if (mode === 'execute') { expect(model.skillResult).toContain('window.__GOODBUDDY_GAME__') expect(model.blueprint).toMatchObject({ title: 'Prism Relay' }) const seen = seenImages.get(project)! expect(seen).toHaveLength(1) const image = seen[0]! if (image.type !== 'image') throw new Error('Expected image block') expect(image.attachment).toMatchObject({ width: project + 1, height: 1 }) const stored = await inProcess.hosts[0]!.context.attachments.readImage(image.attachment) expect(Buffer.from(stored.data).equals(images[project]!)).toBe(true) } else { expect(model.askToolNames).not.toContain(model.mcpToolName) expect(model.askToolResult).toContain('Ask 模式不允许执行非只读工具') } expect(await runtime.getNativeSnapshot?.()).toMatchObject({ skills: expect.arrayContaining([expect.objectContaining({ id: 'shared-plugin-skill', source: 'plugin' })]) }) })) expect(launch).toHaveBeenCalledOnce() expect(calls).toHaveBeenCalledTimes(2) } expect(new Set(calls.mock.contexts).size).toBe(2) expect(calls.mock.calls.map(call => call[3]?.conversationId).sort()) .toEqual(['capabilities-0', 'capabilities-1']) await runtimes[0]!.releaseConversation?.('capabilities-0') expect(await runtimes[1]!.getStatus()).toMatchObject({ available: true }) expect(launch).toHaveBeenCalledOnce() } finally { calls.mockRestore() await Promise.all(runtimes.map(runtime => runtime.dispose())) await registry.dispose() await rm(root, { recursive: true, force: true }) } }, 60_000) it('writes outside the Workspace in Execute without approval and rejects the same tool in Ask', async () => { const root = await realpath(await mkdtemp(join(tmpdir(), 'goodbuddy-dsh-directory-'))) const workspace = join(root, 'workspace') const dshHome = join(root, 'home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) const externalFile = join(root, 'external.txt') const results: string[] = [] const inProcess = createInProcessLaunch(dshHome, { stream(options) { const result = toolResultText(options, 'external-write') if (result !== undefined) { results.push(result) return textResponse('DIRECTORY_TEST_DONE') } return toolCall('external-write', 'write', { file_path: externalFile, content: latestUserText(options) }) } }) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: 'https://api.deepseek.com', model: 'directory-test', launch: options => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) const authorize = vi.fn(async () => 'deny' as const) try { for (const mode of ['execute', 'ask'] as const) { const events = await collect(runtime.run({ requestId: `directory-${mode}`, conversationId: `directory-${mode}`, workMode: mode, prompt: mode === 'execute' ? 'EXECUTE_WRITTEN' : 'ASK_MUST_NOT_WRITE' }, AbortSignal.timeout(20_000), authorize)) expect(events.at(-1)).toMatchObject({ type: 'done' }) expect(await readFile(externalFile, 'utf8')).toBe('EXECUTE_WRITTEN') } expect(results).toHaveLength(2) expect(authorize).not.toHaveBeenCalled() } finally { await runtime.dispose() await rm(root, { recursive: true, force: true }) } }) it('delivers bounded inline images to an image-capable Harness model', async () => { const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-acp-image-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) let observedRequest: GenerateOptions | undefined const inProcess = createInProcessLaunch(dshHome, { stream(options) { observedRequest = options return textResponse('Image received.') } }) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: 'https://api.deepseek.com', model: 'vision-test', supportsImageInput: true, launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) const png = createCanvas(1, 1).toBuffer('image/png') try { const events = await collect( runtime.run( { requestId: 'request-acp-image', conversationId: 'acp-image', prompt: 'Describe this image.', workMode: 'ask', images: [ { name: 'reference.png', mediaType: 'image/png', data: png.toString('base64') } ] }, new AbortController().signal ) ) const image = observedRequest?.messages .flatMap((message) => message.content) .find( ( block ): block is Extract< GenerateOptions['messages'][number]['content'][number], { type: 'image' } > => block.type === 'image' ) expect(events).toContainEqual( expect.objectContaining({ type: 'done' }) ) expect(image?.attachment).toMatchObject({ mediaType: 'image/png', bytes: png.byteLength, width: 1, height: 1 }) const stored = await inProcess.hosts[0]!.context.attachments.readImage( image!.attachment ) expect(Buffer.from(stored.data).equals(png)).toBe(true) } finally { await runtime.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await rm(root, { recursive: true, force: true }) } }) it( 'coalesces micro reasoning deltas without losing content or overriding model output tokens', async () => { const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-acp-deltas-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) let observedRequest: GenerateOptions | undefined const inProcess = createInProcessLaunch(dshHome, { stream(options) { observedRequest = options return microDeltaResponse() } }) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: 'https://api.deepseek.com', model: 'deepseek-test', launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) try { const events = await collect( runtime.run( { requestId: 'request-acp-deltas', conversationId: 'acp-deltas', prompt: 'Return the deterministic reasoning stream.', workMode: 'execute' }, new AbortController().signal ) ) const reasoning = events.filter( ( event ): event is Extract< RuntimeEvent, { type: 'reasoning' } > => event.type === 'reasoning' ) expect(observedRequest?.maxTokens).toBeUndefined() expect( observedRequest?.messages .filter((message) => message.role === 'system') .flatMap((message) => message.content) .filter((block) => block.type === 'text') .map((block) => block.text) .join('\n') ).toContain('act through the available tools') expect(reasoning).toHaveLength(8) expect( reasoning.map((event) => event.delta).join('') ).toBe( Array.from( { length: MICRO_DELTA_COUNT }, (_value, index) => String(index % 10) ).join('') ) expect(events.at(-1)).toMatchObject({ type: 'done' }) } finally { await runtime.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await rm(root, { recursive: true, force: true }) } }, 30_000 ) it( 'rejects the ACP prompt with a bounded model turn error', async () => { const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-acp-error-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) const inProcess = createInProcessLaunch(dshHome, { stream() { throw new Error('synthetic model turn failed') } }) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: 'https://api.deepseek.com', model: 'deepseek-test', launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, initializationTimeoutMs: 20_000, promptTimeoutMs: 2_000, shutdownTimeoutMs: 5_000 }) try { await expect( collect( runtime.run( { requestId: 'request-acp-error', conversationId: 'acp-error', prompt: 'Trigger the synthetic model failure.', workMode: 'ask' }, new AbortController().signal ) ) ).rejects.toThrow('synthetic model turn failed') } finally { await runtime.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await rm(root, { recursive: true, force: true }) } }, 30_000 ) it( 'loads a native Skill, calls an approved real MCP, forwards events, and removes MCP in Ask', async () => { const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-acp-e2e-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([ mkdir(workspace), mkdir(dshHome) ]) const inventoryPlugin = join( root, 'native-inventory-plugin.mjs' ) await writeFile( inventoryPlugin, [ "export const name = 'native-inventory-plugin'", "export const inject = ['skills']", 'export function apply(ctx) {', ' ctx.skills.register({', " name: 'plugin-native-skill',", " description: 'Skill contributed by a Host plugin.',", " content: '# Plugin native skill',", " source: 'custom'", ' })', '}' ].join('\n'), 'utf8' ) const provider = new ModelToolProvider(workspace, [ { id: 'fbf42200-4e60-48d0-b5f2-e816db38ac54', name: 'Local 3D Game Blueprint', description: 'Deterministic integration fixture', enabled: true, allowDynamicTools: false, assignments: ['deepseek-harness'], secretConfigured: false, transport: 'stdio', command: process.versions.electron ? 'node' : process.execPath, args: [ resolve( 'tests', 'fixtures', 'web-3d-game-mcp.mjs' ) ] } satisfies ResolvedMcpServer ]) const callTool = vi.spyOn(provider, 'callTool') const listTools = vi.spyOn(provider, 'listTools') const fakeModel = new FakeGameModel() const inProcess = createInProcessLaunch(dshHome, fakeModel) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: 'https://api.deepseek.com', model: 'deepseek-test', launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: 'unused-in-memory-model-credential' }, skillPackages: [ { id: 'web-3d-game', directory: resolve( 'tests', 'fixtures', 'web-3d-game-skill' ) } ], extensionPackages: [ { id: 'native-inventory-plugin', entrypoint: inventoryPlugin, configuration: {} } ], toolProvider: provider, initializationTimeoutMs: 20_000, promptTimeoutMs: 20_000, shutdownTimeoutMs: 5_000 }) const authorize = vi.fn( async ( request: Parameters< NonNullable< Parameters[2] > >[0] ) => request.scopeKey.startsWith('model:mcp:') ? ('once' as const) : ('deny' as const) ) try { await runtime.testConnection() expect(inProcess.hosts[0]?.extensionFailures).toEqual([]) await expect(runtime.getNativeSnapshot()).resolves.toMatchObject({ provider: 'deepseek-harness', available: true, inventoryStatus: 'available', toolsSupported: true, tools: expect.arrayContaining([ expect.objectContaining({ id: 'read', kind: 'read', source: 'runtime', ask: 'allowed', execute: 'allowed' }), expect.objectContaining({ id: 'edit', kind: 'write', source: 'runtime', ask: 'blocked', execute: 'allowed' }) ]), skills: [ { id: 'plugin-native-skill', name: 'plugin-native-skill', description: 'Skill contributed by a Host plugin.', source: 'plugin' } ], mcpServers: [], agents: [], commands: [], lsp: [], formatters: [], prompts: [], resources: [], resourcesSupported: false, context: { strategy: 'unsupported', manualCompact: false } }) const executeEvents = await collect( runtime.run( { requestId: 'request-acp-execute', conversationId: 'acp-e2e', prompt: 'Use the Web 3D Game Skill and assigned blueprint MCP.', workMode: 'execute' }, new AbortController().signal, authorize ) ) expect(fakeModel.executeToolNames).toContain('skill') expect(fakeModel.mcpToolName).toMatch( /_create_game_blueprint$/u ) expect(fakeModel.skillResult).toContain( 'window.__GOODBUDDY_GAME__' ) expect(fakeModel.blueprint).toMatchObject({ title: 'Prism Relay', objective: { targetCount: 5 }, acceptance: { testSurface: 'window.__GOODBUDDY_GAME__' } }) expect(authorize).toHaveBeenCalledOnce() expect(callTool).toHaveBeenCalledWith( fakeModel.mcpToolName, { theme: 'neon-ruins', seed: 'goodbuddy-0.9.0', targetCount: 5 }, expect.any(AbortSignal), { conversationId: 'acp-e2e', workMode: 'execute', knowledgeCapabilityToken: undefined } satisfies ModelToolCallContext ) expect(executeEvents).toEqual( expect.arrayContaining([ expect.objectContaining({ type: 'tool', callId: SKILL_CALL_ID, name: 'skill', state: 'pending' }), expect.objectContaining({ type: 'tool', callId: SKILL_CALL_ID, state: 'completed' }), expect.objectContaining({ type: 'tool', callId: MCP_CALL_ID, name: fakeModel.mcpToolName, state: 'pending' }), expect.objectContaining({ type: 'tool', callId: MCP_CALL_ID, state: 'completed' }), expect.objectContaining({ type: 'text', delta: expect.stringContaining('Prism Relay') }), expect.objectContaining({ type: 'model-usage', runtime: 'deepseek-harness' }), expect.objectContaining({ type: 'done', sessionId: expect.any(String) }) ]) ) expect( executeEvents.filter( (event) => event.type === 'tool' && event.state === 'running' ) ).toHaveLength(0) const callsBeforeAsk = callTool.mock.calls.length const listsBeforeAsk = listTools.mock.calls.length const approvalsBeforeAsk = authorize.mock.calls.length const askEvents = await collect( runtime.run( { requestId: 'request-acp-ask', conversationId: 'acp-e2e', prompt: 'ASK_BOUNDARY_PROBE: attempt the previous MCP tool.', workMode: 'ask' }, new AbortController().signal, authorize ) ) expect(fakeModel.askToolNames).not.toContain( fakeModel.mcpToolName ) expect(fakeModel.askToolResult).toContain( 'Ask 模式不允许执行非只读工具' ) expect(callTool).toHaveBeenCalledTimes(callsBeforeAsk) expect(listTools).toHaveBeenCalledTimes(listsBeforeAsk + 1) expect(listTools).toHaveBeenLastCalledWith( { conversationId: 'acp-e2e', workMode: 'ask', knowledgeCapabilityToken: undefined }, expect.any(AbortSignal) ) expect(authorize).toHaveBeenCalledTimes(approvalsBeforeAsk) expect(askEvents).toEqual( expect.arrayContaining([ expect.objectContaining({ type: 'tool', callId: ASK_MCP_CALL_ID, name: fakeModel.mcpToolName, state: 'pending' }), expect.objectContaining({ type: 'tool', callId: ASK_MCP_CALL_ID, state: 'failed' }), expect.objectContaining({ type: 'text', delta: expect.stringContaining( 'MCP proxy unavailable' ) }), expect.objectContaining({ type: 'done' }) ]) ) } finally { await runtime.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await rm(root, { recursive: true, force: true }) } }, 60_000 ) it.runIf(liveModelEnabled)( 'forwards a custom model header through the real DeepSeek Harness provider', async () => { if (!liveApiKey) { throw new Error( 'GOODBUDDY_DSH_API_KEY is required for live DSH model E2E' ) } const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-header-model-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) const probe = await createModelRequestProbe({ upstreamUrl: createOpenAIChatCompletionsUrl(liveBaseUrl), headerName: 'x-goodbuddy-e2e' }) const inProcess = createInProcessLaunch(dshHome) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: probe.baseUrl, model: liveModel, requestHeaders: { 'x-goodbuddy-e2e': 'harness-header-present' }, launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: liveApiKey }, initializationTimeoutMs: 20_000, promptTimeoutMs: 120_000, shutdownTimeoutMs: 5_000 }) try { const events = await collect( runtime.run( { requestId: 'request-live-custom-header', conversationId: 'live-custom-header', prompt: 'Reply with exactly DSH_CUSTOM_HEADER_E2E_OK and nothing else.', workMode: 'ask' }, new AbortController().signal ) ) expect( events .flatMap((event) => event.type === 'text' ? [event.delta] : [] ) .join('') ).toContain('DSH_CUSTOM_HEADER_E2E_OK') expect(probe.observations).toEqual([ { headerValue: 'harness-header-present', bodyFields: {} } ]) } finally { await runtime.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await probe.close() await rm(root, { recursive: true, force: true }) } }, 180_000 ) it.runIf(liveModelEnabled)( 'lets a real model use Main-brokered Web Search and Fetch in Ask', async () => { if (!liveApiKey) { throw new Error( 'GOODBUDDY_DSH_API_KEY is required for live DSH model E2E' ) } const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-web-model-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') await Promise.all([mkdir(workspace), mkdir(dshHome)]) const observedRequests: GenerateOptions[] = [] const inProcess = createInProcessLaunch( dshHome, undefined, (options) => observedRequests.push(options) ) const toolProvider = new ModelToolProvider( workspace, [], undefined, undefined, true ) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: liveBaseUrl, model: liveModel, launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: liveApiKey }, toolProvider, initializationTimeoutMs: 20_000, promptTimeoutMs: 120_000, shutdownTimeoutMs: 5_000 }) try { const events = await collect( runtime.run( { requestId: 'request-live-web-search', conversationId: 'live-web-search', prompt: 'DSH_WEB_TOOLS_PROBE: First call web_search exactly once with query "GoodBuddy GitHub desktop assistant" and numResults 2. Then call web_fetch exactly once with urls ["https://example.com/"] and maxCharacters 1000. Do not call another tool. After both results, reply with DSH_WEB_TOOLS_E2E_OK.', workMode: 'ask' }, new AbortController().signal ) ) expect( observedRequests.flatMap( (options) => options.tools?.map((tool) => tool.name) ?? [] ) ).toEqual( expect.arrayContaining(['web_search', 'web_fetch']) ) expect(events).toEqual( expect.arrayContaining([ expect.objectContaining({ type: 'tool', name: 'web_search', state: 'completed' }), expect.objectContaining({ type: 'tool', name: 'web_fetch', state: 'completed' }) ]) ) expect( events .flatMap((event) => event.type === 'text' ? [event.delta] : [] ) .join('') ).toContain('DSH_WEB_TOOLS_E2E_OK') } finally { await runtime.dispose() await toolProvider.dispose() await Promise.allSettled( inProcess.hosts.map((host) => host.dispose()) ) await rm(root, { recursive: true, force: true }) } }, 180_000 ) it.runIf(liveModelEnabled)( 'rejects a real npm plugin in Ask and lets a real model call it in Execute', async () => { if (!liveApiKey) { throw new Error( 'GOODBUDDY_DSH_API_KEY is required for live DSH model E2E' ) } const root = await realpath( await mkdtemp(join(tmpdir(), 'goodbuddy-harness-plugin-model-')) ) const workspace = join(root, 'workspace') const dshHome = join(root, 'dsh-home') const installation = join(root, 'extension') await Promise.all([ mkdir(workspace), mkdir(dshHome), mkdir(installation) ]) let installer: DshNpmExtensionInstaller | undefined try { const entry = { id: 'dsh-plugin-greet-live', package: { name: 'dsh-plugin-greet', version: '0.2.0' }, displayName: 'dsh-plugin-greet', description: 'Reviewed minimal live DSH plugin fixture.' } const npmCliPath = process.env.GOODBUDDY_DSH_NPM_CLI ? resolve(process.env.GOODBUDDY_DSH_NPM_CLI) : resolve( 'node_modules', 'npm', 'bin', 'npm-cli.js' ) const nodeExecutablePath = process.env.GOODBUDDY_DSH_NODE_EXECUTABLE ? resolve( process.env.GOODBUDDY_DSH_NODE_EXECUTABLE ) : undefined installer = new DshNpmExtensionInstaller({ dshHome, npmCliPath, ...(nodeExecutablePath ? { nodeExecutablePath } : {}) }) const installed = await installer.install({ entry, destinationDirectory: installation }) const observedRequests: GenerateOptions[] = [] const inProcess = createInProcessLaunch( dshHome, undefined, (options) => observedRequests.push(options) ) const runtime = new DeepSeekHarnessRuntime({ defaultWorkspace: workspace, baseUrl: liveBaseUrl, model: liveModel, launch: (options) => inProcess.launch(options), credentialRefs: { [CREDENTIAL_REF]: liveApiKey }, extensionPackages: [ { id: entry.id, entrypoint: join( installation, ...installed.entrypoint.split('/') ), configuration: {} } ], initializationTimeoutMs: 20_000, promptTimeoutMs: 120_000, shutdownTimeoutMs: 5_000 }) try { const askEvents = await collect( runtime.run( { requestId: 'request-live-plugin-ask', conversationId: 'live-plugin-ask', prompt: 'DSH_ASK_PLUGIN_PROBE: attempt to call greet exactly once with name GoodBuddyAsk. The runtime must reject it. After the tool result, reply with DSH_ASK_PLUGIN_BLOCKED.', workMode: 'ask' }, new AbortController().signal ) ) const askRequests = observedRequests.filter((options) => latestUserText(options).includes( 'DSH_ASK_PLUGIN_PROBE' ) ) expect(askRequests.length).toBeGreaterThan(0) expect( askRequests.flatMap( (options) => options.tools?.map((tool) => tool.name) ?? [] ) ).toContain('greet') expect(askEvents).toEqual( expect.arrayContaining([ expect.objectContaining({ type: 'tool', name: 'greet', state: 'pending' }), expect.objectContaining({ type: 'tool', state: 'failed', output: expect.stringContaining( 'Ask 模式不允许执行非只读工具' ) }), expect.objectContaining({ type: 'done' }) ]) ) expect( askEvents.some( (event) => event.type === 'tool' && event.state === 'completed' ) ).toBe(false) expect( askEvents .flatMap((event) => event.type === 'text' ? [event.delta] : [] ) .join('') ).toContain('DSH_ASK_PLUGIN_BLOCKED') const executeEvents = await collect( runtime.run( { requestId: 'request-live-plugin-execute', conversationId: 'live-plugin-execute', prompt: 'DSH_EXECUTE_PLUGIN_PROBE: call greet exactly once with name GoodBuddyLive. After its result, reply with DSH_EXECUTE_PLUGIN_OK and the exact greeting.', workMode: 'execute' }, new AbortController().signal ) ) const executeRequests = observedRequests.filter((options) => latestUserText(options).includes( 'DSH_EXECUTE_PLUGIN_PROBE' ) ) expect(executeRequests.length).toBeGreaterThan(0) expect( executeRequests.some((options) => options.tools?.some((tool) => tool.name === 'greet') ) ).toBe(true) expect(executeEvents).toEqual( expect.arrayContaining([ expect.objectContaining({ type: 'tool', name: 'greet', state: 'pending' }), expect.objectContaining({ type: 'tool', state: 'completed', output: expect.stringContaining( 'Hello, GoodBuddyLive!' ) }), expect.objectContaining({ type: 'done' }) ]) ) expect( executeEvents .flatMap((event) => event.type === 'text' ? [event.delta] : [] ) .join('') ).toContain('DSH_EXECUTE_PLUGIN_OK') } finally { await Promise.allSettled([ runtime.dispose(), ...inProcess.hosts.map((host) => host.dispose()) ]) } } finally { await installer?.dispose().catch(() => undefined) await rm(root, { recursive: true, force: true }) } }, 180_000 ) })