-
Notifications
You must be signed in to change notification settings - Fork 7
fix(client-core): keep image prompts in place after conversation reseed #464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -73,6 +73,54 @@ describe('createConversationStore', () => { | |||||||
| close(); | ||||||||
| }); | ||||||||
|
|
||||||||
| it('enriches a lossy seeded prompt with its live image instead of appending a duplicate', async () => { | ||||||||
| const { client, send, close } = await harness(); | ||||||||
| const livePrompt: AgentEvent = { | ||||||||
| type: 'user-message', | ||||||||
| messageId: 'host-prompt' as MessageId, | ||||||||
| content: [ | ||||||||
| { type: 'text', text: 'describe this image' }, | ||||||||
| { type: 'image', data: 'cG5n', mimeType: 'image/png' }, | ||||||||
| ], | ||||||||
| branchCursor: 'live-cursor', | ||||||||
| }; | ||||||||
| const reply: AgentEvent = { | ||||||||
| type: 'agent-message', | ||||||||
| messageId: 'reply' as MessageId, | ||||||||
| content: [{ type: 'text', text: 'It is a test image.' }], | ||||||||
| }; | ||||||||
| send(livePrompt); | ||||||||
| send(reply); | ||||||||
| await tick(); | ||||||||
|
|
||||||||
| const store = createConversationStore(client, sessionId, { | ||||||||
| events: [ | ||||||||
| // Some provider histories retain the prompt text but omit its image blocks. | ||||||||
| { | ||||||||
| event: { | ||||||||
| type: 'user-message', | ||||||||
| messageId: 'provider-prompt' as MessageId, | ||||||||
| content: [{ type: 'text', text: 'describe this image' }], | ||||||||
| branchCursor: 'provider-cursor', | ||||||||
| }, | ||||||||
| }, | ||||||||
| { event: reply }, | ||||||||
| ], | ||||||||
| uptoSeq: 2, | ||||||||
| }); | ||||||||
|
|
||||||||
| const messages = store.getSnapshot().items.filter((item) => item.kind === 'message'); | ||||||||
| expect(messages).toHaveLength(2); | ||||||||
| expect(messages[0]).toMatchObject({ | ||||||||
| id: 'provider-prompt', | ||||||||
| role: 'user', | ||||||||
| blocks: livePrompt.content, | ||||||||
| branchCursor: 'provider-cursor', | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The seed row here has no Giving the seed row a
Suggested change
|
||||||||
| }); | ||||||||
| expect(messages[1]).toMatchObject({ id: 'reply', role: 'assistant' }); | ||||||||
| close(); | ||||||||
| }); | ||||||||
|
|
||||||||
| it('consumes only one matching seed row for repeated prompt content', async () => { | ||||||||
| const { client, send, close } = await harness(); | ||||||||
| send(userText('repeat', 'host-1')); | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This advance registers a second
entriesrow under the seed'smessageId, which breaksconversation-rewindfor enriched prompts.createConversationBuilder.advanceappends every event to a replay log, and the rewind handler scans that log backwards for the first matchinguser-messageid (conversation.ts:211-219) — so the cut lands on this enriched row instead of the seed row, leaving the rewound prompt and the agent reply between them on screen.I reproduced it: with a lossy seed the timeline after a rewind + replacement is
['provider-prompt', 'reply', 'replacement']; with a faithful seed (so the fallback never fires) the same sequence correctly yields['replacement'].Technical details