fix: enforce task-wait checkpoint lifecycle and stop UI probe from rescanning tasks table

A company-mode review left a pending task_user_input checkpoint behind: the
runtime carried the paused work item forward via approval-card grants and a
fresh review attempt without ever replying through the engine checkpoint. The
orphan row then captured the user's next chat message and resumed through the
deprecated multi-agent path with an empty task list, returning an empty reply.

Invariants added:
- write side: when a task settles (done/failed/cancelled) its pending
  task_user_input/task_peer_wait checkpoints are superseded
- read side: checkpoint matching lazily resolves rows whose task settled or
  whose linked work item reached a terminal phase (heals existing dirty DBs)
- resume: the primary task is always part of the resumed set; the
  MULTI_AGENT/COMPANY_MODE value-alias no longer routes company checkpoints
  into _execute_multi_agent (which silently returned "" on empty task lists)

Perf: get_latest_pending_checkpoint_for_session is called per task on every
UI sync tick, and its parent-session resolution loaded and JSON-parsed the
entire tasks table each time (24MB with inline artifact blobs) — a full core
pegged at 100% and the event loop starved so replies never surfaced. Now a
no-live-checkpoints fast path returns immediately, and the resolution uses a
targeted session_id query backed by a new tasks(session_id) index.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
LZH-YS1998
2026-07-07 19:59:26 +08:00
parent 47e9b2c488
commit d502d66c60
3 changed files with 406 additions and 13 deletions
+19
View File
@@ -1620,6 +1620,7 @@ class OPCStore:
CREATE INDEX IF NOT EXISTS idx_tasks_project_status_created ON tasks(project_id, status, created_at);
CREATE INDEX IF NOT EXISTS idx_tasks_project_priority_created ON tasks(project_id, priority, created_at);
CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_id);
CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id);
CREATE INDEX IF NOT EXISTS idx_messages_task ON agent_messages(task_id);
CREATE INDEX IF NOT EXISTS idx_messages_status ON agent_messages(status);
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON agent_messages(timestamp);
@@ -2792,6 +2793,24 @@ class OPCStore:
await self.hydrate_task_work_item_links(tasks)
return tasks
async def get_tasks_by_session_id(
self,
session_id: str,
project_id: str | None = None,
) -> list[Task]:
assert self._db
query = "SELECT * FROM tasks WHERE session_id = ?"
params: list[Any] = [session_id]
if project_id:
query += " AND project_id = ?"
params.append(project_id)
query += " ORDER BY priority ASC, created_at ASC"
async with self._db.execute(query, params) as cursor:
rows = await cursor.fetchall()
tasks = [self._row_to_task(row, cursor.description) for row in rows]
await self.hydrate_task_work_item_links(tasks)
return tasks
async def update_task_status(self, task_id: str, status: TaskStatus) -> None:
assert self._db
await self._db.execute("UPDATE tasks SET status = ? WHERE id = ?", (status.value, task_id))