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:
+41
-1
@@ -52,6 +52,7 @@ const harnessHostEntry =
|
||||
const harnessBundleManifest = 'out/main/package.json'
|
||||
const harnessPackageVersions = {
|
||||
'@deepseek-ai/dsh-agent': '0.1.0-rc.6',
|
||||
'@napi-rs/canvas': '1.0.3',
|
||||
'node-pty': '1.1.0'
|
||||
}
|
||||
const koffiVersion = '3.1.4'
|
||||
@@ -60,6 +61,7 @@ const harnessLicenseFiles = [
|
||||
'deepseek-cordis-MIT.txt',
|
||||
'deepseek-harness-MIT.txt',
|
||||
'koffi-MIT.txt',
|
||||
'napi-rs-canvas-MIT.txt',
|
||||
'node-pty-MIT.txt'
|
||||
]
|
||||
const portableRequiredFiles = [
|
||||
@@ -505,7 +507,14 @@ function targetHarnessPaths(options) {
|
||||
macos: `darwin_${options.arch}/koffi.node`,
|
||||
linux: `linux_${options.arch}/koffi.node`
|
||||
}[options.platform]
|
||||
const canvasTarget = {
|
||||
windows: `win32-${options.arch}-msvc`,
|
||||
macos: `darwin-${options.arch}`,
|
||||
linux: `linux-${options.arch}-gnu`
|
||||
}[options.platform]
|
||||
return {
|
||||
canvasPackage: `@napi-rs/canvas-${canvasTarget}`,
|
||||
canvasBinary: `skia.${canvasTarget}.node`,
|
||||
koffiPackage,
|
||||
koffiBinary,
|
||||
nodePtyBinary:
|
||||
@@ -860,6 +869,18 @@ function verifyHarnessPackage(
|
||||
`${target.koffiPackage} 版本错误:期望 ${koffiVersion},实际 ${String(targetKoffiManifest.version)}`
|
||||
)
|
||||
}
|
||||
const targetCanvasManifest = readJson(
|
||||
`node_modules/${target.canvasPackage}/package.json`,
|
||||
`${target.canvasPackage} 元数据`
|
||||
)
|
||||
if (
|
||||
targetCanvasManifest.version !==
|
||||
harnessPackageVersions['@napi-rs/canvas']
|
||||
) {
|
||||
throw new Error(
|
||||
`${target.canvasPackage} 版本错误:期望 ${harnessPackageVersions['@napi-rs/canvas']},实际 ${String(targetCanvasManifest.version)}`
|
||||
)
|
||||
}
|
||||
|
||||
const ptyBinary = join(
|
||||
unpackedRoot,
|
||||
@@ -873,6 +894,12 @@ function verifyHarnessPackage(
|
||||
...target.koffiPackage.split('/'),
|
||||
...target.koffiBinary.split('/')
|
||||
)
|
||||
const canvasBinary = join(
|
||||
unpackedRoot,
|
||||
'node_modules',
|
||||
...target.canvasPackage.split('/'),
|
||||
target.canvasBinary
|
||||
)
|
||||
assertBinaryArchitecture(
|
||||
ptyBinary,
|
||||
options.arch,
|
||||
@@ -892,9 +919,17 @@ function verifyHarnessPackage(
|
||||
'DeepSeek Harness Koffi 元数据',
|
||||
statAsarFile
|
||||
)
|
||||
const canvasMetadata = asarEntryMetadata(
|
||||
asarPath,
|
||||
entries,
|
||||
`node_modules/${target.canvasPackage}/${target.canvasBinary}`,
|
||||
'DeepSeek Harness Canvas 元数据',
|
||||
statAsarFile
|
||||
)
|
||||
for (const [metadata, description] of [
|
||||
[nodePtyMetadata, 'DeepSeek Harness node-pty'],
|
||||
[koffiMetadata, 'DeepSeek Harness Koffi']
|
||||
[koffiMetadata, 'DeepSeek Harness Koffi'],
|
||||
[canvasMetadata, 'DeepSeek Harness Canvas']
|
||||
]) {
|
||||
if (!('unpacked' in metadata) || !metadata.unpacked) {
|
||||
throw new Error(`${description}未从 ASAR 解包`)
|
||||
@@ -905,6 +940,11 @@ function verifyHarnessPackage(
|
||||
options.arch,
|
||||
'DeepSeek Harness Koffi'
|
||||
)
|
||||
assertBinaryArchitecture(
|
||||
canvasBinary,
|
||||
options.arch,
|
||||
'DeepSeek Harness Canvas'
|
||||
)
|
||||
|
||||
if (options.platform === 'darwin') {
|
||||
const helper = join(
|
||||
|
||||
@@ -17,8 +17,9 @@ const {
|
||||
const { app, utilityProcess } = require('electron/main')
|
||||
|
||||
const protocol = 'goodbuddy.deepseek-harness.control'
|
||||
const version = 1
|
||||
const controlVersion = 2
|
||||
const byteProtocol = 'goodbuddy.deepseek-harness.byte-stream'
|
||||
const byteProtocolVersion = 1
|
||||
const configuredHostPath =
|
||||
process.env.GOODBUDDY_HARNESS_SMOKE_HOST
|
||||
const hostPath = configuredHostPath
|
||||
@@ -132,12 +133,12 @@ async function run() {
|
||||
child.on('message', (message) => {
|
||||
if (
|
||||
message?.protocol === protocol &&
|
||||
message.version === version &&
|
||||
message.version === controlVersion &&
|
||||
message.type === 'ready'
|
||||
) {
|
||||
child.postMessage({
|
||||
protocol: byteProtocol,
|
||||
version,
|
||||
version: byteProtocolVersion,
|
||||
type: 'data',
|
||||
stream: 'stdin',
|
||||
seq: 0,
|
||||
@@ -147,7 +148,7 @@ async function run() {
|
||||
}
|
||||
if (
|
||||
message?.protocol === byteProtocol &&
|
||||
message.version === version &&
|
||||
message.version === byteProtocolVersion &&
|
||||
message.type === 'ack' &&
|
||||
message.stream === 'stdin' &&
|
||||
message.seq === 0
|
||||
@@ -158,7 +159,7 @@ async function run() {
|
||||
}
|
||||
if (
|
||||
message?.protocol === protocol &&
|
||||
message.version === version &&
|
||||
message.version === controlVersion &&
|
||||
message.type === 'fatal'
|
||||
) {
|
||||
finish('fatal', String(message.code))
|
||||
@@ -172,7 +173,7 @@ async function run() {
|
||||
})
|
||||
child.postMessage({
|
||||
protocol,
|
||||
version,
|
||||
version: controlVersion,
|
||||
type: 'start',
|
||||
config: {
|
||||
workspace,
|
||||
@@ -181,11 +182,12 @@ async function run() {
|
||||
api: 'openai-completions',
|
||||
provider: 'goodbuddy',
|
||||
model: 'qwen-plus',
|
||||
supportsImageInput: false,
|
||||
harnessVersion: '0.1.0-rc.6',
|
||||
credentialRefs: ['GOODBUDDY_HARNESS_MODEL_API_KEY'],
|
||||
skillPackages: [],
|
||||
extensionPackages: [],
|
||||
maxFrameBytes: 1024 * 1024
|
||||
maxFrameBytes: 8 * 1024 * 1024
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user