feat(tasks): assign folder='Tasks' at creation + backfill migration (#2834)

* feat: assign folder='Tasks' to task sessions at creation

Task sessions (LLM, action, research) now set folder='Tasks' on their
DbSession row, matching the pattern used by the Assistant folder. This
enables sidebar lens filtering without changing existing session
behaviour.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add backfill script for task session folders

One-shot script to set folder='Tasks' on existing [Task]/[Research]
sessions that predate the folder assignment in task_scheduler.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: replace standalone backfill script with automatic migration

Convert scripts/backfill_task_folders.py into _migrate_backfill_task_folders()
in core/database.py, called from init_db(). The migration is idempotent (only
touches rows where folder IS NULL/empty) and runs automatically on upgrade,
so operators no longer need a manual step to tag pre-existing task sessions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
danielroytel
2026-06-07 23:33:17 +10:00
committed by GitHub
parent 04d6a5ccaa
commit 5d3e3c7053
3 changed files with 57 additions and 0 deletions
+27
View File
@@ -1631,6 +1631,33 @@ def init_db():
_migrate_encrypt_email_passwords()
_migrate_encrypt_signatures()
_migrate_encrypt_endpoint_keys()
_migrate_backfill_task_folders()
def _migrate_backfill_task_folders():
"""Backfill folder='Tasks' on pre-existing task/research sessions.
Sessions created by the task scheduler (LLM tasks, action tasks, research
runs) now set folder='Tasks' at creation time. This migration tags any
older sessions that predate that assignment. Idempotent — only touches
rows where folder is NULL or empty and the title matches known prefixes.
"""
try:
with engine.connect() as conn:
cols = [r[1] for r in conn.execute(text("PRAGMA table_info(sessions)"))]
if "folder" not in cols:
return
res = conn.execute(text(
"UPDATE sessions SET folder = 'Tasks' "
"WHERE (folder IS NULL OR folder = '') "
"AND (name LIKE '[Task] %' OR name LIKE '[Research] %')"
))
conn.commit()
if res.rowcount:
logging.getLogger(__name__).info(
f"Backfilled folder='Tasks' on {res.rowcount} task/research sessions")
except Exception as e:
logging.getLogger(__name__).warning(f"task folder backfill: {e}")
def _migrate_chat_messages_fts():
+3
View File
@@ -1315,6 +1315,7 @@ class TaskScheduler:
endpoint_url=endpoint_url,
model=model,
owner=task.owner,
folder="Tasks",
created_at=_utcnow(),
updated_at=_utcnow(),
)
@@ -1463,6 +1464,7 @@ class TaskScheduler:
endpoint_url=endpoint_url or "",
model=model_name or "",
owner=task.owner,
folder="Tasks",
created_at=_utcnow(),
updated_at=_utcnow(),
)
@@ -1755,6 +1757,7 @@ class TaskScheduler:
endpoint_url=endpoint_url,
model=model,
owner=task.owner,
folder="Tasks",
created_at=_utcnow(),
updated_at=_utcnow(),
)
+27
View File
@@ -0,0 +1,27 @@
"""Task sessions must be assigned folder='Tasks' at creation time."""
import inspect
from src.task_scheduler import TaskScheduler
def test_llm_task_session_gets_tasks_folder():
"""_execute_llm_task must create sessions with folder='Tasks'."""
source = inspect.getsource(TaskScheduler._execute_llm_task)
assert 'folder="Tasks"' in source or "folder='Tasks'" in source, (
"LLM task session creation must set folder='Tasks'"
)
def test_action_task_session_gets_tasks_folder():
"""_deliver_task_result must create sessions with folder='Tasks'."""
source = inspect.getsource(TaskScheduler._deliver_task_result)
assert 'folder="Tasks"' in source or "folder='Tasks'" in source, (
"Action task session delivery must set folder='Tasks'"
)
def test_research_task_session_gets_tasks_folder():
"""_execute_research_task must create sessions with folder='Tasks'."""
source = inspect.getsource(TaskScheduler._execute_research_task)
assert 'folder="Tasks"' in source or "folder='Tasks'" in source, (
"Research task session creation must set folder='Tasks'"
)