GoodBuddy Agents / Validate Agent source (push) Canceled after 0s
GoodBuddy Agents / Build Linux arm64 Agent (push) Canceled after 0s
GoodBuddy Agents / Build Linux x64 Agent (push) Canceled after 0s
GoodBuddy Agent Release / Authorize Agent release (push) Canceled after 0s
Cross-platform packages / Validate source (push) Canceled after 0s
Cross-platform packages / windows x64 (push) Canceled after 0s
Cross-platform packages / Publish GitHub and OSS release (push) Canceled after 0s
GoodBuddy Agent Release / Build Linux arm64 compound package (push) Canceled after 0s
GoodBuddy Agent Release / Build Linux x64 compound package (push) Canceled after 0s
GoodBuddy Agent Release / Sign cumulative Agent catalog (push) Canceled after 0s
GoodBuddy Agent Release / Publish Agent to GitHub and OSS (push) Canceled after 0s
Cross-platform packages / Authorize desktop packaging (push) Canceled after 0s
Cross-platform packages / linux arm64 (push) Canceled after 0s
Cross-platform packages / macos arm64 (push) Canceled after 0s
Cross-platform packages / windows arm64 (push) Canceled after 0s
Cross-platform packages / linux x64 (push) Canceled after 0s
Cross-platform packages / macos x64 (push) Canceled after 0s
The desktop runtime still pinned the rc.6 Harness family. It now uses the coherent rc.8 package set, adapts the revised image-attachment limits and error contract, and derives release checks from the lockfile. The managed SSH Agent package remains unchanged. Release note: 内置 DeepSeek Harness 已升级至 0.1.0-rc.8,并适配新版图片附件限制;托管 SSH Agent 包不受影响。
165 lines
4.7 KiB
TypeScript
165 lines
4.7 KiB
TypeScript
// @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')
|
|
const overwidePng = createCanvas(8_193, 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)
|
|
await expect(
|
|
store.readImage({
|
|
...first,
|
|
width: first.width + 1
|
|
})
|
|
).rejects.toMatchObject({ code: 'INVALID_ATTACHMENT_REF' })
|
|
|
|
store.releaseImage(first)
|
|
await expect(store.readImage(first)).resolves.toBeDefined()
|
|
store.releaseImage(second)
|
|
await expect(store.readImage(first)).rejects.toMatchObject({
|
|
code: 'ATTACHMENT_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: 'IMAGE_TYPE_MISMATCH' })
|
|
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 expect(
|
|
store.saveImage({
|
|
data: overwidePng,
|
|
mediaType: 'image/png'
|
|
})
|
|
).rejects.toMatchObject({
|
|
code: 'IMAGE_DIMENSION_TOO_LARGE'
|
|
})
|
|
|
|
await store.saveImage({
|
|
data: transparentPng,
|
|
mediaType: 'image/png'
|
|
})
|
|
await expect(
|
|
store.saveImage({
|
|
data: secondPng,
|
|
mediaType: 'image/png'
|
|
})
|
|
).rejects.toMatchObject({ code: 'ATTACHMENT_WRITE_FAILED' })
|
|
})
|
|
|
|
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: 'ATTACHMENT_WRITE_FAILED' })
|
|
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
|
|
})
|
|
})
|
|
|
|
it('enforces the upstream per-message image count', async () => {
|
|
const store = new GoodBuddyHarnessAttachmentStore(new Context())
|
|
const input = {
|
|
data: transparentPng,
|
|
mediaType: 'image/png' as const
|
|
}
|
|
|
|
await expect(
|
|
store.saveImages(
|
|
Array.from(
|
|
{ length: store.imageLimits.maxImagesPerMessage + 1 },
|
|
() => input
|
|
)
|
|
)
|
|
).rejects.toMatchObject({ code: 'TOO_MANY_IMAGES' })
|
|
})
|
|
}) |