diff --git a/src/main/database/schema.ts b/src/main/database/schema.ts index 1779d7de..98f3cbf9 100644 --- a/src/main/database/schema.ts +++ b/src/main/database/schema.ts @@ -365,6 +365,48 @@ export function runMigrations( version: 26, name: "add_source_run_id_for_causal_binding", sql: `ALTER TABLE documents ADD COLUMN source_run_id TEXT; ALTER TABLE knowledge_base ADD COLUMN source_run_id TEXT`, }, + { + version: 27, name: "backfill_task_sessions_from_tasks_session_json", + fn: () => { + const legacyTasks = readAll<{ + id: string; + companyId: string; + assigneeAgentId: string | null; + sessionJson: string; + sessionDisplayId: string | null; + updatedAt: string; + connectorId: string | null; + }>( + `SELECT t.id AS id, t.company_id AS companyId, t.assignee_agent_id AS assigneeAgentId, + t.session_json AS sessionJson, t.session_display_id AS sessionDisplayId, + t.updated_at AS updatedAt, a.connector_id AS connectorId + FROM tasks t + LEFT JOIN agents a ON a.id = t.assignee_agent_id + WHERE t.session_json IS NOT NULL + AND t.id NOT IN (SELECT task_id FROM task_sessions)`, + ); + for (const task of legacyTasks) { + const sessionId = randomUUID(); + db.prepare( + `INSERT OR IGNORE INTO task_sessions (id, company_id, task_id, agent_id, adapter_type, session_params_json, session_display_id, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + ).run( + sessionId, + task.companyId, + task.id, + task.assigneeAgentId ?? "unassigned", + task.connectorId ?? "unknown", + task.sessionJson, + task.sessionDisplayId, + task.updatedAt, + task.updatedAt, + ); + db.prepare( + "UPDATE tasks SET active_session_id = ? WHERE id = ? AND active_session_id IS NULL", + ).run(sessionId, task.id); + } + }, + }, ]; for (const migration of migrations) { diff --git a/src/main/database/tasks-crud.ts b/src/main/database/tasks-crud.ts index 8eb7947a..7059277d 100644 --- a/src/main/database/tasks-crud.ts +++ b/src/main/database/tasks-crud.ts @@ -185,36 +185,74 @@ export function buildTaskCrudMethods( sessionJson: Record | null, sessionDisplayId: string | null, ): void { + const ts = nowIso(); + const sessionParamsJson = sessionJson ? JSON.stringify(sessionJson) : null; + const taskRow = getDb() + .prepare( + "select company_id as companyId, assignee_agent_id as assigneeAgentId, active_session_id as activeSessionId from tasks where id = ?", + ) + .get(taskId) as + | { companyId: string; assigneeAgentId: string | null; activeSessionId: string | null } + | undefined; + if (!taskRow) throw new Error(`Task not found: ${taskId}`); + if (taskRow.activeSessionId) { + getDb() + .prepare( + "update task_sessions set session_params_json = ?, session_display_id = ?, updated_at = ? where id = ?", + ) + .run(sessionParamsJson, sessionDisplayId, ts, taskRow.activeSessionId); + return; + } + if (sessionParamsJson === null && sessionDisplayId === null) return; + const agentId = taskRow.assigneeAgentId ?? "unassigned"; + const agent = taskRow.assigneeAgentId + ? (getDb() + .prepare("select connector_id as connectorId from agents where id = ?") + .get(taskRow.assigneeAgentId) as { connectorId: string } | undefined) + : undefined; + const adapterType = agent?.connectorId ?? "unknown"; + const sessionId = randomUUID(); getDb() .prepare( - "update tasks set session_json = ?, session_display_id = ?, updated_at = ? where id = ?", + `insert into task_sessions (id, company_id, task_id, agent_id, adapter_type, session_params_json, session_display_id, created_at, updated_at) + values (?, ?, ?, ?, ?, ?, ?, ?, ?)`, ) .run( - sessionJson ? JSON.stringify(sessionJson) : null, - sessionDisplayId, - nowIso(), + sessionId, + taskRow.companyId, taskId, + agentId, + adapterType, + sessionParamsJson, + sessionDisplayId, + ts, + ts, ); + getDb() + .prepare("update tasks set active_session_id = ?, updated_at = ? where id = ?") + .run(sessionId, ts, taskId); }, getTaskSession(taskId: string): { sessionParams: Record | null; sessionDisplayId: string | null; } { + const taskRow = getDb() + .prepare("select active_session_id as activeSessionId from tasks where id = ?") + .get(taskId) as { activeSessionId: string | null } | undefined; + if (!taskRow?.activeSessionId) { + return { sessionParams: null, sessionDisplayId: null }; + } const row = getDb() .prepare( - "select session_json as sessionJson, session_display_id as sessionDisplayId from tasks where id = ?", + "select session_params_json as sessionParamsJson, session_display_id as sessionDisplayId from task_sessions where id = ?", ) - .get(taskId) as - | { sessionJson: string | null; sessionDisplayId: string | null } + .get(taskRow.activeSessionId) as + | { sessionParamsJson: string | null; sessionDisplayId: string | null } | undefined; let sessionParams: Record | null = null; - if (row?.sessionJson) { - try { - sessionParams = JSON.parse(row.sessionJson) as Record; - } catch { - sessionParams = null; - } + if (row?.sessionParamsJson) { + sessionParams = JSON.parse(row.sessionParamsJson) as Record; } return { sessionParams,