feat: expand multimodal and knowledge workflows

This commit is contained in:
lofyer
2026-08-10 21:25:47 +08:00
parent 0fab985f28
commit ad79659308
38 changed files with 3036 additions and 2416 deletions
+6 -1
View File
@@ -19,8 +19,13 @@ export const builtinMcpServers = [
id: 'knowledge-base',
name: '知识库 MCP',
description:
'搜索当前对话明确选择的知识库,返回可核验的来源与证据引用。',
'列出并搜索当前对话明确选择的知识库,返回可核验的来源与证据引用。',
tools: [
{
name: 'knowledge_list',
description: '列出当前对话已授权的知识库及其说明。',
access: 'read'
},
{
name: 'knowledge_search',
description: '搜索当前对话已授权的知识库并返回来源引用。',
+37
View File
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest'
import {
maximumPastedImageBytes,
pastedImageInputSchema
} from './contracts'
describe('context contracts', () => {
it('accepts bounded pasted image bytes in supported formats', () => {
expect(
pastedImageInputSchema.safeParse({
data: Uint8Array.from([0x89, 0x50, 0x4e, 0x47]),
mimeType: 'image/png'
}).success
).toBe(true)
})
it('rejects empty, oversized, and unsupported pasted images', () => {
expect(
pastedImageInputSchema.safeParse({
data: new Uint8Array(),
mimeType: 'image/png'
}).success
).toBe(false)
expect(
pastedImageInputSchema.safeParse({
data: new Uint8Array(maximumPastedImageBytes + 1),
mimeType: 'image/png'
}).success
).toBe(false)
expect(
pastedImageInputSchema.safeParse({
data: Uint8Array.from([1]),
mimeType: 'image/gif'
}).success
).toBe(false)
})
})
+24
View File
@@ -231,6 +231,7 @@ export const defaultRuntimeSettings = {
modelName: 'sonnet-5',
modelProtocol: 'anthropic-messages',
modelAuthentication: 'api-key',
supportsImageInput: false,
imageGenerationQuality: 'auto',
opencodeBaseUrl: '',
opencodeEmbedded: true,
@@ -321,6 +322,7 @@ const modelProfileInputSchema = z
.regex(/^[\w./:-]+$/, '模型名称包含不支持的字符'),
protocol: modelProtocolSchema,
authentication: modelAuthenticationSchema,
supportsImageInput: z.boolean().optional(),
imageGenerationQuality: imageGenerationQualitySchema,
apiKey: modelApiKeyUpdateSchema
})
@@ -524,6 +526,7 @@ export type ModelConnectionSettings = {
modelName: string
protocol: ModelProtocol
authentication: ModelAuthentication
supportsImageInput?: boolean
imageGenerationQuality: ImageGenerationQuality
apiKeyConfigured: boolean
credentialSource: 'none' | 'encrypted' | 'environment'
@@ -535,6 +538,7 @@ export type RuntimeSettings = {
modelName: string
modelProtocol: ModelProtocol
modelAuthentication: ModelAuthentication
supportsImageInput?: boolean
imageGenerationQuality: ImageGenerationQuality
opencodeBaseUrl: string
opencodeEmbedded: boolean
@@ -564,6 +568,23 @@ export type RuntimeSettings = {
export type ContextAttachment = ConversationAttachment
export const maximumPastedImageBytes = 12 * 1024 * 1024
export const pastedImageInputSchema = z
.object({
data: z
.instanceof(Uint8Array)
.refine((value) => value.byteLength > 0, '粘贴图片内容为空')
.refine(
(value) => value.byteLength <= maximumPastedImageBytes,
'粘贴图片不能超过 12MB'
),
mimeType: z.enum(['image/jpeg', 'image/png', 'image/webp'])
})
.strict()
export type PastedImageInput = z.infer<typeof pastedImageInputSchema>
export const windowCaptureSourceIdSchema = z
.string()
.min(1)
@@ -1169,6 +1190,9 @@ export type DesktopApi = {
}
context: {
selectFiles: () => Promise<ContextAttachment[]>
addPastedImage: (
input: PastedImageInput
) => Promise<ContextAttachment>
captureScreen: () => Promise<ContextAttachment>
listWindows: () => Promise<WindowCaptureOption[]>
captureWindow: (sourceId: string) => Promise<ContextAttachment>
+1
View File
@@ -112,6 +112,7 @@ export const ipcChannels = {
capabilitiesDefaultBrowserProfile: 'capabilities:browser-profile:default',
capabilitiesRemoveBrowserProfile: 'capabilities:browser-profile:remove',
contextSelectFiles: 'context:select-files',
contextAddPastedImage: 'context:add-pasted-image',
contextCaptureScreen: 'context:capture-screen',
contextListWindows: 'context:list-windows',
contextCaptureWindow: 'context:capture-window',