mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-08-01 16:43:37 +08:00
fix(desktop): keep image-only messages in turn order #1095
This commit is contained in:
parent
d141543794
commit
eef49d3395
@ -5559,6 +5559,56 @@ describe('chatStore history mapping', () => {
|
|||||||
expect(userMessages).toHaveLength(1)
|
expect(userMessages).toHaveLength(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('keeps an image-only replay before the assistant response', () => {
|
||||||
|
useChatStore.setState({
|
||||||
|
sessions: {
|
||||||
|
[TEST_SESSION_ID]: makeSession({
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
id: 'live-user',
|
||||||
|
type: 'user_text',
|
||||||
|
content: '',
|
||||||
|
attachments: [{
|
||||||
|
type: 'image',
|
||||||
|
name: 'screenshot.png',
|
||||||
|
data: 'data:image/png;base64,AAAA',
|
||||||
|
mimeType: 'image/png',
|
||||||
|
}],
|
||||||
|
timestamp: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'assistant-answer',
|
||||||
|
type: 'assistant_text',
|
||||||
|
content: 'The screenshot shows a repository list.',
|
||||||
|
timestamp: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
chatState: 'thinking',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
useChatStore.getState().handleServerMessage(TEST_SESSION_ID, {
|
||||||
|
type: 'user_message_replay',
|
||||||
|
content: [
|
||||||
|
'Please analyze the attached image.',
|
||||||
|
'[Image source: /Users/me/.claude/uploads/session/screenshot.png]',
|
||||||
|
].join('\n'),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(useChatStore.getState().sessions[TEST_SESSION_ID]?.messages).toMatchObject([
|
||||||
|
{
|
||||||
|
type: 'user_text',
|
||||||
|
content: '',
|
||||||
|
attachments: [{ type: 'image', name: 'screenshot.png' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'assistant_text',
|
||||||
|
content: 'The screenshot shows a repository list.',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it('dedupes a path-backed image after the server inlines it into replay content', () => {
|
it('dedupes a path-backed image after the server inlines it into replay content', () => {
|
||||||
const prompt = '检查这张截图'
|
const prompt = '检查这张截图'
|
||||||
const imagePath = 'C:\\Users\\tester\\Desktop\\screen.png'
|
const imagePath = 'C:\\Users\\tester\\Desktop\\screen.png'
|
||||||
|
|||||||
@ -3749,6 +3749,7 @@ function extractRestoredUserDisplay(text: string): RestoredUserDisplay {
|
|||||||
// ConversationService stores data-only files as `${randomUUID()}-${sanitizedName}`
|
// ConversationService stores data-only files as `${randomUUID()}-${sanitizedName}`
|
||||||
// and omits successfully inlined images from the replayed text content.
|
// and omits successfully inlined images from the replayed text content.
|
||||||
const MATERIALIZED_UPLOAD_NAME_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}-(.+)$/i
|
const MATERIALIZED_UPLOAD_NAME_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}-(.+)$/i
|
||||||
|
const IMAGE_ONLY_REPLAY_FALLBACK = 'Please analyze the attached image.'
|
||||||
|
|
||||||
function isLikelyInlineImageAttachment(attachment: UIAttachment): boolean {
|
function isLikelyInlineImageAttachment(attachment: UIAttachment): boolean {
|
||||||
if (attachment.type === 'image') return true
|
if (attachment.type === 'image') return true
|
||||||
@ -3800,12 +3801,23 @@ function replayMatchesCurrentUserMessage(
|
|||||||
const currentModelContent = (message.modelContent ?? message.content).trim()
|
const currentModelContent = (message.modelContent ?? message.content).trim()
|
||||||
if (currentModelContent === replayModelContent) return true
|
if (currentModelContent === replayModelContent) return true
|
||||||
|
|
||||||
|
const currentAttachments = message.attachments ?? []
|
||||||
|
if (
|
||||||
|
message.content.trim() === '' &&
|
||||||
|
replayDisplay.content.trim() === IMAGE_ONLY_REPLAY_FALLBACK &&
|
||||||
|
!replayDisplay.attachments?.length &&
|
||||||
|
currentAttachments.length > 0 &&
|
||||||
|
currentAttachments.every(isLikelyInlineImageAttachment)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const currentDisplay = extractRestoredUserDisplay(currentModelContent)
|
const currentDisplay = extractRestoredUserDisplay(currentModelContent)
|
||||||
if (currentDisplay.content.trim() !== replayDisplay.content.trim()) return false
|
if (currentDisplay.content.trim() !== replayDisplay.content.trim()) return false
|
||||||
|
|
||||||
return replayAttachmentsMatchCurrent(
|
return replayAttachmentsMatchCurrent(
|
||||||
replayDisplay.attachments ?? [],
|
replayDisplay.attachments ?? [],
|
||||||
message.attachments ?? [],
|
currentAttachments,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user