diff --git a/src/main/agent/create-runtime.test.ts b/src/main/agent/create-runtime.test.ts index 84cd222..7a76d15 100644 --- a/src/main/agent/create-runtime.test.ts +++ b/src/main/agent/create-runtime.test.ts @@ -80,6 +80,71 @@ describe('createAgentRuntime model compatibility', () => { await runtime.dispose() }) + it('forwards the selected profile image capability to direct runtimes', async () => { + const visionSettings = settings({ + supportsImageInput: true + }) + visionSettings.modelProfiles = visionSettings.modelProfiles.map( + (profile) => ({ + ...profile, + supportsImageInput: true + }) + ) + const fetcher = vi.fn(async () => + new Response( + [ + `data: ${JSON.stringify({ + choices: [ + { + delta: { content: 'OK' }, + finish_reason: 'stop' + } + ] + })}`, + '', + 'data: [DONE]', + '', + '' + ].join('\n'), + { + status: 200, + headers: { 'content-type': 'text/event-stream' } + } + ) + ) + vi.stubGlobal('fetch', fetcher) + const runtime = createAgentRuntime(process.cwd(), visionSettings) + + try { + const events = [] + for await (const event of runtime.run( + { + requestId: '3f496642-f47d-4e0a-8944-a32c77b0d6ef', + conversationId: 'wechat-conversation', + prompt: '描述图片', + images: [ + { + name: '微信图片.png', + mediaType: 'image/png', + data: 'aW1hZ2U=' + } + ] + }, + new AbortController().signal + )) { + events.push(event) + } + + expect(fetcher).toHaveBeenCalledOnce() + expect(events).toContainEqual( + expect.objectContaining({ type: 'done' }) + ) + } finally { + await runtime.dispose() + vi.unstubAllGlobals() + } + }) + it('shares injected browser service without runtime-owned disposal', async () => { const browserService = createBrowserService() const first = createAgentRuntime(process.cwd(), settings(), { diff --git a/src/main/agent/create-runtime.ts b/src/main/agent/create-runtime.ts index 5639727..88c007c 100644 --- a/src/main/agent/create-runtime.ts +++ b/src/main/agent/create-runtime.ts @@ -206,6 +206,10 @@ export function createAgentRuntime( settings?.modelProtocol ?? defaultRuntimeSettings.modelProtocol, authentication: modelAuthentication, + supportsImageInput: + defaultModelProfile?.supportsImageInput ?? + settings?.supportsImageInput ?? + defaultRuntimeSettings.supportsImageInput, imageGenerationQuality: defaultModelProfile?.imageGenerationQuality ?? settings?.imageGenerationQuality ?? diff --git a/src/main/agent/runtime-selection.test.ts b/src/main/agent/runtime-selection.test.ts index 1608afc..913956a 100644 --- a/src/main/agent/runtime-selection.test.ts +++ b/src/main/agent/runtime-selection.test.ts @@ -40,6 +40,7 @@ function settings( modelName: 'second-model', protocol: 'openai-chat-completions', authentication: 'none', + supportsImageInput: true, imageGenerationQuality: 'auto' }, { @@ -98,6 +99,7 @@ describe('runtime selection', () => { modelName: 'second-model', modelProtocol: 'openai-chat-completions', modelAuthentication: 'none', + supportsImageInput: true, defaultModelProfileId: secondProfileId }) expect(original.defaultModelProfileId).toBe(defaultProfileId) diff --git a/src/main/agent/runtime-selection.ts b/src/main/agent/runtime-selection.ts index 5f7c95d..477e71b 100644 --- a/src/main/agent/runtime-selection.ts +++ b/src/main/agent/runtime-selection.ts @@ -80,6 +80,7 @@ export function applyRuntimeSelection( modelName: profile.modelName, modelProtocol: profile.protocol, modelAuthentication: profile.authentication, + supportsImageInput: profile.supportsImageInput, imageGenerationQuality: profile.imageGenerationQuality ?? settings.imageGenerationQuality, apiKey: profile.apiKey,