@bastani/atomic 0.9.42 → 0.9.43-alpha.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/CHANGELOG.md +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/index.bundle.mjs +20 -12
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +19 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +2 -0
- package/dist/builtin/workflows/src/durable/journal/internal.d.ts +17 -1
- package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +5 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +363 -90
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +444 -180
- package/dist/builtin/workflows/src/index.js +334 -69
- package/dist/builtin/workflows/src/local-worker-entry.mjs +444 -180
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +10 -0
- package/dist/builtin/workflows/src/workers/public-options.d.ts +2 -0
- package/dist/core/settings-schema.d.ts +2 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +10 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/docs/settings.md +4 -0
- package/docs/workflows/api-reference.md +18 -3
- package/docs/workflows/operations.md +11 -1
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +12 -0
|
@@ -58,6 +58,113 @@ var __esm = (fn, res, err) => () => {
|
|
|
58
58
|
};
|
|
59
59
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
60
60
|
|
|
61
|
+
// dist/builtin/workflows/src/durable/journal/types.ts
|
|
62
|
+
import { StorageSchemaVersionError } from "@bastani/atomic/storage";
|
|
63
|
+
import { StorageUnavailableError } from "@bastani/atomic/storage";
|
|
64
|
+
import { RUN_EVENT_TYPES } from "@bastani/atomic/storage";
|
|
65
|
+
var JOURNAL_SCHEMA_VERSION = 1, JOURNAL_PAYLOAD_ENCODING = "json-text", JOURNAL_TABLES, JOURNAL_COLUMNS, JOURNAL_LEASE, JournalError, JournalClosedError, JournalInvalidTextError, JournalMetaCorruptError, JournalCounterRangeError, StaleLeaseError, JournalCasConflictError, JournalSchemaVersionError, RunNotFoundError;
|
|
66
|
+
var init_types = __esm(() => {
|
|
67
|
+
JOURNAL_TABLES = { meta: "meta", runs: "runs", events: "events", leases: "leases" };
|
|
68
|
+
JOURNAL_COLUMNS = {
|
|
69
|
+
schemaVersion: "schema_version",
|
|
70
|
+
runId: "run_id",
|
|
71
|
+
name: "name",
|
|
72
|
+
cwd: "cwd",
|
|
73
|
+
createdAt: "created_at",
|
|
74
|
+
status: "status",
|
|
75
|
+
headerJson: "header_json",
|
|
76
|
+
seq: "seq",
|
|
77
|
+
epoch: "epoch",
|
|
78
|
+
key: "key",
|
|
79
|
+
type: "type",
|
|
80
|
+
payload: "payload",
|
|
81
|
+
at: "at",
|
|
82
|
+
holderId: "holder_id",
|
|
83
|
+
renewedAt: "renewed_at"
|
|
84
|
+
};
|
|
85
|
+
JOURNAL_LEASE = { initialEpoch: 1, epochIncrement: 1, unheld: null, absentEpoch: 0 };
|
|
86
|
+
JournalError = class JournalError extends Error {
|
|
87
|
+
};
|
|
88
|
+
JournalClosedError = class JournalClosedError extends JournalError {
|
|
89
|
+
constructor() {
|
|
90
|
+
super("Journal is closed");
|
|
91
|
+
this.name = "JournalClosedError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
JournalInvalidTextError = class JournalInvalidTextError extends JournalError {
|
|
95
|
+
field;
|
|
96
|
+
reason;
|
|
97
|
+
constructor(field, reason) {
|
|
98
|
+
super(`Invalid journal ${field}: ${reason}`);
|
|
99
|
+
this.name = "JournalInvalidTextError";
|
|
100
|
+
this.field = field;
|
|
101
|
+
this.reason = reason;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
JournalMetaCorruptError = class JournalMetaCorruptError extends JournalError {
|
|
105
|
+
path;
|
|
106
|
+
rowCount;
|
|
107
|
+
constructor(path, rowCount) {
|
|
108
|
+
super(`Journal metadata at ${path} has ${rowCount} rows`);
|
|
109
|
+
this.name = "JournalMetaCorruptError";
|
|
110
|
+
this.path = path;
|
|
111
|
+
this.rowCount = rowCount;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
JournalCounterRangeError = class JournalCounterRangeError extends JournalError {
|
|
115
|
+
runId;
|
|
116
|
+
field;
|
|
117
|
+
value;
|
|
118
|
+
reason;
|
|
119
|
+
constructor(runId, field, value2, reason) {
|
|
120
|
+
super(`Unsafe journal ${field} counter for run ${runId}: ${value2}`);
|
|
121
|
+
this.name = "JournalCounterRangeError";
|
|
122
|
+
this.runId = runId;
|
|
123
|
+
this.field = field;
|
|
124
|
+
this.value = value2;
|
|
125
|
+
this.reason = reason;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
StaleLeaseError = class StaleLeaseError extends JournalError {
|
|
129
|
+
runId;
|
|
130
|
+
heldEpoch;
|
|
131
|
+
currentEpoch;
|
|
132
|
+
constructor(runId, heldEpoch, currentEpoch) {
|
|
133
|
+
super(`Stale lease for run ${runId}`);
|
|
134
|
+
this.name = "StaleLeaseError";
|
|
135
|
+
this.runId = runId;
|
|
136
|
+
this.heldEpoch = heldEpoch;
|
|
137
|
+
this.currentEpoch = currentEpoch;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
JournalCasConflictError = class JournalCasConflictError extends JournalError {
|
|
141
|
+
runId;
|
|
142
|
+
expectedSeq;
|
|
143
|
+
actualSeq;
|
|
144
|
+
constructor(runId, expectedSeq, actualSeq) {
|
|
145
|
+
super(`Journal sequence conflict for run ${runId}`);
|
|
146
|
+
this.name = "JournalCasConflictError";
|
|
147
|
+
this.runId = runId;
|
|
148
|
+
this.expectedSeq = expectedSeq;
|
|
149
|
+
this.actualSeq = actualSeq;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
JournalSchemaVersionError = class JournalSchemaVersionError extends StorageSchemaVersionError {
|
|
153
|
+
constructor(found, supported = JOURNAL_SCHEMA_VERSION) {
|
|
154
|
+
super("journal", found, supported);
|
|
155
|
+
this.name = "JournalSchemaVersionError";
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
RunNotFoundError = class RunNotFoundError extends JournalError {
|
|
159
|
+
runId;
|
|
160
|
+
constructor(runId) {
|
|
161
|
+
super(`Run not found: ${runId}`);
|
|
162
|
+
this.name = "RunNotFoundError";
|
|
163
|
+
this.runId = runId;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
|
|
61
168
|
// dist/builtin/workflows/src/durable/journal/internal.ts
|
|
62
169
|
function registerRunJournalVersions(journal, versions) {
|
|
63
170
|
versionReaders.set(journal, versions);
|
|
@@ -71,8 +178,14 @@ function registerSqlPoolStorage(journal, storage) {
|
|
|
71
178
|
function sqlPoolStorage(journal) {
|
|
72
179
|
return poolStorage.get(journal);
|
|
73
180
|
}
|
|
74
|
-
var JOURNAL_READ_PAGE_SIZE = 256, versionReaders, poolStorage;
|
|
181
|
+
var JOURNAL_READ_PAGE_SIZE = 256, NON_SNAPSHOT_EVENT_TYPES, versionReaders, poolStorage;
|
|
75
182
|
var init_internal = __esm(() => {
|
|
183
|
+
init_types();
|
|
184
|
+
NON_SNAPSHOT_EVENT_TYPES = [
|
|
185
|
+
RUN_EVENT_TYPES.checkpointRecorded,
|
|
186
|
+
RUN_EVENT_TYPES.messageSettled,
|
|
187
|
+
RUN_EVENT_TYPES.messageDelivered
|
|
188
|
+
];
|
|
76
189
|
versionReaders = new WeakMap;
|
|
77
190
|
poolStorage = new WeakMap;
|
|
78
191
|
});
|
|
@@ -1280,113 +1393,6 @@ class PromptReservationState {
|
|
|
1280
1393
|
}
|
|
1281
1394
|
}
|
|
1282
1395
|
|
|
1283
|
-
// dist/builtin/workflows/src/durable/journal/types.ts
|
|
1284
|
-
import { StorageSchemaVersionError } from "@bastani/atomic/storage";
|
|
1285
|
-
import { StorageUnavailableError } from "@bastani/atomic/storage";
|
|
1286
|
-
import { RUN_EVENT_TYPES } from "@bastani/atomic/storage";
|
|
1287
|
-
var JOURNAL_SCHEMA_VERSION = 1, JOURNAL_PAYLOAD_ENCODING = "json-text", JOURNAL_TABLES, JOURNAL_COLUMNS, JOURNAL_LEASE, JournalError, JournalClosedError, JournalInvalidTextError, JournalMetaCorruptError, JournalCounterRangeError, StaleLeaseError, JournalCasConflictError, JournalSchemaVersionError, RunNotFoundError;
|
|
1288
|
-
var init_types = __esm(() => {
|
|
1289
|
-
JOURNAL_TABLES = { meta: "meta", runs: "runs", events: "events", leases: "leases" };
|
|
1290
|
-
JOURNAL_COLUMNS = {
|
|
1291
|
-
schemaVersion: "schema_version",
|
|
1292
|
-
runId: "run_id",
|
|
1293
|
-
name: "name",
|
|
1294
|
-
cwd: "cwd",
|
|
1295
|
-
createdAt: "created_at",
|
|
1296
|
-
status: "status",
|
|
1297
|
-
headerJson: "header_json",
|
|
1298
|
-
seq: "seq",
|
|
1299
|
-
epoch: "epoch",
|
|
1300
|
-
key: "key",
|
|
1301
|
-
type: "type",
|
|
1302
|
-
payload: "payload",
|
|
1303
|
-
at: "at",
|
|
1304
|
-
holderId: "holder_id",
|
|
1305
|
-
renewedAt: "renewed_at"
|
|
1306
|
-
};
|
|
1307
|
-
JOURNAL_LEASE = { initialEpoch: 1, epochIncrement: 1, unheld: null, absentEpoch: 0 };
|
|
1308
|
-
JournalError = class JournalError extends Error {
|
|
1309
|
-
};
|
|
1310
|
-
JournalClosedError = class JournalClosedError extends JournalError {
|
|
1311
|
-
constructor() {
|
|
1312
|
-
super("Journal is closed");
|
|
1313
|
-
this.name = "JournalClosedError";
|
|
1314
|
-
}
|
|
1315
|
-
};
|
|
1316
|
-
JournalInvalidTextError = class JournalInvalidTextError extends JournalError {
|
|
1317
|
-
field;
|
|
1318
|
-
reason;
|
|
1319
|
-
constructor(field, reason) {
|
|
1320
|
-
super(`Invalid journal ${field}: ${reason}`);
|
|
1321
|
-
this.name = "JournalInvalidTextError";
|
|
1322
|
-
this.field = field;
|
|
1323
|
-
this.reason = reason;
|
|
1324
|
-
}
|
|
1325
|
-
};
|
|
1326
|
-
JournalMetaCorruptError = class JournalMetaCorruptError extends JournalError {
|
|
1327
|
-
path;
|
|
1328
|
-
rowCount;
|
|
1329
|
-
constructor(path, rowCount) {
|
|
1330
|
-
super(`Journal metadata at ${path} has ${rowCount} rows`);
|
|
1331
|
-
this.name = "JournalMetaCorruptError";
|
|
1332
|
-
this.path = path;
|
|
1333
|
-
this.rowCount = rowCount;
|
|
1334
|
-
}
|
|
1335
|
-
};
|
|
1336
|
-
JournalCounterRangeError = class JournalCounterRangeError extends JournalError {
|
|
1337
|
-
runId;
|
|
1338
|
-
field;
|
|
1339
|
-
value;
|
|
1340
|
-
reason;
|
|
1341
|
-
constructor(runId, field, value2, reason) {
|
|
1342
|
-
super(`Unsafe journal ${field} counter for run ${runId}: ${value2}`);
|
|
1343
|
-
this.name = "JournalCounterRangeError";
|
|
1344
|
-
this.runId = runId;
|
|
1345
|
-
this.field = field;
|
|
1346
|
-
this.value = value2;
|
|
1347
|
-
this.reason = reason;
|
|
1348
|
-
}
|
|
1349
|
-
};
|
|
1350
|
-
StaleLeaseError = class StaleLeaseError extends JournalError {
|
|
1351
|
-
runId;
|
|
1352
|
-
heldEpoch;
|
|
1353
|
-
currentEpoch;
|
|
1354
|
-
constructor(runId, heldEpoch, currentEpoch) {
|
|
1355
|
-
super(`Stale lease for run ${runId}`);
|
|
1356
|
-
this.name = "StaleLeaseError";
|
|
1357
|
-
this.runId = runId;
|
|
1358
|
-
this.heldEpoch = heldEpoch;
|
|
1359
|
-
this.currentEpoch = currentEpoch;
|
|
1360
|
-
}
|
|
1361
|
-
};
|
|
1362
|
-
JournalCasConflictError = class JournalCasConflictError extends JournalError {
|
|
1363
|
-
runId;
|
|
1364
|
-
expectedSeq;
|
|
1365
|
-
actualSeq;
|
|
1366
|
-
constructor(runId, expectedSeq, actualSeq) {
|
|
1367
|
-
super(`Journal sequence conflict for run ${runId}`);
|
|
1368
|
-
this.name = "JournalCasConflictError";
|
|
1369
|
-
this.runId = runId;
|
|
1370
|
-
this.expectedSeq = expectedSeq;
|
|
1371
|
-
this.actualSeq = actualSeq;
|
|
1372
|
-
}
|
|
1373
|
-
};
|
|
1374
|
-
JournalSchemaVersionError = class JournalSchemaVersionError extends StorageSchemaVersionError {
|
|
1375
|
-
constructor(found, supported = JOURNAL_SCHEMA_VERSION) {
|
|
1376
|
-
super("journal", found, supported);
|
|
1377
|
-
this.name = "JournalSchemaVersionError";
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
RunNotFoundError = class RunNotFoundError extends JournalError {
|
|
1381
|
-
runId;
|
|
1382
|
-
constructor(runId) {
|
|
1383
|
-
super(`Run not found: ${runId}`);
|
|
1384
|
-
this.name = "RunNotFoundError";
|
|
1385
|
-
this.runId = runId;
|
|
1386
|
-
}
|
|
1387
|
-
};
|
|
1388
|
-
});
|
|
1389
|
-
|
|
1390
1396
|
// dist/builtin/workflows/src/durable/journal/values.ts
|
|
1391
1397
|
function validateText(field, value2) {
|
|
1392
1398
|
if (value2.includes("\x00"))
|
|
@@ -1690,6 +1696,7 @@ class JournalDurableBackend {
|
|
|
1690
1696
|
projection = createJournalProjection();
|
|
1691
1697
|
sequences = new Map;
|
|
1692
1698
|
foldedAt = new Map;
|
|
1699
|
+
summarized = new Map;
|
|
1693
1700
|
catalogToken;
|
|
1694
1701
|
leases = new Map;
|
|
1695
1702
|
executions = new Map;
|
|
@@ -1715,8 +1722,8 @@ class JournalDurableBackend {
|
|
|
1715
1722
|
let backend;
|
|
1716
1723
|
try {
|
|
1717
1724
|
backend = new JournalDurableBackend(journal, undefined, options.ownsJournal ?? true);
|
|
1718
|
-
for (const
|
|
1719
|
-
for await (const entry of journal.read(
|
|
1725
|
+
for (const runId of options.runs ?? (await journal.listRuns()).map((run) => run.runId))
|
|
1726
|
+
for await (const entry of journal.read(runId))
|
|
1720
1727
|
backend.fold(entry);
|
|
1721
1728
|
return backend;
|
|
1722
1729
|
} catch (error) {
|
|
@@ -1789,6 +1796,18 @@ class JournalDurableBackend {
|
|
|
1789
1796
|
this.sequences.set(entry.runId, entry.seq);
|
|
1790
1797
|
this.foldedAt.set(entry.runId, entry.at);
|
|
1791
1798
|
}
|
|
1799
|
+
summarize(runId, tail) {
|
|
1800
|
+
const event = tail.snapshot.event;
|
|
1801
|
+
const handle = event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased ? event.payload.handle : event.payload;
|
|
1802
|
+
this.projection.deleteWorkflow(runId);
|
|
1803
|
+
this.prompts.delete(runId);
|
|
1804
|
+
this.projection.applyWorkflowSnapshot({
|
|
1805
|
+
...handle,
|
|
1806
|
+
completedCheckpoints: handle.completedCheckpoints + tail.laterCheckpoints,
|
|
1807
|
+
...tail.lastCheckpointAt === undefined ? {} : { updatedAt: tail.lastCheckpointAt }
|
|
1808
|
+
});
|
|
1809
|
+
this.summarized.set(runId, tail.version);
|
|
1810
|
+
}
|
|
1792
1811
|
*entries(runId, fromSeq) {
|
|
1793
1812
|
return yield* invoke(async () => {
|
|
1794
1813
|
const entries = [];
|
|
@@ -1802,6 +1821,7 @@ class JournalDurableBackend {
|
|
|
1802
1821
|
this.projection.deleteWorkflow(runId);
|
|
1803
1822
|
this.sequences.delete(runId);
|
|
1804
1823
|
this.foldedAt.delete(runId);
|
|
1824
|
+
this.summarized.delete(runId);
|
|
1805
1825
|
this.prompts.delete(runId);
|
|
1806
1826
|
for (const entry of entries)
|
|
1807
1827
|
this.fold(entry);
|
|
@@ -2123,6 +2143,9 @@ class JournalDurableBackend {
|
|
|
2123
2143
|
async hydrateWorkflow(runId) {
|
|
2124
2144
|
await this.serialize(runId, () => this.rebuild(runId), false);
|
|
2125
2145
|
}
|
|
2146
|
+
async catchUpWorkflow(runId) {
|
|
2147
|
+
await this.serialize(runId, () => this.extend(runId), false);
|
|
2148
|
+
}
|
|
2126
2149
|
hydrateResumableWorkflows() {
|
|
2127
2150
|
return this.serialize(this.catalogQueue, () => invoke(async () => {
|
|
2128
2151
|
const journal = runJournalVersions(this.journal);
|
|
@@ -2136,16 +2159,33 @@ class JournalDurableBackend {
|
|
|
2136
2159
|
if (token === this.catalogToken)
|
|
2137
2160
|
return;
|
|
2138
2161
|
const versions = await journal.runVersions();
|
|
2139
|
-
for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
|
|
2140
|
-
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
|
|
2162
|
+
for (const runId of new Set([...this.sequences.keys(), ...this.summarized.keys(), ...versions.keys()]))
|
|
2163
|
+
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId), journal), false);
|
|
2141
2164
|
this.catalogToken = token;
|
|
2142
2165
|
}));
|
|
2143
2166
|
}
|
|
2144
|
-
*catchUp(runId, version) {
|
|
2167
|
+
*catchUp(runId, version, journal) {
|
|
2145
2168
|
const folded = this.sequences.get(runId) ?? 0;
|
|
2169
|
+
if (folded === 0 && version !== undefined) {
|
|
2170
|
+
const summarized = this.summarized.get(runId);
|
|
2171
|
+
if (summarized !== undefined && summarized.seq === version.seq && summarized.at === version.at)
|
|
2172
|
+
return;
|
|
2173
|
+
const tail = yield* invoke(() => journal.snapshotTail(runId));
|
|
2174
|
+
if (tail !== undefined)
|
|
2175
|
+
return this.summarize(runId, tail);
|
|
2176
|
+
if (summarized === undefined && version.seq === 0)
|
|
2177
|
+
return;
|
|
2178
|
+
return yield* this.rebuild(runId);
|
|
2179
|
+
}
|
|
2146
2180
|
if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
|
|
2147
2181
|
return;
|
|
2148
|
-
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
2182
|
+
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
2183
|
+
return yield* this.extend(runId);
|
|
2184
|
+
yield* this.rebuild(runId);
|
|
2185
|
+
}
|
|
2186
|
+
*extend(runId) {
|
|
2187
|
+
const folded = this.sequences.get(runId) ?? 0;
|
|
2188
|
+
if (folded > 0) {
|
|
2149
2189
|
const entries = yield* this.entries(runId, folded);
|
|
2150
2190
|
if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
|
|
2151
2191
|
for (const entry of entries)
|
|
@@ -2173,6 +2213,7 @@ class JournalDurableBackend {
|
|
|
2173
2213
|
this.leases.delete(runId);
|
|
2174
2214
|
this.sequences.delete(runId);
|
|
2175
2215
|
this.foldedAt.delete(runId);
|
|
2216
|
+
this.summarized.delete(runId);
|
|
2176
2217
|
this.prompts.delete(runId);
|
|
2177
2218
|
this.projection.deleteWorkflow(runId);
|
|
2178
2219
|
}
|
|
@@ -2537,7 +2578,8 @@ class SqlRunJournal {
|
|
|
2537
2578
|
this.legacy = legacy;
|
|
2538
2579
|
registerRunJournalVersions(this, {
|
|
2539
2580
|
changeToken: () => this.changeToken(),
|
|
2540
|
-
runVersions: () => this.runVersions()
|
|
2581
|
+
runVersions: () => this.runVersions(),
|
|
2582
|
+
snapshotTail: (runId) => this.snapshotTail(runId)
|
|
2541
2583
|
});
|
|
2542
2584
|
registerSqlPoolStorage(this, {
|
|
2543
2585
|
transaction: (body) => this.operation(() => this.database.transaction(body)),
|
|
@@ -2663,6 +2705,28 @@ class SqlRunJournal {
|
|
|
2663
2705
|
]));
|
|
2664
2706
|
});
|
|
2665
2707
|
}
|
|
2708
|
+
async snapshotTail(runId) {
|
|
2709
|
+
this.assertOpen();
|
|
2710
|
+
validateText("runId", runId);
|
|
2711
|
+
return this.operation(async () => {
|
|
2712
|
+
const events = await this.isUnconvertedLegacyRun(runId) ? JOURNAL_TABLES.events : this.tables.events;
|
|
2713
|
+
const later = `FROM ${events} AS later WHERE later.${JOURNAL_COLUMNS.runId} = snapshot.${JOURNAL_COLUMNS.runId} AND later.${JOURNAL_COLUMNS.seq} > snapshot.${JOURNAL_COLUMNS.seq} AND later.${JOURNAL_COLUMNS.type} = ?`;
|
|
2714
|
+
const row = await this.database.get(`SELECT ${EVENT_COLUMNS.map((column) => `snapshot.${column}`).join(", ")},
|
|
2715
|
+
latest.${JOURNAL_COLUMNS.seq} AS latest_seq, latest.${JOURNAL_COLUMNS.at} AS latest_at,
|
|
2716
|
+
(SELECT count(*) ${later}) AS later_checkpoints,
|
|
2717
|
+
(SELECT json_extract(later.${JOURNAL_COLUMNS.payload}, '$.completedAt') ${later} ORDER BY later.${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS last_checkpoint_at
|
|
2718
|
+
FROM (SELECT ${JOURNAL_COLUMNS.seq}, ${JOURNAL_COLUMNS.at} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS latest,
|
|
2719
|
+
(SELECT ${EVENT_COLUMNS.join(", ")} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.type} NOT IN (${NON_SNAPSHOT_EVENT_TYPES.map(() => "?").join(", ")}) ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS snapshot`, RUN_EVENT_TYPES.checkpointRecorded, RUN_EVENT_TYPES.checkpointRecorded, runId, runId, ...NON_SNAPSHOT_EVENT_TYPES);
|
|
2720
|
+
if (row === undefined)
|
|
2721
|
+
return;
|
|
2722
|
+
return {
|
|
2723
|
+
version: { seq: journalCounter(runId, "seq", row.latest_seq), at: Number(row.latest_at) },
|
|
2724
|
+
snapshot: entryFromRow(row),
|
|
2725
|
+
laterCheckpoints: Number(row.later_checkpoints),
|
|
2726
|
+
...row.last_checkpoint_at === null ? {} : { lastCheckpointAt: Number(row.last_checkpoint_at) }
|
|
2727
|
+
};
|
|
2728
|
+
});
|
|
2729
|
+
}
|
|
2666
2730
|
async requireRun(tx, runId) {
|
|
2667
2731
|
if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
|
|
2668
2732
|
return;
|
|
@@ -2880,13 +2944,14 @@ class SqlRunJournal {
|
|
|
2880
2944
|
return this.closePromise;
|
|
2881
2945
|
}
|
|
2882
2946
|
}
|
|
2883
|
-
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)";
|
|
2947
|
+
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", EVENT_COLUMNS;
|
|
2884
2948
|
var init_sql_run_journal = __esm(() => {
|
|
2885
2949
|
init_internal();
|
|
2886
2950
|
init_legacy_journal_tables();
|
|
2887
2951
|
init_types();
|
|
2888
2952
|
init_values();
|
|
2889
2953
|
init_internal();
|
|
2954
|
+
EVENT_COLUMNS = [JOURNAL_COLUMNS.runId, JOURNAL_COLUMNS.seq, JOURNAL_COLUMNS.epoch, JOURNAL_COLUMNS.key, JOURNAL_COLUMNS.type, JOURNAL_COLUMNS.payload, JOURNAL_COLUMNS.at];
|
|
2890
2955
|
});
|
|
2891
2956
|
|
|
2892
2957
|
// dist/builtin/workflows/src/durable/journal/resolution.ts
|
|
@@ -5679,7 +5744,13 @@ async function initializeDurableBackend(options = {}) {
|
|
|
5679
5744
|
const selected = owner.selectedBackends;
|
|
5680
5745
|
const existing = selected.get(key);
|
|
5681
5746
|
const entry = existing ?? {
|
|
5682
|
-
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal })).then((opened) => {
|
|
5747
|
+
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal, runs: [] })).then(async (opened) => {
|
|
5748
|
+
try {
|
|
5749
|
+
await opened.hydrateResumableWorkflows();
|
|
5750
|
+
} catch (error) {
|
|
5751
|
+
await opened.close();
|
|
5752
|
+
throw error;
|
|
5753
|
+
}
|
|
5683
5754
|
if (ownsJournal)
|
|
5684
5755
|
opened.closeOnProcessExit();
|
|
5685
5756
|
entry.close = () => opened.close();
|
|
@@ -60525,6 +60596,57 @@ var init_types2 = __esm(() => {
|
|
|
60525
60596
|
});
|
|
60526
60597
|
});
|
|
60527
60598
|
|
|
60599
|
+
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
60600
|
+
function isInfrastructureError(value2) {
|
|
60601
|
+
if (value2 instanceof WorkflowInfrastructureError)
|
|
60602
|
+
return true;
|
|
60603
|
+
if (typeof value2 !== "object" || value2 === null)
|
|
60604
|
+
return false;
|
|
60605
|
+
const candidate = value2;
|
|
60606
|
+
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
60607
|
+
}
|
|
60608
|
+
function isRetryableWorkflowError(error) {
|
|
60609
|
+
let current = error;
|
|
60610
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
|
|
60611
|
+
if (isInfrastructureError(current))
|
|
60612
|
+
return true;
|
|
60613
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
60614
|
+
}
|
|
60615
|
+
return false;
|
|
60616
|
+
}
|
|
60617
|
+
function workflowInfrastructureFault(message) {
|
|
60618
|
+
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
60619
|
+
}
|
|
60620
|
+
function asWorkflowInfrastructureError(error) {
|
|
60621
|
+
if (isInfrastructureError(error))
|
|
60622
|
+
return error;
|
|
60623
|
+
if (!(error instanceof Error))
|
|
60624
|
+
return;
|
|
60625
|
+
const code = workflowInfrastructureFault(error.message);
|
|
60626
|
+
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
60627
|
+
}
|
|
60628
|
+
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
60629
|
+
var init_workflow_infrastructure_error = __esm(() => {
|
|
60630
|
+
FAULT_PATTERNS = [
|
|
60631
|
+
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
60632
|
+
[/Local worker retry limit/, "worker_retry_limit"],
|
|
60633
|
+
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
60634
|
+
[/Worker exited before delivery acknowledgement/, "worker_lost"],
|
|
60635
|
+
[/Stale work lease/, "stale_work_lease"],
|
|
60636
|
+
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
60637
|
+
[/Storage unavailable/, "storage_unavailable"]
|
|
60638
|
+
];
|
|
60639
|
+
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
60640
|
+
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
60641
|
+
retryable = true;
|
|
60642
|
+
code;
|
|
60643
|
+
constructor(code, message, options) {
|
|
60644
|
+
super(message, options);
|
|
60645
|
+
this.code = code;
|
|
60646
|
+
}
|
|
60647
|
+
};
|
|
60648
|
+
});
|
|
60649
|
+
|
|
60528
60650
|
// dist/builtin/workflows/src/workflows/registry.ts
|
|
60529
60651
|
function makeRegistry(store) {
|
|
60530
60652
|
return {
|
|
@@ -60596,11 +60718,13 @@ __export(exports_sdk_surface, {
|
|
|
60596
60718
|
StaleLeaseError: () => StaleLeaseError,
|
|
60597
60719
|
StorageUnavailableError: () => StorageUnavailableError,
|
|
60598
60720
|
WORKFLOW_HEARTBEAT_CUSTOM_TYPE: () => WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
|
|
60721
|
+
WorkflowInfrastructureError: () => WorkflowInfrastructureError,
|
|
60599
60722
|
cancellationRegistry: () => cancellationRegistry,
|
|
60600
60723
|
createAgentSessionAdapter: () => createAgentSessionAdapter,
|
|
60601
60724
|
createCancellationRegistry: () => createCancellationRegistry,
|
|
60602
60725
|
createRegistry: () => createRegistry,
|
|
60603
60726
|
createStore: () => createStore,
|
|
60727
|
+
isRetryableWorkflowError: () => isRetryableWorkflowError,
|
|
60604
60728
|
keepContext: () => keepContext,
|
|
60605
60729
|
loadWorkerWorkflow: () => loadWorkerWorkflow,
|
|
60606
60730
|
normalizeWorkflowName: () => normalizeWorkflowName,
|
|
@@ -60627,6 +60751,7 @@ var init_sdk_surface = __esm(() => {
|
|
|
60627
60751
|
init_worktree();
|
|
60628
60752
|
init_store();
|
|
60629
60753
|
init_types2();
|
|
60754
|
+
init_workflow_infrastructure_error();
|
|
60630
60755
|
init_definitions();
|
|
60631
60756
|
init_registry();
|
|
60632
60757
|
init_types();
|
|
@@ -61038,7 +61163,7 @@ class SqlPoolQueue {
|
|
|
61038
61163
|
});
|
|
61039
61164
|
const row = await this.current(tx, lease, token);
|
|
61040
61165
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
61041
|
-
throw new Error(
|
|
61166
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61042
61167
|
assertSession();
|
|
61043
61168
|
}, action);
|
|
61044
61169
|
}
|
|
@@ -61047,7 +61172,7 @@ class SqlPoolQueue {
|
|
|
61047
61172
|
const { now } = await this.authority(tx, lease);
|
|
61048
61173
|
const row = await this.current(tx, lease, token);
|
|
61049
61174
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
61050
|
-
throw new Error(
|
|
61175
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61051
61176
|
});
|
|
61052
61177
|
}
|
|
61053
61178
|
async enqueue(lease, descriptor, boundary) {
|
|
@@ -61127,7 +61252,7 @@ class SqlPoolQueue {
|
|
|
61127
61252
|
async current(tx, lease, token, allowCompleted = false) {
|
|
61128
61253
|
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
61129
61254
|
if (row?.state !== "leased" && !(allowCompleted && row?.state === "completed") || row.epoch !== token.epoch || row.generation !== token.generation || row.worker !== token.worker)
|
|
61130
|
-
throw new Error(
|
|
61255
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61131
61256
|
return row;
|
|
61132
61257
|
}
|
|
61133
61258
|
async renew(lease, token, operationId, durationMs) {
|
|
@@ -61140,7 +61265,7 @@ class SqlPoolQueue {
|
|
|
61140
61265
|
const { now } = await this.authority(tx, lease);
|
|
61141
61266
|
const row = await this.current(tx, lease, token);
|
|
61142
61267
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
61143
|
-
throw new Error(
|
|
61268
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61144
61269
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
61145
61270
|
if (previous) {
|
|
61146
61271
|
if (previous.request !== request)
|
|
@@ -61168,7 +61293,7 @@ class SqlPoolQueue {
|
|
|
61168
61293
|
const { now, status } = await this.authority(tx, lease);
|
|
61169
61294
|
const row = await this.current(tx, lease, token);
|
|
61170
61295
|
if (row.epoch !== lease.epoch)
|
|
61171
|
-
throw new Error(
|
|
61296
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61172
61297
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
61173
61298
|
if (previous) {
|
|
61174
61299
|
if (previous.request !== request)
|
|
@@ -61176,7 +61301,7 @@ class SqlPoolQueue {
|
|
|
61176
61301
|
return JSON.parse(previous.receipt);
|
|
61177
61302
|
}
|
|
61178
61303
|
if (row.expires_at < now)
|
|
61179
|
-
throw new Error(
|
|
61304
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61180
61305
|
if (!await this.admitsAttemptWrites(tx, lease, status))
|
|
61181
61306
|
throw new Error("Pool root is not running");
|
|
61182
61307
|
const checkpoint = mutation.checkpoint;
|
|
@@ -61216,7 +61341,7 @@ class SqlPoolQueue {
|
|
|
61216
61341
|
const { now, status } = await this.authority(tx, lease);
|
|
61217
61342
|
const row = await this.current(tx, lease, token, true);
|
|
61218
61343
|
if (row.epoch !== lease.epoch)
|
|
61219
|
-
throw new Error(
|
|
61344
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61220
61345
|
if (row.state === "completed") {
|
|
61221
61346
|
const previous = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, token.id);
|
|
61222
61347
|
if (previous?.result !== payload)
|
|
@@ -61224,7 +61349,7 @@ class SqlPoolQueue {
|
|
|
61224
61349
|
return;
|
|
61225
61350
|
}
|
|
61226
61351
|
if (row.expires_at < now || !await this.admitsAttemptWrites(tx, lease, status))
|
|
61227
|
-
throw new Error(
|
|
61352
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61228
61353
|
if (JSON.parse(payload).runId !== fromRow(row).childRunId)
|
|
61229
61354
|
throw new Error("Pool result identity mismatch");
|
|
61230
61355
|
await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
|
|
@@ -61249,6 +61374,40 @@ class SqlPoolQueue {
|
|
|
61249
61374
|
return true;
|
|
61250
61375
|
});
|
|
61251
61376
|
}
|
|
61377
|
+
async extend(lease, token, durationMs) {
|
|
61378
|
+
positive(durationMs);
|
|
61379
|
+
lease = snapshotLease(lease);
|
|
61380
|
+
token = { ...token };
|
|
61381
|
+
return this.transaction(async (tx) => {
|
|
61382
|
+
const { now } = await this.authority(tx, lease);
|
|
61383
|
+
const row = await this.current(tx, lease, token);
|
|
61384
|
+
if (row.epoch !== lease.epoch)
|
|
61385
|
+
throw new Error(STALE_WORK_LEASE);
|
|
61386
|
+
const expiresAt = Math.max(Number(row.expires_at), expiry(now, durationMs));
|
|
61387
|
+
await tx.run(`UPDATE ${this.work} SET expires_at = ?, renewed_at = ? WHERE id = ?`, expiresAt, now, row.id);
|
|
61388
|
+
return { ...fromRow(row), expiresAt, renewedAt: now };
|
|
61389
|
+
});
|
|
61390
|
+
}
|
|
61391
|
+
async releaseExited(lease, token) {
|
|
61392
|
+
lease = snapshotLease(lease);
|
|
61393
|
+
token = { ...token };
|
|
61394
|
+
return this.transaction(async (tx) => {
|
|
61395
|
+
await this.authority(tx, lease);
|
|
61396
|
+
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
61397
|
+
if (row?.state !== "leased" || row.generation !== token.generation || row.worker !== token.worker || row.epoch !== token.epoch)
|
|
61398
|
+
return false;
|
|
61399
|
+
await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE id = ?`, row.id);
|
|
61400
|
+
return true;
|
|
61401
|
+
});
|
|
61402
|
+
}
|
|
61403
|
+
async releasePreviousIncarnations(lease) {
|
|
61404
|
+
lease = snapshotLease(lease);
|
|
61405
|
+
return this.transaction(async (tx) => {
|
|
61406
|
+
await this.authority(tx, lease);
|
|
61407
|
+
const released = await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE root = ? AND state = 'leased' AND epoch < ?`, lease.runId, lease.epoch);
|
|
61408
|
+
return released.changes;
|
|
61409
|
+
});
|
|
61410
|
+
}
|
|
61252
61411
|
async inspect(root) {
|
|
61253
61412
|
return this.transaction(async (tx) => (await tx.all(`SELECT * FROM ${this.work} WHERE root = ? ORDER BY ready_at, rowid`, root)).map(fromRow));
|
|
61254
61413
|
}
|
|
@@ -61259,7 +61418,7 @@ function openSqlPoolQueue(journal) {
|
|
|
61259
61418
|
return Promise.reject(new Error("Worker pool requires a SQL run journal"));
|
|
61260
61419
|
return SqlPoolQueue.open(storage);
|
|
61261
61420
|
}
|
|
61262
|
-
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000;
|
|
61421
|
+
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000, STALE_WORK_LEASE = "Stale work lease";
|
|
61263
61422
|
var init_sql_pool_queue = __esm(() => {
|
|
61264
61423
|
init_serializable();
|
|
61265
61424
|
init_boundary_topology();
|
|
@@ -61347,6 +61506,9 @@ var init_host_options = __esm(() => {
|
|
|
61347
61506
|
hostWorkerBindings = Symbol("host-worker-bindings");
|
|
61348
61507
|
});
|
|
61349
61508
|
|
|
61509
|
+
// dist/builtin/workflows/src/workers/protocol.ts
|
|
61510
|
+
var WORKER_HEARTBEAT_INTERVAL_MS = 1000;
|
|
61511
|
+
|
|
61350
61512
|
// dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
|
|
61351
61513
|
function isWorkflowPendingStageDeliveryFailure(error) {
|
|
61352
61514
|
if (error instanceof WorkflowPendingStageDeliveryFailedError)
|
|
@@ -61886,20 +62048,33 @@ var init_stage_handoff = __esm(() => {
|
|
|
61886
62048
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
61887
62049
|
import { fork } from "node:child_process";
|
|
61888
62050
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
61889
|
-
import {
|
|
62051
|
+
import { createWriteStream } from "node:fs";
|
|
62052
|
+
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
62053
|
+
import { dirname as dirname12, join as join28, resolve as resolve11 } from "node:path";
|
|
61890
62054
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
61891
62055
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
61892
62056
|
import { isBunBinary as isBunBinary2 } from "@bastani/atomic";
|
|
62057
|
+
function workerLogDirectory(journalPath, root) {
|
|
62058
|
+
return join28(dirname12(resolve11(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
62059
|
+
}
|
|
61893
62060
|
|
|
61894
62061
|
class LocalWorkerPool {
|
|
61895
62062
|
backend;
|
|
61896
62063
|
options;
|
|
61897
62064
|
children = new Set;
|
|
61898
62065
|
incarnations = new Map;
|
|
62066
|
+
readyWorkers = new Set;
|
|
62067
|
+
logs = new Map;
|
|
62068
|
+
logDirectory;
|
|
61899
62069
|
cleanups = new Set;
|
|
61900
62070
|
recovering;
|
|
61901
62071
|
nextRecoveryAt = 0;
|
|
61902
62072
|
controlAcks = new Map;
|
|
62073
|
+
lastHeard = new Map;
|
|
62074
|
+
lastTick = performance.now();
|
|
62075
|
+
rootStalledMs = 0;
|
|
62076
|
+
ticker;
|
|
62077
|
+
leaseMs;
|
|
61903
62078
|
desiredControl;
|
|
61904
62079
|
root;
|
|
61905
62080
|
store;
|
|
@@ -61923,9 +62098,15 @@ class LocalWorkerPool {
|
|
|
61923
62098
|
this.options = options;
|
|
61924
62099
|
if (!Number.isSafeInteger(options.workers) || options.workers < 1)
|
|
61925
62100
|
throw new Error("Invalid local worker count");
|
|
62101
|
+
if (options.startupTimeoutMs !== undefined && (!Number.isSafeInteger(options.startupTimeoutMs) || options.startupTimeoutMs < 1 || options.startupTimeoutMs > MAX_TIMER_DELAY_MS))
|
|
62102
|
+
throw new Error("Invalid local worker startup timeout");
|
|
62103
|
+
if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
|
|
62104
|
+
throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
|
|
62105
|
+
this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
|
|
61926
62106
|
this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
|
|
61927
62107
|
if (options.admission && options.rootId === undefined)
|
|
61928
62108
|
workflowResourceAdmission.set(backend, options.admission);
|
|
62109
|
+
this.ticker = setInterval(() => this.observeResponsiveness(), ROOT_TICK_INTERVAL_MS).unref();
|
|
61929
62110
|
}
|
|
61930
62111
|
get workerPids() {
|
|
61931
62112
|
return [...this.children].flatMap((child) => child.pid === undefined ? [] : [child.pid]);
|
|
@@ -61951,6 +62132,7 @@ class LocalWorkerPool {
|
|
|
61951
62132
|
this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
|
|
61952
62133
|
const queue = await openSqlPoolQueue(this.backend.journal);
|
|
61953
62134
|
await queue.initialize(this.lease, COORDINATOR_LEASE_MS);
|
|
62135
|
+
await queue.releasePreviousIncarnations(this.lease);
|
|
61954
62136
|
for (;; ) {
|
|
61955
62137
|
const intended = this.desiredControl ?? "running";
|
|
61956
62138
|
await queue.setControl(this.lease, intended);
|
|
@@ -61965,8 +62147,8 @@ class LocalWorkerPool {
|
|
|
61965
62147
|
if (!this.queue || !this.lease)
|
|
61966
62148
|
return;
|
|
61967
62149
|
const control = await this.queue.setControl(this.lease, state);
|
|
61968
|
-
const deadline = Date.now() +
|
|
61969
|
-
while ([...this.
|
|
62150
|
+
const deadline = Date.now() + CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS;
|
|
62151
|
+
while ([...this.readyWorkers].some((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision)) {
|
|
61970
62152
|
if (this.desiredControl !== state)
|
|
61971
62153
|
return;
|
|
61972
62154
|
if (Date.now() >= deadline) {
|
|
@@ -62036,7 +62218,16 @@ class LocalWorkerPool {
|
|
|
62036
62218
|
root,
|
|
62037
62219
|
holder: "coordinator"
|
|
62038
62220
|
});
|
|
62039
|
-
|
|
62221
|
+
this.logDirectory = workerLogDirectory(this.options.journalPath, root);
|
|
62222
|
+
await mkdir6(this.logDirectory, { recursive: true }).catch(() => {
|
|
62223
|
+
return;
|
|
62224
|
+
});
|
|
62225
|
+
const workers = Array.from({ length: this.options.workers }, () => this.spawn(root));
|
|
62226
|
+
try {
|
|
62227
|
+
await Promise.any(workers);
|
|
62228
|
+
} catch (error) {
|
|
62229
|
+
throw error.errors[0];
|
|
62230
|
+
}
|
|
62040
62231
|
}
|
|
62041
62232
|
spawn(root) {
|
|
62042
62233
|
if (this.closed)
|
|
@@ -62057,26 +62248,56 @@ class LocalWorkerPool {
|
|
|
62057
62248
|
let serial = Promise.resolve();
|
|
62058
62249
|
let work;
|
|
62059
62250
|
const deliveries = new Map;
|
|
62251
|
+
const logPath = join28(this.logDirectory, `${worker}.log`);
|
|
62252
|
+
this.logs.set(child, logPath);
|
|
62253
|
+
let logFailure;
|
|
62254
|
+
const log = createWriteStream(logPath, { flags: "a" });
|
|
62255
|
+
log.on("error", (error) => {
|
|
62256
|
+
logFailure = error.message;
|
|
62257
|
+
});
|
|
62060
62258
|
let stderr = "";
|
|
62061
62259
|
child.stderr?.on("data", (chunk) => {
|
|
62062
|
-
stderr = (stderr + chunk.toString()).slice(-
|
|
62260
|
+
stderr = (stderr + chunk.toString()).slice(-STDERR_TAIL_CHARACTERS);
|
|
62261
|
+
});
|
|
62262
|
+
child.stderr?.on("error", (error) => {
|
|
62263
|
+
logFailure ??= error.message;
|
|
62264
|
+
log.end();
|
|
62063
62265
|
});
|
|
62266
|
+
child.stderr?.pipe(log);
|
|
62267
|
+
const diagnosed = (summary) => new Error(`${summary} (worker stderr log: ${logFailure === undefined ? logPath : `unavailable, ${logFailure}`})${stderr ? `: ${stderr}` : ""}`);
|
|
62268
|
+
const startupTimeoutMs = this.options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
62269
|
+
let timedOut = false;
|
|
62270
|
+
let terminated = false;
|
|
62271
|
+
const terminate = () => {
|
|
62272
|
+
if (terminated)
|
|
62273
|
+
return;
|
|
62274
|
+
terminated = true;
|
|
62275
|
+
child.kill("SIGKILL");
|
|
62276
|
+
};
|
|
62277
|
+
const replied = (error) => {
|
|
62278
|
+
if (error)
|
|
62279
|
+
terminate();
|
|
62280
|
+
};
|
|
62064
62281
|
return new Promise((resolve, reject) => {
|
|
62065
62282
|
const startup = setTimeout(() => {
|
|
62066
|
-
|
|
62067
|
-
|
|
62068
|
-
|
|
62069
|
-
|
|
62070
|
-
child.once("error", (error) => {
|
|
62283
|
+
timedOut = true;
|
|
62284
|
+
terminate();
|
|
62285
|
+
}, startupTimeoutMs);
|
|
62286
|
+
child.on("error", (error) => {
|
|
62071
62287
|
clearTimeout(startup);
|
|
62072
62288
|
reject(error);
|
|
62289
|
+
terminate();
|
|
62073
62290
|
});
|
|
62291
|
+
const closed = new Promise((resolve) => child.once("close", () => resolve()));
|
|
62074
62292
|
child.once("exit", () => {
|
|
62293
|
+
Promise.race([closed, delay2(STDERR_DRAIN_GRACE_MS)]).then(() => reject(diagnosed(timedOut ? `Local worker startup timed out after ${startupTimeoutMs} ms` : "Local worker exited before readiness")));
|
|
62075
62294
|
this.children.delete(child);
|
|
62295
|
+
this.logs.delete(child);
|
|
62076
62296
|
clearTimeout(startup);
|
|
62077
62297
|
this.incarnations.delete(worker);
|
|
62078
|
-
|
|
62298
|
+
this.readyWorkers.delete(worker);
|
|
62079
62299
|
this.controlAcks.delete(worker);
|
|
62300
|
+
this.lastHeard.delete(worker);
|
|
62080
62301
|
if (work)
|
|
62081
62302
|
this.handoff?.fence(work);
|
|
62082
62303
|
for (const delivery of deliveries.values())
|
|
@@ -62099,9 +62320,11 @@ class LocalWorkerPool {
|
|
|
62099
62320
|
}
|
|
62100
62321
|
if (this.closed)
|
|
62101
62322
|
return;
|
|
62323
|
+
if (work)
|
|
62324
|
+
await this.queue.releaseExited(this.lease, work);
|
|
62102
62325
|
const exhausted = work ? work.generation >= 3 : ++this.replacements > 3;
|
|
62103
62326
|
if (exhausted)
|
|
62104
|
-
this.failure =
|
|
62327
|
+
this.failure = diagnosed("Local worker retry limit");
|
|
62105
62328
|
else
|
|
62106
62329
|
await this.spawn(root);
|
|
62107
62330
|
}).catch((error) => {
|
|
@@ -62111,6 +62334,8 @@ class LocalWorkerPool {
|
|
|
62111
62334
|
cleanup.finally(() => this.cleanups.delete(cleanup));
|
|
62112
62335
|
});
|
|
62113
62336
|
child.on("message", (message) => {
|
|
62337
|
+
this.observeResponsiveness();
|
|
62338
|
+
this.lastHeard.set(worker, { at: performance.now(), rootStalled: this.rootStalledMs });
|
|
62114
62339
|
if (message.kind === "delivery-ack") {
|
|
62115
62340
|
const pending = deliveries.get(message.deliveryId);
|
|
62116
62341
|
deliveries.delete(message.deliveryId);
|
|
@@ -62122,7 +62347,10 @@ class LocalWorkerPool {
|
|
|
62122
62347
|
}
|
|
62123
62348
|
const response = serial.then(async () => {
|
|
62124
62349
|
if (message.kind === "ready") {
|
|
62350
|
+
if (terminated)
|
|
62351
|
+
return;
|
|
62125
62352
|
ready = true;
|
|
62353
|
+
this.readyWorkers.add(worker);
|
|
62126
62354
|
clearTimeout(startup);
|
|
62127
62355
|
resolve();
|
|
62128
62356
|
return;
|
|
@@ -62149,11 +62377,13 @@ class LocalWorkerPool {
|
|
|
62149
62377
|
work = await queue.claim(lease, worker, this.sources.map((source) => ({
|
|
62150
62378
|
definition: `${source.path}#${source.exportName}`,
|
|
62151
62379
|
digest: source.digest
|
|
62152
|
-
})),
|
|
62380
|
+
})), this.leaseMs);
|
|
62153
62381
|
return work;
|
|
62154
62382
|
}
|
|
62155
62383
|
if (!work)
|
|
62156
62384
|
throw new Error("Worker has no active attempt");
|
|
62385
|
+
if (message.kind === "renew" || work.expiresAt - Date.now() < this.leaseMs / 2)
|
|
62386
|
+
work = await queue.extend(lease, work, this.leaseMs);
|
|
62157
62387
|
if (message.kind === "activity")
|
|
62158
62388
|
return this.handoff?.publish(work, message.runs);
|
|
62159
62389
|
if (message.kind === "route")
|
|
@@ -62174,10 +62404,8 @@ class LocalWorkerPool {
|
|
|
62174
62404
|
});
|
|
62175
62405
|
}));
|
|
62176
62406
|
}
|
|
62177
|
-
if (message.kind === "renew")
|
|
62178
|
-
work = await queue.renew(lease, work, randomUUID16(), WORK_LEASE_MS);
|
|
62407
|
+
if (message.kind === "renew")
|
|
62179
62408
|
return;
|
|
62180
|
-
}
|
|
62181
62409
|
if (message.kind === "commit") {
|
|
62182
62410
|
const receipt = await queue.commit(lease, work, message.operation, message.mutation);
|
|
62183
62411
|
this.usageTotal = await this.usageLedger.total(root);
|
|
@@ -62202,13 +62430,7 @@ class LocalWorkerPool {
|
|
|
62202
62430
|
});
|
|
62203
62431
|
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
62204
62432
|
serial = response.then(() => {}, () => {});
|
|
62205
|
-
response.then((value2) => {
|
|
62206
|
-
if (child.connected)
|
|
62207
|
-
child.send({ id: message.id, value: value2 });
|
|
62208
|
-
}, (error) => {
|
|
62209
|
-
if (child.connected)
|
|
62210
|
-
child.send({ id: message.id, error: error.message });
|
|
62211
|
-
});
|
|
62433
|
+
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => child.send({ id: message.id, error: error.message }, replied));
|
|
62212
62434
|
});
|
|
62213
62435
|
});
|
|
62214
62436
|
}
|
|
@@ -62218,14 +62440,22 @@ class LocalWorkerPool {
|
|
|
62218
62440
|
if (this.closed || performance.now() < this.nextRecoveryAt)
|
|
62219
62441
|
return Promise.resolve();
|
|
62220
62442
|
this.recovering = (async () => {
|
|
62443
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
62221
62444
|
await this.admission?.reconcile();
|
|
62222
62445
|
const expiredBefore = Date.now();
|
|
62223
62446
|
for (const work of await this.queue.inspect(root)) {
|
|
62224
62447
|
if (work.state !== "leased" || work.expiresAt >= expiredBefore)
|
|
62225
62448
|
continue;
|
|
62226
62449
|
const child = work.worker === null ? undefined : this.incarnations.get(work.worker);
|
|
62227
|
-
if (child)
|
|
62228
|
-
await this.
|
|
62450
|
+
if (child && work.worker !== null && this.isLive(work.worker, child)) {
|
|
62451
|
+
await this.queue.extend(this.lease, work, this.leaseMs).catch((error) => {
|
|
62452
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
62453
|
+
throw error;
|
|
62454
|
+
});
|
|
62455
|
+
continue;
|
|
62456
|
+
}
|
|
62457
|
+
if (child && !await this.stop(child).then(() => true, () => false))
|
|
62458
|
+
continue;
|
|
62229
62459
|
await this.queue.expire(this.lease, work);
|
|
62230
62460
|
}
|
|
62231
62461
|
})().finally(() => {
|
|
@@ -62234,6 +62464,18 @@ class LocalWorkerPool {
|
|
|
62234
62464
|
});
|
|
62235
62465
|
return this.recovering;
|
|
62236
62466
|
}
|
|
62467
|
+
observeResponsiveness() {
|
|
62468
|
+
const now = performance.now();
|
|
62469
|
+
const gap = now - this.lastTick;
|
|
62470
|
+
if (gap > ROOT_STALL_THRESHOLD_MS)
|
|
62471
|
+
this.rootStalledMs += gap - ROOT_TICK_INTERVAL_MS;
|
|
62472
|
+
this.lastTick = now;
|
|
62473
|
+
}
|
|
62474
|
+
isLive(worker, child) {
|
|
62475
|
+
this.observeResponsiveness();
|
|
62476
|
+
const heard = this.lastHeard.get(worker);
|
|
62477
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.rootStalledMs - heard.rootStalled) < this.leaseMs;
|
|
62478
|
+
}
|
|
62237
62479
|
stop(child) {
|
|
62238
62480
|
if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
62239
62481
|
return Promise.resolve();
|
|
@@ -62250,9 +62492,13 @@ class LocalWorkerPool {
|
|
|
62250
62492
|
try {
|
|
62251
62493
|
return await this.dispatch(definition, inputs, options);
|
|
62252
62494
|
} catch (error) {
|
|
62253
|
-
|
|
62254
|
-
|
|
62255
|
-
|
|
62495
|
+
try {
|
|
62496
|
+
if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
|
|
62497
|
+
await this.close();
|
|
62498
|
+
} catch (closeError) {
|
|
62499
|
+
throw asWorkflowInfrastructureError(closeError) ?? closeError;
|
|
62500
|
+
}
|
|
62501
|
+
throw asWorkflowInfrastructureError(error) ?? error;
|
|
62256
62502
|
}
|
|
62257
62503
|
}
|
|
62258
62504
|
async dispatch(definition, inputs, options) {
|
|
@@ -62296,6 +62542,8 @@ class LocalWorkerPool {
|
|
|
62296
62542
|
for (;; ) {
|
|
62297
62543
|
options.signal?.throwIfAborted();
|
|
62298
62544
|
if (this.closed) {
|
|
62545
|
+
if (this.failure)
|
|
62546
|
+
throw this.failure;
|
|
62299
62547
|
if (this.desiredControl === "quit")
|
|
62300
62548
|
throw new WorkflowGracefulQuitError(root, "worker pool teardown");
|
|
62301
62549
|
throw new Error("Local worker pool is closed");
|
|
@@ -62322,19 +62570,28 @@ class LocalWorkerPool {
|
|
|
62322
62570
|
}
|
|
62323
62571
|
async dispose() {
|
|
62324
62572
|
this.closed = true;
|
|
62573
|
+
clearInterval(this.ticker);
|
|
62325
62574
|
this.releaseBinding();
|
|
62326
62575
|
if (this.options.rootId === undefined)
|
|
62327
62576
|
workflowResourceAdmission.delete(this.backend);
|
|
62328
62577
|
let failure;
|
|
62578
|
+
let stopping = [];
|
|
62329
62579
|
try {
|
|
62330
62580
|
await this.recovering?.catch(() => {});
|
|
62331
|
-
|
|
62581
|
+
stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
|
|
62582
|
+
await Promise.all(stopping.map(({ child }) => this.stop(child)));
|
|
62332
62583
|
await Promise.all([...this.cleanups]);
|
|
62333
62584
|
if (this.cleanupFailure)
|
|
62334
62585
|
throw this.cleanupFailure;
|
|
62335
62586
|
} catch (error) {
|
|
62336
62587
|
failure = error;
|
|
62337
62588
|
}
|
|
62589
|
+
if (failure === undefined) {
|
|
62590
|
+
const stopped = stopping.flatMap(({ child, log }) => log !== undefined && (child.exitCode !== null || child.signalCode !== null) ? [log] : []);
|
|
62591
|
+
await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
|
|
62592
|
+
if (this.logDirectory !== undefined)
|
|
62593
|
+
await rmdir(this.logDirectory).catch(() => {});
|
|
62594
|
+
}
|
|
62338
62595
|
try {
|
|
62339
62596
|
await this.releaseRoutes?.();
|
|
62340
62597
|
} catch (error) {
|
|
@@ -62344,7 +62601,7 @@ class LocalWorkerPool {
|
|
|
62344
62601
|
throw failure;
|
|
62345
62602
|
}
|
|
62346
62603
|
}
|
|
62347
|
-
var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker",
|
|
62604
|
+
var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker", DEFAULT_WORK_LEASE_MS = 30000, MINIMUM_WORK_LEASE_MS, CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS = 5000, RECOVERY_INTERVAL_MS = 500, ROOT_TICK_INTERVAL_MS = 100, ROOT_STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, DEFAULT_STARTUP_TIMEOUT_MS = 30000, MAX_TIMER_DELAY_MS = 2147483647, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000;
|
|
62348
62605
|
var init_local_pool = __esm(() => {
|
|
62349
62606
|
init_internal();
|
|
62350
62607
|
init_sql_pool_queue();
|
|
@@ -62352,12 +62609,14 @@ var init_local_pool = __esm(() => {
|
|
|
62352
62609
|
init_sql_run_journal();
|
|
62353
62610
|
init_workflow_tool_abort();
|
|
62354
62611
|
init_sdk_intercom();
|
|
62612
|
+
init_workflow_infrastructure_error();
|
|
62355
62613
|
init_admission_binding();
|
|
62356
62614
|
init_definitions();
|
|
62357
62615
|
init_dispatch();
|
|
62358
62616
|
init_host_options();
|
|
62359
62617
|
init_resource_admission();
|
|
62360
62618
|
init_stage_handoff();
|
|
62619
|
+
MINIMUM_WORK_LEASE_MS = 2 * WORKER_HEARTBEAT_INTERVAL_MS;
|
|
62361
62620
|
COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
|
|
62362
62621
|
});
|
|
62363
62622
|
|
|
@@ -62399,6 +62658,8 @@ async function activatePublicPool(backend, options) {
|
|
|
62399
62658
|
const cwd = options.cwd ?? process.cwd();
|
|
62400
62659
|
const localWorkers = options.localWorkers && {
|
|
62401
62660
|
...options.localWorkers,
|
|
62661
|
+
startupTimeoutMs: undefined,
|
|
62662
|
+
leaseMs: undefined,
|
|
62402
62663
|
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve12(cwd, source.path) }))
|
|
62403
62664
|
};
|
|
62404
62665
|
const admission = options.admission && {
|
|
@@ -62427,7 +62688,9 @@ async function activatePublicPool(backend, options) {
|
|
|
62427
62688
|
journalPath: backend.journal.path,
|
|
62428
62689
|
workers: localWorkers.count,
|
|
62429
62690
|
definitions,
|
|
62430
|
-
admission: resources.admission ?? {}
|
|
62691
|
+
admission: resources.admission ?? {},
|
|
62692
|
+
startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
|
|
62693
|
+
leaseMs: options.localWorkers?.leaseMs
|
|
62431
62694
|
});
|
|
62432
62695
|
try {
|
|
62433
62696
|
pool.validateOptions(options);
|
|
@@ -63345,12 +63608,12 @@ function createChildWorkflowRunner(input) {
|
|
|
63345
63608
|
const childExitStatus = isWorkflowExitStatus2(childRun.status) ? childRun.status : "blocked";
|
|
63346
63609
|
if (!isWorkflowExitStatus2(childRun.status) && !childBudgetExceeded || childRun.status === "failed" && childRun.exited !== true) {
|
|
63347
63610
|
const failedChildStage = childRun.stages.find((stage) => stage.failureKind !== undefined);
|
|
63348
|
-
|
|
63349
|
-
|
|
63350
|
-
|
|
63351
|
-
|
|
63352
|
-
|
|
63353
|
-
});
|
|
63611
|
+
const message = `atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`;
|
|
63612
|
+
const cause = {
|
|
63613
|
+
...failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {},
|
|
63614
|
+
...failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}
|
|
63615
|
+
};
|
|
63616
|
+
throw new Error(message, { cause });
|
|
63354
63617
|
}
|
|
63355
63618
|
const outputs = selectWorkflowOutputs(child, childRun.result);
|
|
63356
63619
|
const childExited = childBudgetExceeded || childRun.exited === true || childRun.status !== "completed";
|
|
@@ -63411,7 +63674,7 @@ function describeErrorWithCauses(error) {
|
|
|
63411
63674
|
const messages = [];
|
|
63412
63675
|
const visited = new Set;
|
|
63413
63676
|
let current = error;
|
|
63414
|
-
for (let depth = 0;current !== undefined && depth <
|
|
63677
|
+
for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH2 && !visited.has(current); depth++) {
|
|
63415
63678
|
visited.add(current);
|
|
63416
63679
|
const message = current instanceof Error ? current.message : String(current);
|
|
63417
63680
|
if (!messages.includes(message))
|
|
@@ -63420,7 +63683,7 @@ function describeErrorWithCauses(error) {
|
|
|
63420
63683
|
}
|
|
63421
63684
|
return messages.join(": ");
|
|
63422
63685
|
}
|
|
63423
|
-
var
|
|
63686
|
+
var MAX_CAUSE_DEPTH2 = 5;
|
|
63424
63687
|
|
|
63425
63688
|
// dist/builtin/workflows/src/shared/returned-run-status.ts
|
|
63426
63689
|
function normalizeReturnedWorkflowStatus(status) {
|
|
@@ -63747,7 +64010,7 @@ function hasUsableContentBlock(block) {
|
|
|
63747
64010
|
|
|
63748
64011
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
63749
64012
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
63750
|
-
import { dirname as
|
|
64013
|
+
import { dirname as dirname13, resolve as resolve13 } from "node:path";
|
|
63751
64014
|
import {
|
|
63752
64015
|
JsonlSessionStore,
|
|
63753
64016
|
resolveSessionStore,
|
|
@@ -63784,7 +64047,7 @@ async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
|
63784
64047
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
63785
64048
|
return;
|
|
63786
64049
|
const location = resolve13(sessionFile);
|
|
63787
|
-
const legacy = await JsonlSessionStore.open(
|
|
64050
|
+
const legacy = await JsonlSessionStore.open(dirname13(location), { exactDirectory: true, scanExisting: false });
|
|
63788
64051
|
try {
|
|
63789
64052
|
for await (const file of legacy.scanFiles()) {
|
|
63790
64053
|
if (resolve13(file.location) !== location || file.header.id !== sessionId)
|
|
@@ -64932,7 +65195,7 @@ function recordedOwners(boundary, reason) {
|
|
|
64932
65195
|
const pending = [{ value: reason, depth: 0 }];
|
|
64933
65196
|
while (pending.length > 0) {
|
|
64934
65197
|
const { value: value2, depth } = pending.pop();
|
|
64935
|
-
if (depth >
|
|
65198
|
+
if (depth > MAX_CAUSE_DEPTH3)
|
|
64936
65199
|
continue;
|
|
64937
65200
|
if (isPrimitive(value2)) {
|
|
64938
65201
|
if (depth === 0 || value2 !== undefined && value2 !== null) {
|
|
@@ -65254,7 +65517,7 @@ function containUiRejections(ui, scope) {
|
|
|
65254
65517
|
custom: (factory, options) => scope.watch(ui.custom(factory, options))
|
|
65255
65518
|
};
|
|
65256
65519
|
}
|
|
65257
|
-
var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections",
|
|
65520
|
+
var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections", MAX_CAUSE_DEPTH3 = 8, MAX_PRIMITIVES_PER_RUN = 64, MAX_STOP_STRINGS = 64, ENDED_RUN_GRACE_MS = 30000, NATIVE_REPORTING_MODES, WATCHED_STAGE_METHODS;
|
|
65258
65521
|
var init_run_rejection_boundary = __esm(() => {
|
|
65259
65522
|
init_prompt_callsite();
|
|
65260
65523
|
init_workflow_source();
|
|
@@ -70047,8 +70310,8 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
70047
70310
|
|
|
70048
70311
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
70049
70312
|
import { createHash as createHash4 } from "node:crypto";
|
|
70050
|
-
import { mkdir as
|
|
70051
|
-
import { basename as basename5, dirname as
|
|
70313
|
+
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
70314
|
+
import { basename as basename5, dirname as dirname14, isAbsolute as isAbsolute11, join as join29, resolve as resolve14 } from "node:path";
|
|
70052
70315
|
function normalizeMaxOutput2(maxOutput) {
|
|
70053
70316
|
return {
|
|
70054
70317
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -70111,7 +70374,7 @@ function formatByteSize(bytes) {
|
|
|
70111
70374
|
}
|
|
70112
70375
|
function transcriptPath(runId, outputPath) {
|
|
70113
70376
|
const digest = createHash4("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
70114
|
-
return
|
|
70377
|
+
return join29(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
70115
70378
|
}
|
|
70116
70379
|
function appendContent(lines, content) {
|
|
70117
70380
|
if (typeof content === "string") {
|
|
@@ -70231,7 +70494,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
70231
70494
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
70232
70495
|
const transcript = renderTranscript(messages, fullOutput);
|
|
70233
70496
|
try {
|
|
70234
|
-
await
|
|
70497
|
+
await mkdir7(dirname14(outputPath), { recursive: true });
|
|
70235
70498
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
70236
70499
|
} catch (err) {
|
|
70237
70500
|
return `${displayOutput}
|
|
@@ -70243,7 +70506,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
70243
70506
|
let transcriptError;
|
|
70244
70507
|
try {
|
|
70245
70508
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
70246
|
-
await
|
|
70509
|
+
await mkdir7(dirname14(transcriptFile), { recursive: true });
|
|
70247
70510
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
70248
70511
|
transcriptAvailable = true;
|
|
70249
70512
|
} catch (err) {
|
|
@@ -71152,7 +71415,7 @@ function reportsClosedSession(error) {
|
|
|
71152
71415
|
}
|
|
71153
71416
|
function isSessionClosedError(error) {
|
|
71154
71417
|
let current = error;
|
|
71155
|
-
for (let depth = 0;depth <
|
|
71418
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH4 && current !== undefined; depth++) {
|
|
71156
71419
|
try {
|
|
71157
71420
|
if (reportsClosedSession(current))
|
|
71158
71421
|
return true;
|
|
@@ -71163,7 +71426,7 @@ function isSessionClosedError(error) {
|
|
|
71163
71426
|
}
|
|
71164
71427
|
return false;
|
|
71165
71428
|
}
|
|
71166
|
-
var
|
|
71429
|
+
var MAX_CAUSE_DEPTH4 = 8;
|
|
71167
71430
|
var init_session_closed_error = () => {};
|
|
71168
71431
|
|
|
71169
71432
|
// dist/builtin/workflows/src/engine/workflow-activity.ts
|
|
@@ -72381,7 +72644,7 @@ async function runLocalWorker(start) {
|
|
|
72381
72644
|
return typeof value2 === "function" ? value2.bind(target) : value2;
|
|
72382
72645
|
}
|
|
72383
72646
|
});
|
|
72384
|
-
const reader = await JournalDurableBackend.open(readOnlyJournal);
|
|
72647
|
+
const reader = await JournalDurableBackend.open(readOnlyJournal, { runs: [] });
|
|
72385
72648
|
const sessions = await new StorageProvider3().openSessionStore({ kind: "sqlite", path: start.journalPath, prefix: `${sqlPoolStorage(journal).tables.runs}_pool_` }, { agentDir: "", domain: "sessions" });
|
|
72386
72649
|
const commit = async (mutation) => {
|
|
72387
72650
|
const receipt = await request({
|
|
@@ -72389,7 +72652,7 @@ async function runLocalWorker(start) {
|
|
|
72389
72652
|
operation: randomUUID20(),
|
|
72390
72653
|
mutation
|
|
72391
72654
|
});
|
|
72392
|
-
await reader.
|
|
72655
|
+
await reader.catchUpWorkflow(start.root);
|
|
72393
72656
|
return receipt;
|
|
72394
72657
|
};
|
|
72395
72658
|
const reads = new Set([
|
|
@@ -72466,6 +72729,7 @@ async function runLocalWorker(start) {
|
|
|
72466
72729
|
await delay3(25);
|
|
72467
72730
|
continue;
|
|
72468
72731
|
}
|
|
72732
|
+
await reader.catchUpWorkflow(start.root);
|
|
72469
72733
|
const work = await request({ kind: "claim" });
|
|
72470
72734
|
if (!work) {
|
|
72471
72735
|
await delay3(25 + Math.random() * 25);
|
|
@@ -72474,7 +72738,7 @@ async function runLocalWorker(start) {
|
|
|
72474
72738
|
const index = start.definitions.findIndex((source) => `${source.path}#${source.exportName}` === work.definition && source.digest === work.digest);
|
|
72475
72739
|
if (index < 0)
|
|
72476
72740
|
throw new Error("Worker definition compatibility error");
|
|
72477
|
-
await reader.
|
|
72741
|
+
await reader.catchUpWorkflow(start.root);
|
|
72478
72742
|
const controller = new AbortController;
|
|
72479
72743
|
activeController = controller;
|
|
72480
72744
|
const store = createStore();
|
|
@@ -72579,7 +72843,7 @@ async function runLocalWorker(start) {
|
|
|
72579
72843
|
})().catch(failPulse).finally(() => {
|
|
72580
72844
|
report = undefined;
|
|
72581
72845
|
});
|
|
72582
|
-
},
|
|
72846
|
+
}, WORKER_HEARTBEAT_INTERVAL_MS);
|
|
72583
72847
|
try {
|
|
72584
72848
|
await observeControl();
|
|
72585
72849
|
while ((await request({ kind: "control" })).state !== "running") {
|