fix: guard chat deletion and research idempotency

This commit is contained in:
snowspeeder committed 2026-10-03 08:54:08 -04:00
1 parent 2048b33799
commit fe4192c8bc
2 files changed
+55 -5

No files matched your search

+11 -2
View File
@@ -216,6 +216,14 @@ class ChatStore:
def delete_conversation(self, owner, cid):
with self.lock, self.db:
self._row('chat_conversations',owner,cid)
if self.db.execute("SELECT 1 FROM chat_runs WHERE owner=? AND conversation_id=? AND status IN ('queued','running','awaiting_approval') LIMIT 1",(owner,cid)).fetchone():
raise ChatConflict('Execution still active')
if self.db.execute("SELECT 1 FROM sqlite_master WHERE type='table' AND name='chat_transport'").fetchone():
for row in self.db.execute('SELECT metadata FROM chat_transport WHERE owner=? AND conversation_id=?',(owner,cid)):
metadata=json.loads(row['metadata'])
if metadata.get('upstream_id') and not metadata.get('remote_terminal'):
raise ChatConflict('Remote execution still active')
self.db.execute('DELETE FROM chat_transport WHERE owner=? AND conversation_id=?',(owner,cid))
self.db.execute('DELETE FROM chat_conversations WHERE id=? AND owner=?',(cid,owner))
self._change(owner,'conversation',cid)
return {'ok': True}
@@ -290,14 +298,15 @@ class ChatStore:
self.db.execute('INSERT INTO chat_messages(id,owner,conversation_id,role,content,status,run_id,created_at,position) VALUES(?,?,?,?,?,?,?,?,?)',(identity,owner,cid,role,content,status,run_id,time.time(),position))
return self._message(self._row('chat_messages',owner,identity))
def send(self, owner, cid, content, key, attachment_ids=None):
def send(self, owner, cid, content, key, attachment_ids=None, mode='normal'):
"""Atomic admission; replay returns same IDs and never creates new work."""
text(content,'content',32000); text(key,'idempotency key',200)
if attachment_ids is None: attachment_ids=[]
if not isinstance(attachment_ids,list) or len(attachment_ids)>8: raise ValueError('Invalid attachments')
for attachment_id in attachment_ids: text(attachment_id,'attachment id',128)
if len(set(attachment_ids))!=len(attachment_ids): raise ValueError('Duplicate attachments')
payload=json.dumps({'content':content,'attachment_ids':attachment_ids},sort_keys=True)
if not isinstance(mode,str) or mode not in ('normal','research'): raise ValueError('Invalid mode')
payload=json.dumps({'content':content,'attachment_ids':attachment_ids,'mode':mode},sort_keys=True)
with self.lock,self.db:
self._row('chat_conversations',owner,cid)
prior=self.db.execute('SELECT * FROM chat_idempotency WHERE owner=? AND conversation_id=? AND key=?',(owner,cid,key)).fetchone()