fix(core): allow multi-image requests past stale capabilities

This commit is contained in:
linshen
2026-04-06 14:09:43 +08:00
parent 4e3ea11567
commit 1fe25fbd6c
2 changed files with 80 additions and 15 deletions

View File

@@ -155,21 +155,6 @@ export class ImageService implements IImageService {
this.validateInputImage(inputImage)
}
const config = await this.imageModelManager.getConfig(request.configId)
if (!config) {
throw new ImageError(IMAGE_ERROR_CODES.CONFIG_NOT_FOUND, undefined, { configId: request.configId })
}
const configModel = config.model
const staticModels = this.registry.getStaticModels(config.providerId)
const staticModel = staticModels.find(m => m.id === config.modelId)
const capabilities = configModel?.capabilities ?? staticModel?.capabilities
const modelName = configModel?.name ?? staticModel?.name ?? config.modelId
if (capabilities && !capabilities.multiImage) {
throw new ImageError(IMAGE_ERROR_CODES.MODEL_NOT_SUPPORT_MULTI_IMAGE, undefined, { modelName })
}
}
private async validateBaseRequest(request: Pick<ImageRequest, 'prompt' | 'configId' | 'count'>): Promise<void> {

View File

@@ -503,6 +503,30 @@ describe('ImageService', () => {
await expect(imageService.validateMultiImageRequest(request)).resolves.not.toThrow()
})
test('should not reject multi-image requests only because local capabilities say multiImage is unsupported', async () => {
await mockModelManager.updateConfig('test-multiimage-config', {
model: {
...(await mockModelManager.getConfig('test-multiimage-config'))!.model,
capabilities: {
text2image: true,
image2image: true,
multiImage: false,
},
},
})
const request: MultiImageRequest = {
prompt: 'merge these references into one scene',
configId: 'test-multiimage-config',
inputImages: [
{ b64: 'AAAA', mimeType: 'image/png' },
{ b64: 'BBBB', mimeType: 'image/jpeg' }
]
}
await expect(imageService.validateMultiImageRequest(request)).resolves.not.toThrow()
})
test('should reject multi-image requests with fewer than two images', async () => {
const request: MultiImageRequest = {
prompt: 'merge these references into one scene',
@@ -671,6 +695,62 @@ describe('ImageService', () => {
expect(result.metadata?.modelId).toBe('gemini-2.5-flash-image-preview')
expect(registry.getAdapter).toHaveBeenCalledWith('gemini')
})
test('should still call the adapter for multi-image generation when local capability metadata is stale', async () => {
await mockModelManager.updateConfig('test-multiimage-config', {
model: {
...(await mockModelManager.getConfig('test-multiimage-config'))!.model,
capabilities: {
text2image: true,
image2image: true,
multiImage: false,
},
},
})
const adapterGenerate = vi.fn().mockResolvedValue({
images: [{ b64: 'aGVsbG8=', mimeType: 'image/png', url: 'data:image/png;base64,aGVsbG8=' }],
})
const registry = {
getAdapter: vi.fn().mockReturnValue({
generate: adapterGenerate,
}),
getStaticModels: vi.fn().mockReturnValue([
{
id: 'gemini-2.5-flash-image-preview',
name: 'Gemini 2.5 Flash Image Preview',
providerId: 'gemini',
capabilities: { text2image: true, image2image: true, multiImage: false },
parameterDefinitions: [],
defaultParameterValues: {},
},
]),
getDynamicModels: vi.fn(),
getModels: vi.fn(),
getAllProviders: vi.fn(),
getAllStaticModels: vi.fn(),
supportsDynamicModels: vi.fn(),
validateProviderModel: vi.fn(),
} as unknown as IImageAdapterRegistry
const multiImageService = new ImageService(mockModelManager, registry)
const request: MultiImageGenerationRequest = {
prompt: 'compose 图1 and 图2 into one cinematic frame',
configId: 'test-multiimage-config',
inputImages: [
{ b64: 'AAAA', mimeType: 'image/png' },
{ b64: 'BBBB', mimeType: 'image/png' }
]
}
await expect(multiImageService.generateMultiImage(request)).resolves.toMatchObject({
metadata: {
configId: 'test-multiimage-config',
},
})
expect(adapterGenerate).toHaveBeenCalledTimes(1)
})
})
describe('Error Handling', () => {