Files
goodbuddy/src/main/deepseek-harness-host.test.ts
T
mesalogo 1c22e1a06d fix: keep browser overlays and knowledge controls usable
Native browser pages could cover application dialogs and overlapping menus
or notifications. Suspend only the viewport while covered and restore the
same active page afterward, including nested dialogs and terminal prompts.

Keep knowledge source controls at their full height, constrain long library
cards and titles, and update automatic names when switching remote targets
without overwriting edited or saved names. Restore packaged release-note
loading now that the history exceeds its previous size limit.

Add focused regressions and real Electron UI evidence. Clean up temporary
Harness fixture directories at test completion instead of accumulating them.

Release note: 修复内嵌浏览器遮挡弹窗和浮层、知识库来源选项被压缩及长名称显示异常;切换远端知识库时自动名称正确更新,并恢复更新说明显示。
2026-09-13 19:46:37 +08:00

392 lines
12 KiB
TypeScript

import { describe, expect, it, onTestFinished } from 'vitest'
import {
createBoundedNdJsonStream,
installHarnessDiagnosticGuard,
startControlledDeepSeekHarnessHost
} from './deepseek-harness-host'
import { vi } from 'vitest'
import { mkdir, mkdtemp, realpath, rm, writeFile } from 'node:fs/promises'
import type {
Agent,
CreateAgentOptions
} from '@deepseek-ai/dsh-agent'
import { GoodBuddyHarnessAttachmentStore } from './agent/goodbuddy-harness-attachment-store'
import { tmpdir } from 'node:os'
import { basename, join } from 'node:path'
async function readAllMessages(
readable: ReadableStream<unknown>
): Promise<unknown[]> {
const values: unknown[] = []
for await (const value of readable) {
values.push(value)
}
return values
}
describe('controlled DeepSeek Harness host', () => {
it('rejects unsupported endpoint protocols before Cordis starts', async () => {
await expect(
startControlledDeepSeekHarnessHost({
workspace: 'C:\\workspace',
baseUrl: 'file:///private/config',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.2-rc.1',
credentialRefs: ['GOODBUDDY_API_KEY'],
dshHome: 'C:\\controlled-dsh-home',
skillPackages: []
})
).rejects.toThrow('HTTP or HTTPS OpenAI-compatible')
})
it('suppresses console payloads instead of contaminating stdout', () => {
const restore = installHarnessDiagnosticGuard()
const originalWrite = process.stderr.write
const writes: string[] = []
process.stderr.write = ((value: string | Uint8Array) => {
writes.push(String(value))
return true
}) as typeof process.stderr.write
try {
console.log('prompt and secret must not reach protocol stdout')
expect(writes.join('')).toBe(
'DeepSeek Harness diagnostic suppressed\n'
)
expect(writes.join('')).not.toContain('secret')
} finally {
process.stderr.write = originalWrite
restore()
}
})
it('starts the controlled host with local execution providers', async () => {
const root = await realpath(
await mkdtemp(join(tmpdir(), 'goodbuddy-harness-host-'))
)
onTestFinished(() => rm(root, { recursive: true, force: true }))
const inbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const outbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const host = await startControlledDeepSeekHarnessHost({
workspace: root,
dshHome: root,
baseUrl: 'https://gateway.example/openai/v1',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'qwen-plus',
supportsImageInput: true,
harnessVersion: '0.1.2-rc.1',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
stream: {
readable: inbound.readable,
writable: outbound.writable
} as never
})
expect(host.context.fs.sandboxMode).toBeUndefined()
expect(host.context.get('sessionProjections')).toBeDefined()
expect(host.context.get('agentLoop')).toBeDefined()
expect(host.context.shell.sandboxMode).toBeUndefined()
expect(host.context.get('attachments')).toBeInstanceOf(
GoodBuddyHarnessAttachmentStore
)
expect(
host.context.shell.resolve({
command: 'echo goodbuddy-host-execution'
}).workdir
).toBe(root)
const execution = await host.context.shell.run(
host.context.shell.resolve({
command:
process.platform === 'win32'
? 'Write-Output goodbuddy-host-execution'
: 'printf goodbuddy-host-execution'
})
)
expect(execution).toMatchObject({
exitCode: 0,
timedOut: false,
aborted: false
})
expect(execution.stdout.text).toContain(
'goodbuddy-host-execution'
)
await host.dispose()
})
it('canonicalizes workspace aliases before binding the host', async () => {
const root = await realpath(
await mkdtemp(join(tmpdir(), 'goodbuddy-harness-alias-'))
)
onTestFinished(() => rm(root, { recursive: true, force: true }))
const alias = join(root, '..', basename(root))
const inbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const outbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const host = await startControlledDeepSeekHarnessHost({
workspace: alias,
dshHome: alias,
baseUrl: 'https://api.deepseek.com',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.2-rc.1',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
stream: {
readable: inbound.readable,
writable: outbound.writable
} as never
})
await host.dispose()
})
it('reports extension startup failures without failing the Host', async () => {
const root = await realpath(
await mkdtemp(join(tmpdir(), 'goodbuddy-harness-extensions-'))
)
onTestFinished(() => rm(root, { recursive: true, force: true }))
const brokenEntrypoint = join(root, 'broken.mjs')
await writeFile(
brokenEntrypoint,
'export const value = 1\n',
'utf8'
)
const inbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const outbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const host = await startControlledDeepSeekHarnessHost({
workspace: root,
dshHome: root,
baseUrl: 'https://api.deepseek.com',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.2-rc.1',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
extensionPackages: [
{
id: 'broken',
entrypoint: brokenEntrypoint,
configuration: {}
}
],
stream: {
readable: inbound.readable,
writable: outbound.writable
} as never
})
expect(host.failedExtensionIds).toEqual(['broken'])
await host.dispose()
})
it('loads only explicitly supplied Skill packages into a session scope', async () => {
const root = await realpath(
await mkdtemp(join(tmpdir(), 'goodbuddy-harness-skill-'))
)
onTestFinished(() => rm(root, { recursive: true, force: true }))
const skillDirectory = join(root, 'web-3d-game')
await mkdir(skillDirectory)
await writeFile(
join(skillDirectory, 'SKILL.md'),
[
'---',
'name: web-3d-game',
'description: Build a playable browser 3D game.',
'---',
'',
'# Web 3D game',
'',
'Create and validate a playable project.'
].join('\n'),
'utf8'
)
const inbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const outbound = new TransformStream<
Record<string, unknown>,
Record<string, unknown>
>()
const host = await startControlledDeepSeekHarnessHost({
workspace: root,
dshHome: root,
baseUrl: 'https://api.deepseek.com',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.2-rc.1',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [
{ id: 'web-3d-game', directory: skillDirectory }
],
stream: {
readable: inbound.readable,
writable: outbound.writable
} as never
})
let createdContext: typeof host.context | undefined
let createdAgent: Agent | undefined
const create = vi
.spyOn(host.context.agents, 'create')
.mockImplementation(async (options: CreateAgentOptions) => {
const agentContext = host.context.extend({
isolate: ['skills', 'tools']
})
createdContext = agentContext
await options.setup?.(agentContext)
const agent = {
options: options.agentOptions ?? {},
session: {
id: options.sessionId,
header: { cwd: options.meta?.cwd ?? root },
events: [],
append: vi.fn()
},
ctx: agentContext,
cancel: vi.fn()
}
createdAgent = agent as never
return {
agent,
dispose: async () => {
await agentContext.fiber.dispose()
}
} as never
})
const api = (
host.controlPlane as unknown as {
createAgentApi(): {
newSession(params: {
cwd: string
mcpServers: never[]
}): Promise<{ sessionId: string }>
}
}
).createAgentApi()
const session = await api.newSession({
cwd: root,
mcpServers: []
})
expect(session.sessionId).toBeTruthy()
expect(
(
await createdContext!.skills.list({
cwd: root,
scope: createdAgent
})
).map((skill) => skill.name)
).toEqual(['web-3d-game'])
expect(
createdContext!.tools
.schemas(createdAgent)
.map((tool) => tool.name)
).toContain('skill')
const loadedSkill = await createdContext!.tools.execute({
callId: 'skill-call',
name: 'skill',
arguments: { name: 'web-3d-game' },
agent: createdAgent,
signal: new AbortController().signal
} as never)
expect(loadedSkill).toMatchObject({
isError: false,
value: {
name: 'web-3d-game',
content: expect.stringContaining(
'Create and validate a playable project.'
)
}
})
expect(create).toHaveBeenCalledTimes(1)
expect(create).toHaveBeenCalledWith(
expect.objectContaining({
agentOptions: {
provider: 'goodbuddy',
model: 'deepseek-test'
}
})
)
const assembly = await createdContext!.systemPrompt.assemble({
agent: createdAgent,
scope: createdAgent
})
expect(
assembly.sections.find(
(section) =>
section.name === 'goodbuddy:controlled-execution'
)?.text
).toContain('create or update the requested workspace files promptly')
await host.dispose()
})
it('frames fragmented and coalesced ACP messages individually', async () => {
const inbound = new TransformStream<Uint8Array, Uint8Array>()
const outbound = new TransformStream<Uint8Array, Uint8Array>()
const stream = createBoundedNdJsonStream(
outbound.writable,
inbound.readable,
24
)
const reading = readAllMessages(stream.readable)
const writer = inbound.writable.getWriter()
const encoder = new TextEncoder()
await writer.write(encoder.encode('{"text":"你'))
await writer.write(
encoder.encode('好"}\n{"value":"1234567890"}\n')
)
await writer.close()
await expect(reading).resolves.toEqual([
{ text: '你好' },
{ value: '1234567890' }
])
})
it('rejects oversized ACP frames at EOF in both directions', async () => {
const inbound = new TransformStream<Uint8Array, Uint8Array>()
const outbound = new TransformStream<Uint8Array, Uint8Array>()
const stream = createBoundedNdJsonStream(
outbound.writable,
inbound.readable,
8
)
const reading = readAllMessages(stream.readable)
const inputWriter = inbound.writable.getWriter()
await inputWriter.write(
new TextEncoder().encode('{"value":"too large"}')
)
await inputWriter.close()
await expect(reading).rejects.toThrow('input frame exceeds')
const outputWriter = stream.writable.getWriter()
await expect(
outputWriter.write({ value: 'too large' } as never)
).rejects.toThrow('output frame exceeds')
})
})