fix(tasks): route updateTaskSession/getTaskSession through task_sessions table
Stop writing new session data back to the legacy tasks.session_json column; updateTaskSession now upserts the active task_sessions row (updating the session pointed to by tasks.active_session_id, creating one when absent), and getTaskSession reads from the same row so session data has a single source of truth. Adds migration 27 to backfill pre-existing tasks.session_json values into task_sessions idempotently via INSERT OR IGNORE guarded on task_id. The legacy column is kept for read-only history and is not dropped.
This commit is contained in:
1 parent
ccf0c2a500
commit
a130dc29f5
2 files changed
+93
-13
No files matched your search
@@ -365,6 +365,48 @@ export function runMigrations(
|
|||||||
version: 26, name: "add_source_run_id_for_causal_binding",
|
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`,
|
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) {
|
for (const migration of migrations) {
|
||||||
|
|||||||
@@ -185,36 +185,74 @@ export function buildTaskCrudMethods(
|
|||||||
sessionJson: Record<string, unknown> | null,
|
sessionJson: Record<string, unknown> | null,
|
||||||
sessionDisplayId: string | null,
|
sessionDisplayId: string | null,
|
||||||
): void {
|
): 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()
|
getDb()
|
||||||
.prepare(
|
.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(
|
.run(
|
||||||
sessionJson ? JSON.stringify(sessionJson) : null,
|
sessionId,
|
||||||
sessionDisplayId,
|
taskRow.companyId,
|
||||||
nowIso(),
|
|
||||||
taskId,
|
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): {
|
getTaskSession(taskId: string): {
|
||||||
sessionParams: Record<string, unknown> | null;
|
sessionParams: Record<string, unknown> | null;
|
||||||
sessionDisplayId: string | 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()
|
const row = getDb()
|
||||||
.prepare(
|
.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
|
.get(taskRow.activeSessionId) as
|
||||||
| { sessionJson: string | null; sessionDisplayId: string | null }
|
| { sessionParamsJson: string | null; sessionDisplayId: string | null }
|
||||||
| undefined;
|
| undefined;
|
||||||
let sessionParams: Record<string, unknown> | null = null;
|
let sessionParams: Record<string, unknown> | null = null;
|
||||||
if (row?.sessionJson) {
|
if (row?.sessionParamsJson) {
|
||||||
try {
|
sessionParams = JSON.parse(row.sessionParamsJson) as Record<string, unknown>;
|
||||||
sessionParams = JSON.parse(row.sessionJson) as Record<string, unknown>;
|
|
||||||
} catch {
|
|
||||||
sessionParams = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
sessionParams,
|
sessionParams,
|
||||||
|
|||||||
Reference in new issue
Block a user