fix: session handling and SDK async iteration

- Add sdk_conversation_id column to track SDK conversation separately from user session_id
- Queue processor looks up SDK conversation ID for resume instead of passing user session_id
- session_id "new" stores NULL initially, gets set from SDK on completion
- Custom session_ids are preserved (not overwritten by SDK)
- Worker catches SDK process exit error after messages are collected

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-25 20:59:55 +00:00
parent 98ad65d248
commit 9b68f772f6
3 changed files with 45 additions and 21 deletions
+19 -12
View File
@@ -19,6 +19,7 @@ CREATE TABLE IF NOT EXISTS topics (
CREATE TABLE IF NOT EXISTS requests (
id TEXT PRIMARY KEY,
session_id TEXT,
sdk_conversation_id TEXT,
topic_id TEXT NOT NULL REFERENCES topics(id),
prompt TEXT NOT NULL,
model TEXT,
@@ -156,7 +157,7 @@ async def create_request(
now = _now()
if session_id == "new":
session_id = _new_id()
session_id = None
await db.execute(
"INSERT INTO requests (id, session_id, topic_id, prompt, model, summarize, status, created_at) "
@@ -246,19 +247,14 @@ async def complete_request(
db: aiosqlite.Connection,
request_id: str,
result: str,
session_id: str | None = None,
sdk_conversation_id: str | None = None,
) -> None:
now = _now()
if session_id:
await db.execute(
"UPDATE requests SET status = 'completed', result = ?, completed_at = ?, session_id = ? WHERE id = ?",
(result, now, session_id, request_id),
)
else:
await db.execute(
"UPDATE requests SET status = 'completed', result = ?, completed_at = ? WHERE id = ?",
(result, now, request_id),
)
await db.execute(
"UPDATE requests SET status = 'completed', result = ?, completed_at = ?, "
"sdk_conversation_id = ?, session_id = COALESCE(session_id, ?) WHERE id = ?",
(result, now, sdk_conversation_id, sdk_conversation_id, request_id),
)
await db.commit()
@@ -297,6 +293,17 @@ async def list_sessions(db: aiosqlite.Connection) -> list[dict]:
return [dict(row) for row in rows]
async def get_session_sdk_id(db: aiosqlite.Connection, session_id: str) -> str | None:
cursor = await db.execute(
"SELECT sdk_conversation_id FROM requests "
"WHERE session_id = ? AND status = 'completed' AND sdk_conversation_id IS NOT NULL "
"ORDER BY completed_at DESC LIMIT 1",
(session_id,),
)
row = await cursor.fetchone()
return row[0] if row else None
async def session_exists(db: aiosqlite.Connection, session_id: str) -> bool:
cursor = await db.execute(
"SELECT 1 FROM requests WHERE session_id = ? LIMIT 1", (session_id,)
+8 -2
View File
@@ -9,6 +9,7 @@ from src.backend.db.database import (
complete_request,
fail_request,
append_topic_summary,
get_session_sdk_id,
)
from src.backend.services.worker_client import WorkerClient
@@ -38,6 +39,11 @@ async def process_one(worker: WorkerClient) -> bool:
return True
model = resolve_model(req["model"], topic["model"])
# Only resume if there's a previous completed request with an SDK conversation ID
resume_id = None
if req["session_id"]:
resume_id = await get_session_sdk_id(db, req["session_id"])
finally:
await db.close()
@@ -46,7 +52,7 @@ async def process_one(worker: WorkerClient) -> bool:
prompt=req["prompt"],
system_prompt=topic["system_prompt"],
model=model,
session_id=req["session_id"],
session_id=resume_id,
)
except Exception as e:
db = await get_db()
@@ -63,7 +69,7 @@ async def process_one(worker: WorkerClient) -> bool:
db,
req["id"],
result["result"],
session_id=result.get("session_id"),
sdk_conversation_id=result.get("session_id"),
)
if req["summarize"]: