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
@@ -0,0 +1,133 @@
// @vitest-environment node
import { Context } from '@deepseek-ai/cordis'
import { createCanvas } from '@napi-rs/canvas'
import { describe, expect, it } from 'vitest'
import { GoodBuddyHarnessAttachmentStore } from './goodbuddy-harness-attachment-store'
const canvas = createCanvas(1, 1)
const transparentPng = canvas.toBuffer('image/png')
const jpeg = canvas.toBuffer('image/jpeg')
const secondPng = createCanvas(2, 1).toBuffer('image/png')
describe('GoodBuddy Harness attachment store', () => {
it('decodes, stores, verifies, and releases inline images', async () => {
const store = new GoodBuddyHarnessAttachmentStore(new Context())
const input = {
data: transparentPng,
mediaType: 'image/png' as const,
name: '..\\screenshots\\reference.png'
}
const first = await store.saveImage(input)
const second = await store.saveImage(input)
expect(first).toEqual(second)
expect(first).toMatchObject({
mediaType: 'image/png',
bytes: transparentPng.byteLength,
width: 1,
height: 1,
name: 'reference.png'
})
const stored = await store.readImage(first)
expect(stored.ref).toBe(first)
expect(Buffer.from(stored.data).equals(transparentPng)).toBe(true)
store.releaseImage(first)
await expect(store.readImage(first)).resolves.toBeDefined()
store.releaseImage(second)
await expect(store.readImage(first)).rejects.toMatchObject({
code: 'NOT_FOUND'
})
const jpegRef = await store.saveImage({
data: jpeg,
mediaType: 'image/jpeg'
})
expect(jpegRef).toMatchObject({
mediaType: 'image/jpeg',
bytes: jpeg.byteLength,
width: 1,
height: 1
})
})
it('rejects mismatched, malformed, and over-capacity images', async () => {
const store = new GoodBuddyHarnessAttachmentStore(new Context(), {
maxStoredImages: 1
})
await expect(
store.saveImage({
data: transparentPng,
mediaType: 'image/jpeg'
})
).rejects.toMatchObject({ code: 'INVALID_IMAGE' })
await expect(
store.saveImage({
data: Buffer.from([
0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a
]),
mediaType: 'image/png'
})
).rejects.toMatchObject({ code: 'INVALID_IMAGE' })
const corruptPng = Buffer.from(transparentPng)
corruptPng[corruptPng.length - 8] =
(corruptPng[corruptPng.length - 8] ?? 0) ^ 1
await expect(
store.saveImage({
data: corruptPng,
mediaType: 'image/png'
})
).rejects.toMatchObject({ code: 'INVALID_IMAGE' })
await store.saveImage({
data: transparentPng,
mediaType: 'image/png'
})
await expect(
store.saveImage({
data: secondPng,
mediaType: 'image/png'
})
).rejects.toMatchObject({ code: 'STORAGE_LIMIT' })
})
it('does not retain a partial batch when capacity is exceeded', async () => {
const store = new GoodBuddyHarnessAttachmentStore(new Context(), {
maxStoredImages: 1
})
await expect(
store.saveImages([
{ data: transparentPng, mediaType: 'image/png' },
{ data: jpeg, mediaType: 'image/jpeg' }
])
).rejects.toMatchObject({ code: 'STORAGE_LIMIT' })
await expect(
store.saveImage({
data: jpeg,
mediaType: 'image/jpeg'
})
).resolves.toMatchObject({ mediaType: 'image/jpeg' })
})
it('bounds aggregate decoded pixels before retaining a batch', async () => {
const store = new GoodBuddyHarnessAttachmentStore(new Context(), {
maxBatchImagePixels: 1
})
const input = {
data: transparentPng,
mediaType: 'image/png' as const
}
await expect(
store.saveImages([input, input])
).rejects.toMatchObject({ code: 'INVALID_IMAGE' })
await expect(store.saveImage(input)).resolves.toMatchObject({
width: 1,
height: 1
})
})
})