fix: refresh conversation revision before post-run actions

This commit is contained in:
snowspeeder committed 2026-10-03 12:10:14 -04:00
1 parent 0c57217ad9
commit 6bb2f53dce
2 files changed
+27 -4

No files matched your search

+24 -1
View File
@@ -36,6 +36,8 @@ def fixture(page, replay=False):
streams.append(r.request.url)
message = 'id: 1\nevent: message\ndata: {"message":{"id":"a1","role":"assistant","content":"## Answer\\n| Name | Value |\\n| --- | --- |\\n| <img src=x> | **safe** |\\n**Safe** and `clear`.\\n<script>window.injected=true</script>\\n[bad](javascript:alert(1))","status":"completed"}}\n\n'
done = 'id: 2\nevent: done\ndata: {"run":{"id":"r1","status":"completed"}}\n\n'
if not replay or len(streams) > 1:
for c in conversations.values(): c['revision'] += 1
r.fulfill(body=message if replay and len(streams) == 1 else message + done, content_type='text/event-stream'); return
elif path.endswith('/messages'):
cid = path.split('/')[3]; message = dict(id='u2', role='user', content=body['content'], status='completed'); messages[cid].append(message)
@@ -46,7 +48,10 @@ def fixture(page, replay=False):
elif path.startswith('/api/conversations/'):
cid = path.split('/')[3]
if method == 'DELETE': del conversations[cid]; data = {'ok':True}
elif method == 'PATCH': conversations[cid].update(body); conversations[cid]['revision'] += 1; data = {'conversation':conversations[cid]}
elif method == 'PATCH':
if body['revision'] != conversations[cid]['revision']:
r.fulfill(status=409,json={'error':'Stale revision'}); return
conversations[cid].update(body); conversations[cid]['revision'] += 1; data = {'conversation':conversations[cid]}
else: data = {'conversation':conversations[cid],'messages':messages[cid],'runs':[],'next_cursor':None}
elif path == '/api/auth/logout': data = {'ok':True}
else:
@@ -203,3 +208,21 @@ def test_qualified_research_and_private_export():
assert info.value.suggested_filename.endswith('.json')
assert all('/api/conversations/' in path for method,path,body in calls if path.endswith('/export'))
browser.close()
def test_immediate_pin_after_response_uses_final_server_revision():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(); calls, streams, conversations, messages = fixture(page)
page.goto('https://hope.test/'); page.wait_for_load_state('networkidle')
page.get_by_role('button',name='A saved thought',exact=True).click()
expect(page.locator('#chatTitle')).to_have_text('A saved thought')
page.locator('#primaryInput').fill('Finish and immediately pin'); page.locator('#primarySend').click()
expect(page.locator('#chatTimeline')).to_contain_text('Answer')
page.locator('#pinConversation').click()
expect(page.locator('#pinConversation')).to_have_text('Unpin')
assert conversations['c1']['pinned'] is True
assert 'Conversation refreshed' not in page.locator('#chatNotice').inner_text()
patch = next(body for method,path,body in calls if method == 'PATCH')
assert patch['revision'] == 2
browser.close()