review: format check precedes limits, INVALID_IMAGE/IMAGE_TYPE_MISMATCH as format copy, tile-sized retry control
This commit is contained in:
@@ -38,6 +38,11 @@ export function attachmentErrorText(
|
||||
case 'MODEL_DOES_NOT_SUPPORT_IMAGES': return t('image.modelUnsupported')
|
||||
case 'SUBAGENT_IMAGE_UNSUPPORTED': return t('image.subagentUnsupported')
|
||||
case 'IMAGE_TOO_MANY_PIXELS': return t('image.tooManyPixels')
|
||||
// Undecodable bytes or a declared type its bytes contradict: solvable by
|
||||
// replacing or re-exporting the file, so it reads as a format problem.
|
||||
case 'INVALID_IMAGE':
|
||||
case 'IMAGE_TYPE_MISMATCH':
|
||||
return t('image.unsupportedType')
|
||||
case 'TOO_MANY_IMAGES':
|
||||
if (limits !== undefined) return t('image.tooMany', { count: limits.maxImagesPerMessage })
|
||||
break
|
||||
|
||||
@@ -425,6 +425,12 @@ export function InputBar({
|
||||
if (addImages === undefined || files.length === 0) return
|
||||
const rejected = ((): string | null => {
|
||||
if (imageLimits !== undefined) {
|
||||
// Format precedes limits (DeepSeek Chat's filter order): a batch with
|
||||
// a non-image must announce the format problem, not a count or size
|
||||
// it could never pass anyway — addImages rejects it authoritatively.
|
||||
if (files.some(file => !(imageLimits.mediaTypes as readonly string[]).includes(file.type))) {
|
||||
return addImages(files)
|
||||
}
|
||||
if (attachments.length + files.length > imageLimits.maxImagesPerMessage) {
|
||||
return t('image.tooMany', { count: imageLimits.maxImagesPerMessage })
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ describe('attachment rejection copy', () => {
|
||||
expect(attachmentErrorText(t, 'MODEL_DOES_NOT_SUPPORT_IMAGES')).toBe('当前模型不支持图片,请切换支持图片的模型')
|
||||
expect(attachmentErrorText(t, 'SUBAGENT_IMAGE_UNSUPPORTED')).toBe('子智能体会话暂不支持图片')
|
||||
expect(attachmentErrorText(t, 'IMAGE_TOO_MANY_PIXELS')).toBe('图片分辨率过大,请压缩后重试')
|
||||
expect(attachmentErrorText(t, 'INVALID_IMAGE')).toBe('仅支持 PNG、JPG、WebP、GIF 格式的图片')
|
||||
expect(attachmentErrorText(t, 'IMAGE_TYPE_MISMATCH')).toBe('仅支持 PNG、JPG、WebP、GIF 格式的图片')
|
||||
expect(attachmentErrorText(t, 'TOO_MANY_IMAGES', limits)).toBe('一条消息最多添加 20 张图片')
|
||||
expect(attachmentErrorText(t, 'IMAGE_TOO_LARGE', limits)).toBe('单张图片不能超过 10MB')
|
||||
expect(attachmentErrorText(t, 'IMAGES_TOO_LARGE', limits)).toBe('图片总大小超过 100MB,请移除部分图片')
|
||||
|
||||
@@ -297,6 +297,28 @@ describe('image draft rail', () => {
|
||||
expect(within.view.queryByRole('alert')).toBeNull()
|
||||
})
|
||||
|
||||
it('announces the format problem before any limit when the batch holds a non-image', () => {
|
||||
const addImages = vi.fn(() => '仅支持 PNG、JPG、WebP、GIF 格式的图片')
|
||||
const { view } = bench({
|
||||
addImages,
|
||||
imageLimits: {
|
||||
maxImageBytes: 8,
|
||||
maxImagesPerMessage: 1,
|
||||
maxMessageImageBytes: 8,
|
||||
maxImagePixels: 40_000_000,
|
||||
mediaTypes: ['image/png'] as const,
|
||||
},
|
||||
})
|
||||
// Oversized AND over-count AND wrong type: the format rejection wins.
|
||||
const files = [
|
||||
new File([new ArrayBuffer(64)], 'a.pdf', { type: 'application/pdf' }),
|
||||
new File([new ArrayBuffer(64)], 'b.pdf', { type: 'application/pdf' }),
|
||||
]
|
||||
fireEvent.drop(document.body, { dataTransfer: { types: ['Files'], files, dropEffect: 'none' } })
|
||||
expect(addImages).toHaveBeenCalledWith(files)
|
||||
expect(view.getByRole('alert').textContent).toContain('仅支持 PNG、JPG、WebP、GIF 格式的图片')
|
||||
})
|
||||
|
||||
it('shows the projected limits in the drop overlay desc line', () => {
|
||||
const { view } = bench({
|
||||
addImages: vi.fn(() => null),
|
||||
|
||||
Reference in New Issue
Block a user