feat: add model-aware DSH image input

DeepSeek Harness previously treated every selected model as text-only. It now carries the model profile's image capability through Main, the Utility Host, ACP, and Pi-AI, rejects unsupported images before model invocation, and validates supported JPEG/PNG data in a bounded process-local attachment store.

The Composer keeps universal controls on its first row, places OpenCode and Continue controls on a dedicated responsive row, and anchors context compaction without shifting the footer. Runtime supervision ownership for future Subagents and Jobs is documented for the right sidebar.

Release note: DeepSeek Harness 现可按所选模型连接的能力安全接收 JPEG/PNG 图片;Composer 同时将 Runtime 专属选择器移到独立一行,并固定上下文压缩入口。
This commit is contained in:
mesalogo
2026-08-16 23:30:54 +08:00
parent 18263a6b23
commit b751c70d75
30 changed files with 1589 additions and 187 deletions
@@ -1,5 +1,6 @@
import { describe, expect, it, vi } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import { createCanvas } from '@napi-rs/canvas'
import type { Stream } from '@agentclientprotocol/sdk'
import { resolve } from 'node:path'
import {
@@ -9,17 +10,24 @@ import {
GoodBuddyHarnessControlPlane,
createBoundedAcpStream
} from './goodbuddy-harness-control-plane'
import { GoodBuddyHarnessAttachmentStore } from './goodbuddy-harness-attachment-store'
function controlPlane() {
return new GoodBuddyHarnessControlPlane({} as Context, {
provider: 'goodbuddy',
model: 'deepseek-test',
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: []
})
return new GoodBuddyHarnessControlPlane(
{
on: vi.fn(),
get: vi.fn()
} as unknown as Context,
{
provider: 'goodbuddy',
model: 'deepseek-test',
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: []
}
)
}
function stubAgentContext() {
@@ -123,6 +131,127 @@ function stubAgentContext() {
}
describe('GoodBuddy Harness internal control plane', () => {
it('advertises and stores only model-enabled inline image prompts', async () => {
const textOnly = controlPlane() as unknown as {
createAgentApi(): {
initialize(): Promise<{
agentCapabilities: {
promptCapabilities: { image: boolean }
}
}>
}
storePromptImages(
prompt: Array<Record<string, unknown>>
): Promise<unknown[]>
}
await expect(textOnly.createAgentApi().initialize()).resolves.toMatchObject({
agentCapabilities: {
promptCapabilities: { image: false }
}
})
await expect(
textOnly.storePromptImages([
{
type: 'image',
mimeType: 'image/png',
data: 'aW1hZ2U='
}
])
).rejects.toThrow('does not accept image input')
const storeContext = new Context()
const store = new GoodBuddyHarnessAttachmentStore(storeContext)
const ctx = {
on: vi.fn(),
get: vi.fn((name: string) =>
name === 'attachments' ? store : undefined
)
} as unknown as Context
const subject = new GoodBuddyHarnessControlPlane(ctx, {
provider: 'goodbuddy',
model: 'vision-test',
supportsImageInput: true,
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: []
}) as unknown as {
createAgentApi(): {
initialize(): Promise<{
agentCapabilities: {
promptCapabilities: { image: boolean }
}
}>
}
storePromptImages(
prompt: Array<Record<string, unknown>>
): Promise<
Array<
Parameters<GoodBuddyHarnessAttachmentStore['readImage']>[0]
>
>
releaseAttachments(
refs: Array<
Parameters<GoodBuddyHarnessAttachmentStore['readImage']>[0]
>
): void
}
const png = createCanvas(1, 1).toBuffer('image/png')
await expect(subject.createAgentApi().initialize()).resolves.toMatchObject({
agentCapabilities: {
promptCapabilities: { image: true }
}
})
const refs = await subject.storePromptImages([
{ type: 'text', text: 'describe this image' },
{
type: 'image',
mimeType: 'image/png',
data: png.toString('base64')
}
])
expect(refs).toHaveLength(1)
await expect(store.readImage(refs[0]!)).resolves.toMatchObject({
ref: expect.objectContaining({
mediaType: 'image/png',
width: 1,
height: 1
})
})
subject.releaseAttachments(refs)
await expect(store.readImage(refs[0]!)).rejects.toMatchObject({
code: 'NOT_FOUND'
})
await expect(
subject.storePromptImages([
{
type: 'image',
mimeType: 'image/png',
data: png.toString('base64'),
uri: 'https://example.com/reference.png'
}
])
).rejects.toThrow('invalid inline image')
const saveImages = vi.spyOn(store, 'saveImages')
const largeInlineData = Buffer.alloc(800 * 1024).toString(
'base64'
)
await expect(
subject.storePromptImages(
Array.from({ length: 3 }, () => ({
type: 'image' as const,
mimeType: 'image/png',
data: largeInlineData
}))
)
).rejects.toThrow('invalid inline image')
expect(saveImages).not.toHaveBeenCalled()
await storeContext.fiber.dispose()
})
it('requires a versioned handshake before privileged extensions', async () => {
const subject = controlPlane()