@osolmaz/pi-workflows 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/builtins/catalog.js +12 -2
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/monitor.workflow.d.ts +2 -2
- package/dist/builtins/monitor.workflow.js +11 -27
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/sqlite.d.ts +43 -5
- package/dist/controllers/sqlite.js +128 -32
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/extension/index.js +109 -94
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/widget.d.ts +5 -2
- package/dist/extension/widget.js +52 -17
- package/dist/extension/widget.js.map +1 -1
- package/dist/host/runner.js +20 -1
- package/dist/host/runner.js.map +1 -1
- package/dist/render/graph-render.js +3 -0
- package/dist/render/graph-render.js.map +1 -1
- package/dist/workflows/definition.d.ts +2 -1
- package/dist/workflows/definition.js +9 -1
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +1 -0
- package/dist/workflows/engine.js +22 -0
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/index.d.ts +2 -2
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/migrate-sources.d.ts +1 -0
- package/dist/workflows/migrate-sources.js +4 -0
- package/dist/workflows/migrate-sources.js.map +1 -1
- package/dist/workflows/schema.d.ts +2 -1
- package/dist/workflows/schema.js +12 -0
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.js +3 -0
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +26 -1
- package/docs/plans/2026-08-13-responsive-workflow-widget-plan.md +64 -0
- package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +95 -0
- package/docs/workflows.md +23 -4
- package/package.json +3 -1
- package/src/builtins/catalog.ts +12 -2
- package/src/builtins/monitor.workflow.ts +11 -28
- package/src/controllers/index.ts +1 -0
- package/src/controllers/sqlite.ts +225 -33
- package/src/extension/index.ts +123 -125
- package/src/extension/widget.ts +83 -20
- package/src/host/runner.ts +20 -1
- package/src/render/graph-render.ts +3 -0
- package/src/workflows/definition.ts +11 -0
- package/src/workflows/engine.ts +26 -0
- package/src/workflows/index.ts +5 -0
- package/src/workflows/migrate-sources.ts +7 -0
- package/src/workflows/schema.ts +14 -0
- package/src/workflows/store.ts +3 -0
- package/src/workflows/types.ts +30 -0
|
@@ -93,6 +93,7 @@ type WorkflowRunQueueRow = {
|
|
|
93
93
|
claim_token: string | null;
|
|
94
94
|
claim_expires_at: number | null;
|
|
95
95
|
affinity_runner_id: string | null;
|
|
96
|
+
origin_session_id: string | null;
|
|
96
97
|
parent_run_id: string | null;
|
|
97
98
|
created_at: string;
|
|
98
99
|
updated_at: string;
|
|
@@ -111,11 +112,42 @@ export type WorkflowRunQueueRecord = {
|
|
|
111
112
|
claimToken: string | null;
|
|
112
113
|
claimExpiresAt: string | null;
|
|
113
114
|
affinityRunnerId: string | null;
|
|
115
|
+
/** Pi session that owns delivery and interactive execution, or null for detached runs. */
|
|
116
|
+
originSessionId: string | null;
|
|
114
117
|
parentRunId: string | null;
|
|
115
118
|
createdAt: string;
|
|
116
119
|
updatedAt: string;
|
|
117
120
|
};
|
|
118
121
|
|
|
122
|
+
type WorkflowNotificationRow = {
|
|
123
|
+
notification_id: string;
|
|
124
|
+
run_id: string;
|
|
125
|
+
node_id: string;
|
|
126
|
+
attempt_id: string;
|
|
127
|
+
notification_index: number;
|
|
128
|
+
target_session_id: string;
|
|
129
|
+
kind: "progress" | "final";
|
|
130
|
+
content: string;
|
|
131
|
+
created_at: string;
|
|
132
|
+
delivery_claim_token: string | null;
|
|
133
|
+
delivery_claim_expires_at: number | null;
|
|
134
|
+
delivered_at: string | null;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export type WorkflowNotificationRecord = {
|
|
138
|
+
notificationId: string;
|
|
139
|
+
runId: string;
|
|
140
|
+
nodeId: string;
|
|
141
|
+
attemptId: string;
|
|
142
|
+
notificationIndex: number;
|
|
143
|
+
targetSessionId: string;
|
|
144
|
+
kind: "progress" | "final";
|
|
145
|
+
content: string;
|
|
146
|
+
createdAt: string;
|
|
147
|
+
deliveryClaimExpiresAt: string | null;
|
|
148
|
+
deliveredAt: string | null;
|
|
149
|
+
};
|
|
150
|
+
|
|
119
151
|
type RunEventRow = {
|
|
120
152
|
seq: number;
|
|
121
153
|
recorded_at: string;
|
|
@@ -774,6 +806,13 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
774
806
|
.prepare("INSERT OR IGNORE INTO schema_info (singleton, schema_id) VALUES (1, ?)")
|
|
775
807
|
.run(CONTROLLER_STORE_SCHEMA);
|
|
776
808
|
this.database.exec(SCHEMA_SQL);
|
|
809
|
+
const queueColumns = this.database.pragma("table_info(workflow_run_queue)") as {
|
|
810
|
+
name: string;
|
|
811
|
+
}[];
|
|
812
|
+
if (!queueColumns.some((column) => column.name === "origin_session_id")) {
|
|
813
|
+
this.database.exec("ALTER TABLE workflow_run_queue ADD COLUMN origin_session_id TEXT");
|
|
814
|
+
}
|
|
815
|
+
this.database.exec("DROP TABLE IF EXISTS session_watermarks");
|
|
777
816
|
});
|
|
778
817
|
}
|
|
779
818
|
|
|
@@ -875,6 +914,7 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
875
914
|
claimToken: string;
|
|
876
915
|
leaseMs: number;
|
|
877
916
|
affinityRunnerId?: string;
|
|
917
|
+
originSessionId?: string;
|
|
878
918
|
parentRunId?: string;
|
|
879
919
|
now?: string;
|
|
880
920
|
}): WorkflowRunQueueRecord {
|
|
@@ -884,6 +924,9 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
884
924
|
validateKey(options.runnerId, "runner id");
|
|
885
925
|
validateKey(options.claimToken, "claim token");
|
|
886
926
|
validateDuration(options.leaseMs, "leaseMs");
|
|
927
|
+
if (options.originSessionId !== undefined) {
|
|
928
|
+
validateKey(options.originSessionId, "origin session id");
|
|
929
|
+
}
|
|
887
930
|
const inputJson = canonicalJson(options.input ?? null, "workflow run input");
|
|
888
931
|
validateJsonSize(inputJson, "Workflow run input", MAX_RESOURCE_VALUE_BYTES);
|
|
889
932
|
const now = validTimestamp(options.now);
|
|
@@ -893,8 +936,8 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
893
936
|
`INSERT INTO workflow_run_queue (
|
|
894
937
|
run_id, workflow_ref, workflow_path, input_json, status,
|
|
895
938
|
runner_id, claim_token, claim_expires_at, affinity_runner_id,
|
|
896
|
-
parent_run_id, created_at, updated_at
|
|
897
|
-
) VALUES (?, ?, ?, ?, 'claimed', ?, ?, ?, ?, ?, ?, ?)`,
|
|
939
|
+
origin_session_id, parent_run_id, created_at, updated_at
|
|
940
|
+
) VALUES (?, ?, ?, ?, 'claimed', ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
898
941
|
)
|
|
899
942
|
.run(
|
|
900
943
|
options.runId,
|
|
@@ -905,6 +948,7 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
905
948
|
options.claimToken,
|
|
906
949
|
expiresAt,
|
|
907
950
|
options.affinityRunnerId ?? options.runnerId,
|
|
951
|
+
options.originSessionId ?? null,
|
|
908
952
|
options.parentRunId ?? null,
|
|
909
953
|
now,
|
|
910
954
|
now,
|
|
@@ -945,11 +989,14 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
945
989
|
claimToken: string;
|
|
946
990
|
leaseMs: number;
|
|
947
991
|
excludeRunIds?: string[];
|
|
992
|
+
/** Interactive sessions provide their id; detached hosts omit it. */
|
|
993
|
+
sessionId?: string;
|
|
948
994
|
now?: string;
|
|
949
995
|
}): WorkflowRunQueueRecord | undefined {
|
|
950
996
|
validateKey(options.runnerId, "runner id");
|
|
951
997
|
validateKey(options.claimToken, "claim token");
|
|
952
998
|
validateDuration(options.leaseMs, "leaseMs");
|
|
999
|
+
if (options.sessionId !== undefined) validateKey(options.sessionId, "session id");
|
|
953
1000
|
const now = validTimestamp(options.now);
|
|
954
1001
|
const nowMs = epoch(now);
|
|
955
1002
|
const expiresAt = nowMs + options.leaseMs;
|
|
@@ -959,6 +1006,10 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
959
1006
|
}
|
|
960
1007
|
const exclusion =
|
|
961
1008
|
excluded.length === 0 ? "" : `AND run_id NOT IN (${excluded.map(() => "?").join(", ")})`;
|
|
1009
|
+
const sessionFilter =
|
|
1010
|
+
options.sessionId === undefined
|
|
1011
|
+
? ""
|
|
1012
|
+
: "AND (origin_session_id IS NULL OR origin_session_id = ?)";
|
|
962
1013
|
const claimable = `(
|
|
963
1014
|
status = 'parked'
|
|
964
1015
|
OR (status = 'claimed' AND claim_expires_at IS NOT NULL AND claim_expires_at <= ?)
|
|
@@ -967,13 +1018,18 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
967
1018
|
const candidate = this.database
|
|
968
1019
|
.prepare(
|
|
969
1020
|
`SELECT run_id FROM workflow_run_queue
|
|
970
|
-
WHERE ${claimable} ${exclusion}
|
|
1021
|
+
WHERE ${claimable} ${exclusion} ${sessionFilter}
|
|
971
1022
|
ORDER BY
|
|
972
1023
|
CASE WHEN affinity_runner_id = ? THEN 0 ELSE 1 END,
|
|
973
1024
|
created_at ASC
|
|
974
1025
|
LIMIT 1`,
|
|
975
1026
|
)
|
|
976
|
-
.get(
|
|
1027
|
+
.get(
|
|
1028
|
+
nowMs,
|
|
1029
|
+
...excluded,
|
|
1030
|
+
...(options.sessionId === undefined ? [] : [options.sessionId]),
|
|
1031
|
+
options.runnerId,
|
|
1032
|
+
) as { run_id: string } | undefined;
|
|
977
1033
|
if (candidate === undefined) {
|
|
978
1034
|
return undefined;
|
|
979
1035
|
}
|
|
@@ -1235,37 +1291,141 @@ export class SqliteControllerStore implements ControllerStore {
|
|
|
1235
1291
|
}));
|
|
1236
1292
|
}
|
|
1237
1293
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1294
|
+
enqueueWorkflowNotification(options: {
|
|
1295
|
+
runId: string;
|
|
1296
|
+
nodeId: string;
|
|
1297
|
+
attemptId: string;
|
|
1298
|
+
notificationIndex: number;
|
|
1299
|
+
targetSessionId: string;
|
|
1300
|
+
kind: "progress" | "final";
|
|
1301
|
+
content: string;
|
|
1302
|
+
notificationId?: string;
|
|
1303
|
+
now?: string;
|
|
1304
|
+
}): WorkflowNotificationRecord {
|
|
1305
|
+
validateRunId(options.runId);
|
|
1306
|
+
validateKey(options.nodeId, "workflow node id");
|
|
1307
|
+
validateKey(options.attemptId, "workflow attempt id");
|
|
1308
|
+
if (!Number.isSafeInteger(options.notificationIndex) || options.notificationIndex <= 0) {
|
|
1309
|
+
throw new Error("Workflow notification index must be a positive safe integer");
|
|
1310
|
+
}
|
|
1311
|
+
validateKey(options.targetSessionId, "target session id");
|
|
1312
|
+
if (options.content.trim().length === 0 || options.content.length > MAX_EVENT_BYTES) {
|
|
1313
|
+
throw new Error(`Workflow notification content must be 1-${MAX_EVENT_BYTES} characters`);
|
|
1314
|
+
}
|
|
1315
|
+
const notificationId = options.notificationId ?? randomUUID();
|
|
1316
|
+
validateKey(notificationId, "notification id");
|
|
1317
|
+
this.database
|
|
1318
|
+
.prepare(
|
|
1319
|
+
`INSERT INTO workflow_notifications (
|
|
1320
|
+
notification_id, run_id, node_id, attempt_id, notification_index,
|
|
1321
|
+
target_session_id, kind, content, created_at, delivered_at
|
|
1322
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
|
|
1323
|
+
ON CONFLICT(run_id, node_id, notification_index) DO NOTHING`,
|
|
1324
|
+
)
|
|
1325
|
+
.run(
|
|
1326
|
+
notificationId,
|
|
1327
|
+
options.runId,
|
|
1328
|
+
options.nodeId,
|
|
1329
|
+
options.attemptId,
|
|
1330
|
+
options.notificationIndex,
|
|
1331
|
+
options.targetSessionId,
|
|
1332
|
+
options.kind,
|
|
1333
|
+
options.content.trim(),
|
|
1334
|
+
validTimestamp(options.now),
|
|
1335
|
+
);
|
|
1249
1336
|
const row = this.database
|
|
1250
|
-
.prepare(
|
|
1251
|
-
|
|
1252
|
-
|
|
1337
|
+
.prepare(
|
|
1338
|
+
"SELECT * FROM workflow_notifications WHERE run_id = ? AND node_id = ? AND notification_index = ?",
|
|
1339
|
+
)
|
|
1340
|
+
.get(options.runId, options.nodeId, options.notificationIndex) as WorkflowNotificationRow;
|
|
1341
|
+
return workflowNotificationFromRow(row);
|
|
1253
1342
|
}
|
|
1254
1343
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1344
|
+
claimPendingWorkflowNotifications(options: {
|
|
1345
|
+
targetSessionId: string;
|
|
1346
|
+
claimToken: string;
|
|
1347
|
+
leaseMs: number;
|
|
1348
|
+
limit?: number;
|
|
1349
|
+
now?: string;
|
|
1350
|
+
}): WorkflowNotificationRecord[] {
|
|
1351
|
+
validateKey(options.targetSessionId, "target session id");
|
|
1352
|
+
validateKey(options.claimToken, "notification claim token");
|
|
1353
|
+
validateDuration(options.leaseMs, "notification leaseMs");
|
|
1354
|
+
const limit = options.limit ?? 20;
|
|
1355
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || limit > 100) {
|
|
1356
|
+
throw new Error("Workflow notification limit must be an integer from 1 through 100");
|
|
1259
1357
|
}
|
|
1260
|
-
|
|
1358
|
+
const now = validTimestamp(options.now);
|
|
1359
|
+
const nowMs = epoch(now);
|
|
1360
|
+
return this.transaction(() => {
|
|
1361
|
+
const ids = this.database
|
|
1362
|
+
.prepare(
|
|
1363
|
+
`SELECT notification_id FROM workflow_notifications
|
|
1364
|
+
WHERE target_session_id = ? AND delivered_at IS NULL
|
|
1365
|
+
AND (delivery_claim_expires_at IS NULL OR delivery_claim_expires_at <= ?)
|
|
1366
|
+
ORDER BY created_at, notification_id LIMIT ?`,
|
|
1367
|
+
)
|
|
1368
|
+
.all(options.targetSessionId, nowMs, limit) as { notification_id: string }[];
|
|
1369
|
+
if (ids.length === 0) return [];
|
|
1370
|
+
const placeholders = ids.map(() => "?").join(", ");
|
|
1371
|
+
this.database
|
|
1372
|
+
.prepare(
|
|
1373
|
+
`UPDATE workflow_notifications
|
|
1374
|
+
SET delivery_claim_token = ?, delivery_claim_expires_at = ?
|
|
1375
|
+
WHERE notification_id IN (${placeholders}) AND delivered_at IS NULL
|
|
1376
|
+
AND (delivery_claim_expires_at IS NULL OR delivery_claim_expires_at <= ?)`,
|
|
1377
|
+
)
|
|
1378
|
+
.run(
|
|
1379
|
+
options.claimToken,
|
|
1380
|
+
nowMs + options.leaseMs,
|
|
1381
|
+
...ids.map((row) => row.notification_id),
|
|
1382
|
+
nowMs,
|
|
1383
|
+
);
|
|
1384
|
+
const rows = this.database
|
|
1385
|
+
.prepare(
|
|
1386
|
+
`SELECT * FROM workflow_notifications WHERE delivery_claim_token = ?
|
|
1387
|
+
ORDER BY created_at, notification_id`,
|
|
1388
|
+
)
|
|
1389
|
+
.all(options.claimToken) as WorkflowNotificationRow[];
|
|
1390
|
+
return rows.map(workflowNotificationFromRow);
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
markWorkflowNotificationDelivered(options: {
|
|
1395
|
+
notificationId: string;
|
|
1396
|
+
targetSessionId: string;
|
|
1397
|
+
claimToken: string;
|
|
1398
|
+
now?: string;
|
|
1399
|
+
}): boolean {
|
|
1400
|
+
validateKey(options.notificationId, "notification id");
|
|
1401
|
+
validateKey(options.targetSessionId, "target session id");
|
|
1402
|
+
validateKey(options.claimToken, "notification claim token");
|
|
1403
|
+
const result = this.database
|
|
1404
|
+
.prepare(
|
|
1405
|
+
`UPDATE workflow_notifications
|
|
1406
|
+
SET delivered_at = ?, delivery_claim_token = NULL, delivery_claim_expires_at = NULL
|
|
1407
|
+
WHERE notification_id = ? AND target_session_id = ?
|
|
1408
|
+
AND delivery_claim_token = ? AND delivered_at IS NULL`,
|
|
1409
|
+
)
|
|
1410
|
+
.run(
|
|
1411
|
+
validTimestamp(options.now),
|
|
1412
|
+
options.notificationId,
|
|
1413
|
+
options.targetSessionId,
|
|
1414
|
+
options.claimToken,
|
|
1415
|
+
);
|
|
1416
|
+
return result.changes === 1;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
setWorkflowRunOriginSession(runId: string, originSessionId: string): boolean {
|
|
1420
|
+
validateRunId(runId);
|
|
1421
|
+
validateKey(originSessionId, "origin session id");
|
|
1422
|
+
const result = this.database
|
|
1261
1423
|
.prepare(
|
|
1262
|
-
`
|
|
1263
|
-
|
|
1264
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
1265
|
-
last_event_seq = MAX(session_watermarks.last_event_seq, excluded.last_event_seq),
|
|
1266
|
-
updated_at = excluded.updated_at`,
|
|
1424
|
+
`UPDATE workflow_run_queue SET origin_session_id = ?
|
|
1425
|
+
WHERE run_id = ? AND origin_session_id IS NULL`,
|
|
1267
1426
|
)
|
|
1268
|
-
.run(
|
|
1427
|
+
.run(originSessionId, runId);
|
|
1428
|
+
return result.changes === 1;
|
|
1269
1429
|
}
|
|
1270
1430
|
|
|
1271
1431
|
private requireWorkflowRun(runId: string): WorkflowRunQueueRecord {
|
|
@@ -1329,6 +1489,7 @@ const SCHEMA_SQL = `
|
|
|
1329
1489
|
claim_token TEXT,
|
|
1330
1490
|
claim_expires_at INTEGER,
|
|
1331
1491
|
affinity_runner_id TEXT,
|
|
1492
|
+
origin_session_id TEXT,
|
|
1332
1493
|
parent_run_id TEXT,
|
|
1333
1494
|
created_at TEXT NOT NULL,
|
|
1334
1495
|
updated_at TEXT NOT NULL
|
|
@@ -1351,11 +1512,24 @@ const SCHEMA_SQL = `
|
|
|
1351
1512
|
);
|
|
1352
1513
|
CREATE INDEX IF NOT EXISTS run_events_run ON run_events(run_id);
|
|
1353
1514
|
|
|
1354
|
-
CREATE TABLE IF NOT EXISTS
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1515
|
+
CREATE TABLE IF NOT EXISTS workflow_notifications (
|
|
1516
|
+
notification_id TEXT PRIMARY KEY,
|
|
1517
|
+
run_id TEXT NOT NULL,
|
|
1518
|
+
node_id TEXT NOT NULL,
|
|
1519
|
+
attempt_id TEXT NOT NULL,
|
|
1520
|
+
notification_index INTEGER NOT NULL CHECK (notification_index > 0),
|
|
1521
|
+
target_session_id TEXT NOT NULL,
|
|
1522
|
+
kind TEXT NOT NULL CHECK (kind IN ('progress', 'final')),
|
|
1523
|
+
content TEXT NOT NULL,
|
|
1524
|
+
created_at TEXT NOT NULL,
|
|
1525
|
+
delivery_claim_token TEXT,
|
|
1526
|
+
delivery_claim_expires_at INTEGER,
|
|
1527
|
+
delivered_at TEXT,
|
|
1528
|
+
UNIQUE (run_id, node_id, notification_index)
|
|
1358
1529
|
);
|
|
1530
|
+
CREATE INDEX IF NOT EXISTS workflow_notifications_pending
|
|
1531
|
+
ON workflow_notifications(target_session_id, delivery_claim_expires_at, created_at)
|
|
1532
|
+
WHERE delivered_at IS NULL;
|
|
1359
1533
|
|
|
1360
1534
|
CREATE TABLE IF NOT EXISTS effects (
|
|
1361
1535
|
effect_key TEXT NOT NULL,
|
|
@@ -1447,6 +1621,23 @@ function workflowFromRow(row: WorkflowRow): ChildWorkflowRecord {
|
|
|
1447
1621
|
};
|
|
1448
1622
|
}
|
|
1449
1623
|
|
|
1624
|
+
function workflowNotificationFromRow(row: WorkflowNotificationRow): WorkflowNotificationRecord {
|
|
1625
|
+
return {
|
|
1626
|
+
notificationId: row.notification_id,
|
|
1627
|
+
runId: row.run_id,
|
|
1628
|
+
nodeId: row.node_id,
|
|
1629
|
+
attemptId: row.attempt_id,
|
|
1630
|
+
notificationIndex: row.notification_index,
|
|
1631
|
+
targetSessionId: row.target_session_id,
|
|
1632
|
+
kind: row.kind,
|
|
1633
|
+
content: row.content,
|
|
1634
|
+
createdAt: row.created_at,
|
|
1635
|
+
deliveryClaimExpiresAt:
|
|
1636
|
+
row.delivery_claim_expires_at === null ? null : iso(row.delivery_claim_expires_at),
|
|
1637
|
+
deliveredAt: row.delivered_at,
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1450
1641
|
function workflowRunFromRow(row: WorkflowRunQueueRow): WorkflowRunQueueRecord {
|
|
1451
1642
|
return {
|
|
1452
1643
|
runId: row.run_id,
|
|
@@ -1458,6 +1649,7 @@ function workflowRunFromRow(row: WorkflowRunQueueRow): WorkflowRunQueueRecord {
|
|
|
1458
1649
|
claimToken: row.claim_token,
|
|
1459
1650
|
claimExpiresAt: row.claim_expires_at === null ? null : iso(row.claim_expires_at),
|
|
1460
1651
|
affinityRunnerId: row.affinity_runner_id,
|
|
1652
|
+
originSessionId: row.origin_session_id,
|
|
1461
1653
|
parentRunId: row.parent_run_id,
|
|
1462
1654
|
createdAt: row.created_at,
|
|
1463
1655
|
updatedAt: row.updated_at,
|