fix: update bundled DeepSeek Harness to rc.8
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 包不受影响。
This commit is contained in:
mesalogo
2026-08-25 23:26:43 +08:00
parent 6913e9ce16
commit 798ac814a9
21 changed files with 524 additions and 416 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ export type BundledRuntimePaths = {
}
export const bundledContinueVersion = '1.5.47'
export const bundledDeepSeekHarnessVersion = '0.1.0-rc.6'
export const bundledDeepSeekHarnessVersion = '0.1.0-rc.8'
export function resolveBundledRuntimePaths(input: {
appPath: string
@@ -329,7 +329,7 @@ function createInProcessLaunch(
provider: 'goodbuddy',
model: options.model,
supportsImageInput: options.supportsImageInput,
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: options.credentialRefs,
skillPackages: options.skillPackages,
extensionPackages: options.extensionPackages,
@@ -5,11 +5,13 @@ import {
runtimeExtensionConfigurationSchema,
runtimeExtensionIdSchema
} from '../../shared/runtime-extension-contracts'
import { bundledDeepSeekHarnessVersion } from './bundled-runtimes'
export const DEEPSEEK_HARNESS_CONTROL_PROTOCOL =
'goodbuddy.deepseek-harness.control'
export const DEEPSEEK_HARNESS_CONTROL_VERSION = 2
export const DEEPSEEK_HARNESS_HOST_VERSION = '0.1.0-rc.6'
export const DEEPSEEK_HARNESS_HOST_VERSION =
bundledDeepSeekHarnessVersion
export const DEEPSEEK_HARNESS_CREDENTIAL_REF =
'GOODBUDDY_HARNESS_MODEL_API_KEY'
export const DEEPSEEK_HARNESS_MAX_FRAME_BYTES =
@@ -156,7 +156,7 @@ function setup(
if (method === 'goodbuddy/handshake') {
return {
controlProtocolVersion: 1,
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
acpProtocolVersion: 1,
supports: {
cancellation: true,
@@ -95,7 +95,7 @@ describe.skipIf(!enabled)('DSH marketplace live E2E', () => {
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
extensionPackages: extensions,
@@ -8,6 +8,7 @@ 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 () => {
@@ -32,12 +33,18 @@ describe('GoodBuddy Harness attachment store', () => {
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: 'NOT_FOUND'
code: 'ATTACHMENT_NOT_FOUND'
})
const jpegRef = await store.saveImage({
@@ -62,7 +69,7 @@ describe('GoodBuddy Harness attachment store', () => {
data: transparentPng,
mediaType: 'image/jpeg'
})
).rejects.toMatchObject({ code: 'INVALID_IMAGE' })
).rejects.toMatchObject({ code: 'IMAGE_TYPE_MISMATCH' })
await expect(
store.saveImage({
data: Buffer.from([
@@ -81,6 +88,14 @@ describe('GoodBuddy Harness attachment store', () => {
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,
@@ -91,7 +106,7 @@ describe('GoodBuddy Harness attachment store', () => {
data: secondPng,
mediaType: 'image/png'
})
).rejects.toMatchObject({ code: 'STORAGE_LIMIT' })
).rejects.toMatchObject({ code: 'ATTACHMENT_WRITE_FAILED' })
})
it('does not retain a partial batch when capacity is exceeded', async () => {
@@ -104,7 +119,7 @@ describe('GoodBuddy Harness attachment store', () => {
{ data: transparentPng, mediaType: 'image/png' },
{ data: jpeg, mediaType: 'image/jpeg' }
])
).rejects.toMatchObject({ code: 'STORAGE_LIMIT' })
).rejects.toMatchObject({ code: 'ATTACHMENT_WRITE_FAILED' })
await expect(
store.saveImage({
data: jpeg,
@@ -130,4 +145,21 @@ describe('GoodBuddy Harness attachment store', () => {
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' })
})
})
@@ -6,6 +6,7 @@ import {
AttachmentError,
AttachmentId,
AttachmentStore,
type ImageAdmissionErrorCode,
type ImageAttachmentLimits,
type ImageAttachmentRef,
type ImageMediaType,
@@ -23,6 +24,7 @@ export const GOODBUDDY_HARNESS_IMAGE_LIMITS: ImageAttachmentLimits =
maxImagesPerMessage: 8,
maxMessageImageBytes: 2 * 1024 * 1024,
maxImagePixels: 16_000_000,
maxImageDimension: 8_192,
mediaTypes: Object.freeze([
'image/png',
'image/jpeg'
@@ -47,8 +49,12 @@ export type GoodBuddyHarnessAttachmentStoreConfig = {
maxBatchImagePixels?: number
}
function invalidImage(message: string, cause?: unknown): AttachmentError {
return new AttachmentError(message, 'INVALID_IMAGE', {
function imageError(
message: string,
code: ImageAdmissionErrorCode,
cause?: unknown
): AttachmentError {
return new AttachmentError(message, code, {
...(cause === undefined ? {} : { cause })
})
}
@@ -88,6 +94,57 @@ function matchesSignature(
)
}
function validateImageInputBounds(
input: SaveImageAttachment,
limits: ImageAttachmentLimits
): void {
if (!limits.mediaTypes.includes(input.mediaType)) {
throw imageError(
'Image media type is not supported',
'UNSUPPORTED_IMAGE_TYPE'
)
}
if (input.data.byteLength === 0) {
throw imageError('Image data is empty', 'INVALID_IMAGE')
}
if (input.data.byteLength > limits.maxImageBytes) {
throw imageError(
'Image exceeds the per-image byte limit',
'IMAGE_TOO_LARGE'
)
}
}
function validateImageDimensions(
width: number,
height: number,
limits: ImageAttachmentLimits
): void {
if (
!Number.isSafeInteger(width) ||
!Number.isSafeInteger(height) ||
width < 1 ||
height < 1
) {
throw imageError('Image dimensions are invalid', 'INVALID_IMAGE')
}
if (
width > limits.maxImageDimension ||
height > limits.maxImageDimension
) {
throw imageError(
'Image exceeds the per-side dimension limit',
'IMAGE_DIMENSION_TOO_LARGE'
)
}
if (width * height > limits.maxImagePixels) {
throw imageError(
'Image dimensions exceed the pixel limit',
'IMAGE_TOO_MANY_PIXELS'
)
}
}
function pngDimensions(data: Buffer): {
width: number
height: number
@@ -200,34 +257,26 @@ async function inspectImage(
input: SaveImageAttachment,
limits: ImageAttachmentLimits
): Promise<InspectedImage> {
if (!limits.mediaTypes.includes(input.mediaType)) {
throw invalidImage('Image media type is not supported')
}
if (
input.data.byteLength === 0 ||
input.data.byteLength > limits.maxImageBytes
) {
throw invalidImage('Image exceeds the per-image byte limit')
}
validateImageInputBounds(input, limits)
const data = Buffer.from(input.data)
if (!matchesSignature(data, input.mediaType)) {
throw invalidImage('Image media type does not match its bytes')
throw imageError(
'Image media type does not match its bytes',
'IMAGE_TYPE_MISMATCH'
)
}
const encodedDimensions =
input.mediaType === 'image/png'
? pngDimensions(data)
: jpegDimensions(data)
if (!encodedDimensions) {
throw invalidImage('Image container is malformed')
}
if (
encodedDimensions.width < 1 ||
encodedDimensions.height < 1 ||
encodedDimensions.width * encodedDimensions.height >
limits.maxImagePixels
) {
throw invalidImage('Image dimensions exceed the pixel limit')
throw imageError('Image container is malformed', 'INVALID_IMAGE')
}
validateImageDimensions(
encodedDimensions.width,
encodedDimensions.height,
limits
)
let width: number
let height: number
let loadImage: typeof import('@napi-rs/canvas')['loadImage']
@@ -237,7 +286,7 @@ async function inspectImage(
} catch (error) {
throw new AttachmentError(
'Harness image decoder is unavailable',
'DECODER_UNAVAILABLE',
'ATTACHMENT_WRITE_FAILED',
{ cause: error }
)
}
@@ -246,18 +295,21 @@ async function inspectImage(
width = image.naturalWidth || image.width
height = image.naturalHeight || image.height
} catch (error) {
throw invalidImage('Image bytes could not be decoded', error)
throw imageError(
'Image bytes could not be decoded',
'INVALID_IMAGE',
error
)
}
validateImageDimensions(width, height, limits)
if (
!Number.isSafeInteger(width) ||
!Number.isSafeInteger(height) ||
width < 1 ||
height < 1 ||
width * height > limits.maxImagePixels ||
width !== encodedDimensions.width ||
height !== encodedDimensions.height
) {
throw invalidImage('Image dimensions exceed the pixel limit')
throw imageError(
'Decoded image dimensions do not match its container',
'INVALID_IMAGE'
)
}
return { data, width, height }
}
@@ -314,6 +366,23 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
async saveImages(
inputs: readonly SaveImageAttachment[]
): Promise<ImageAttachmentRef[]> {
if (inputs.length > this.imageLimits.maxImagesPerMessage) {
throw new AttachmentError(
'Images exceed the per-message count limit',
'TOO_MANY_IMAGES'
)
}
let batchBytes = 0
for (const input of inputs) {
validateImageInputBounds(input, this.imageLimits)
batchBytes += input.data.byteLength
if (batchBytes > this.imageLimits.maxMessageImageBytes) {
throw new AttachmentError(
'Images exceed the per-message byte limit',
'IMAGES_TOO_LARGE'
)
}
}
const inspectedByContent = new Map<string, InspectedImage>()
const candidates: Array<{
input: SaveImageAttachment
@@ -322,13 +391,6 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
}> = []
let batchPixels = 0
for (const input of inputs) {
if (
!this.imageLimits.mediaTypes.includes(input.mediaType) ||
input.data.byteLength === 0 ||
input.data.byteLength > this.imageLimits.maxImageBytes
) {
throw invalidImage('Image exceeds the attachment limits')
}
const digest = createHash('sha256')
.update(input.data)
.digest('hex')
@@ -340,7 +402,10 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
}
batchPixels += inspected.width * inspected.height
if (batchPixels > this.maxBatchImagePixels) {
throw invalidImage('Images exceed the batch pixel limit')
throw imageError(
'Images exceed the batch pixel limit',
'INVALID_IMAGE'
)
}
candidates.push({
input,
@@ -370,7 +435,7 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
) {
throw new AttachmentError(
'Harness attachment store is full',
'STORAGE_LIMIT'
'ATTACHMENT_WRITE_FAILED'
)
}
return candidates.map(({ input, inspected, attachmentId }) => {
@@ -407,7 +472,7 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
if (!stored) {
throw new AttachmentError(
'Harness image attachment was not found',
'NOT_FOUND'
'ATTACHMENT_NOT_FOUND'
)
}
if (
@@ -419,8 +484,8 @@ export class GoodBuddyHarnessAttachmentStore extends AttachmentStore {
stored.ref.name !== ref.name
) {
throw new AttachmentError(
'Harness image attachment failed integrity validation',
'INTEGRITY'
'Harness image attachment reference is invalid',
'INVALID_ATTACHMENT_REF'
)
}
return {
@@ -22,7 +22,7 @@ function controlPlane() {
provider: 'goodbuddy',
model: 'deepseek-test',
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: []
@@ -75,7 +75,7 @@ function stubAgentContext() {
provider: 'goodbuddy',
model: 'deepseek-test',
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: [],
@@ -172,7 +172,7 @@ describe('GoodBuddy Harness internal control plane', () => {
model: 'vision-test',
supportsImageInput: true,
workspace: resolve('workspace'),
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
execution: { mode: 'host' },
credentialRefs: ['GOODBUDDY_API_KEY'],
skills: []
@@ -223,7 +223,7 @@ describe('GoodBuddy Harness internal control plane', () => {
subject.releaseAttachments(refs)
await expect(store.readImage(refs[0]!)).rejects.toMatchObject({
code: 'NOT_FOUND'
code: 'ATTACHMENT_NOT_FOUND'
})
await expect(
subject.storePromptImages([
@@ -13,6 +13,7 @@ import type { Context } from '@deepseek-ai/cordis'
import type { AgentHandle } from '@deepseek-ai/dsh-agent'
import {
AttachmentError,
isImageAdmissionError,
type ImageAttachmentRef,
type SaveImageAttachment
} from '@deepseek-ai/dsh-attachment'
@@ -1059,16 +1060,13 @@ export class GoodBuddyHarnessControlPlane {
return await store.saveImages(inputs)
} catch (error) {
if (error instanceof AttachmentError) {
if (error.code === 'INVALID_IMAGE') {
if (isImageAdmissionError(error)) {
throw RequestError.invalidParams(
undefined,
'invalid inline image prompt content'
)
}
if (
error.code === 'STORAGE_LIMIT' ||
error.code === 'DECODER_UNAVAILABLE'
) {
if (error.code === 'ATTACHMENT_WRITE_FAILED') {
throw RequestError.internalError(
undefined,
'Harness image attachment service is unavailable'
+2 -2
View File
@@ -192,7 +192,7 @@ describe('runtime discovery', () => {
binaryPath: '',
bundledPath: bundledScript,
bundledValidation: 'canonical-file',
bundledVersion: '0.1.0-rc.6',
bundledVersion: '0.1.0-rc.8',
binaryNames: [],
label: 'GoodBuddy DeepSeek Harness Host'
})
@@ -200,7 +200,7 @@ describe('runtime discovery', () => {
expect(detection).toMatchObject({
available: true,
path: await realpath(bundledScript),
version: '0.1.0-rc.6',
version: '0.1.0-rc.8',
source: 'bundled'
})
expect(detection.detail).toContain('内置')
+5 -5
View File
@@ -34,7 +34,7 @@ describe('controlled DeepSeek Harness host', () => {
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
dshHome: 'C:\\controlled-dsh-home',
skillPackages: []
@@ -82,7 +82,7 @@ describe('controlled DeepSeek Harness host', () => {
provider: 'goodbuddy',
model: 'qwen-plus',
supportsImageInput: true,
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
stream: {
@@ -140,7 +140,7 @@ describe('controlled DeepSeek Harness host', () => {
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
stream: {
@@ -177,7 +177,7 @@ describe('controlled DeepSeek Harness host', () => {
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
extensionPackages: [
@@ -232,7 +232,7 @@ describe('controlled DeepSeek Harness host', () => {
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [
{ id: 'web-3d-game', directory: skillDirectory }
@@ -31,7 +31,7 @@ describe.skipIf(!entrypoint)(
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
harnessVersion: '0.1.0-rc.6',
harnessVersion: '0.1.0-rc.8',
credentialRefs: ['GOODBUDDY_API_KEY'],
skillPackages: [],
extensionPackages: [
+3 -3
View File
@@ -171,7 +171,7 @@ const detectAgentRuntimes = vi.fn<
deepseekHarness: {
available: true,
path: 'bundled://deepseek-harness',
version: '0.1.0-rc.6',
version: '0.1.0-rc.8',
source: 'bundled',
detail: '内置 Harness Adapter 已就绪'
}
@@ -2665,11 +2665,11 @@ describe('SettingsPanel runtime files', () => {
)
).toHaveClass('runtime-overview__path')
expect(
within(harnessOverview).getByText('0.1.0-rc.6')
within(harnessOverview).getByText('0.1.0-rc.8')
).toBeInTheDocument()
expect(
within(harnessOverview).getByText(
'内置 DeepSeek Harness 0.1.0-rc.6 已就绪'
'内置 DeepSeek Harness 0.1.0-rc.8 已就绪'
)
).toBeInTheDocument()
expect(