@bastani/atomic 0.9.44-alpha.1 → 0.9.44-alpha.3
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 +31 -0
- package/dist/builtin/intercom/CHANGELOG.md +17 -0
- package/dist/builtin/intercom/broker/client-message-validation.ts +6 -0
- package/dist/builtin/intercom/broker/client.ts +4 -0
- package/dist/builtin/intercom/broker/framing.ts +18 -1
- package/dist/builtin/intercom/broker/send-signature.ts +4 -1
- package/dist/builtin/intercom/index.bundle.mjs +101 -18
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/skills/intercom/SKILL.md +1 -0
- package/dist/builtin/intercom/types.ts +8 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/index.bundle.mjs +2510 -1308
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +13 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +363 -37
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +363 -37
- package/dist/builtin/workflows/src/index.js +363 -37
- package/dist/builtin/workflows/src/local-worker-entry.mjs +363 -37
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +59 -0
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +1 -0
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts +4 -0
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +10 -2
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +9 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/builtin-packages.d.ts.map +1 -1
- package/dist/core/builtin-packages.js +13 -13
- package/dist/core/builtin-packages.js.map +1 -1
- package/docs/intercom/operations.md +1 -1
- package/docs/intercom.md +11 -1
- package/docs/subagents.md +9 -1
- package/examples/extensions/gondolin/package-lock.json +3 -3
- package/npm-shrinkwrap.json +67 -51
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.9.44-alpha.
|
|
3
|
+
"version": "0.9.44-alpha.3",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.44-alpha.3] - 2026-10-25
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- A workflow whose stages send many Intercom messages to stage patterns (for example `workflow:<rootRunId>/child-*/**`) no longer saturates the workflow host. The host matched every queued pattern message against every stage on each change; it now indexes the patterns and each stage's paths once. In a 150-child fan-out test, delivered sends went from 566 of 900 to 900 of 900 and host event-loop lag p99 from about 1 s to under 200 ms ([#3931](https://github.com/bastani-inc/atomic/issues/3931))
|
|
14
|
+
- Workflow journal events no longer store a run's whole list of pending stage messages each time. Pattern sends stay queued until the root run ends, so every queued message rewrote the growing list and the journal grew quadratically with the number of sends. Each event now records only what changed; older journals still read as before ([#3929](https://github.com/bastani-inc/atomic/issues/3929))
|
|
15
|
+
|
|
16
|
+
## [0.9.44-alpha.2] - 2026-10-24
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- A sticky Intercom broadcast, such as `workflow:<rootRunId>/**`, that reaches many workflow stages no longer makes the workflow journal grow quadratically. Recording one more delivery used to rewrite every stage's deliveries in the run's queued-message event; each event now stores only the deliveries that changed since the run's previous event. In a 160-worker run this shrinks those events from about 160 MB to about 9 MB. Journals written by earlier versions read and resume unchanged ([#3920](https://github.com/bastani-inc/atomic/issues/3920))
|
|
21
|
+
|
|
9
22
|
## [0.9.44-alpha.1] - 2026-10-24
|
|
10
23
|
|
|
11
24
|
### Changed
|
|
@@ -2120,7 +2120,20 @@ function createWorkflowBoundarySegmentsResolver(runs) {
|
|
|
2120
2120
|
};
|
|
2121
2121
|
}
|
|
2122
2122
|
function workflowBoundaryHops(runs, runId) {
|
|
2123
|
+
return boundaryHopsFrom(new Map(runs.map((run) => [run.id, run])), runId);
|
|
2124
|
+
}
|
|
2125
|
+
function createWorkflowBoundaryHopsResolver(runs) {
|
|
2123
2126
|
const runById = new Map(runs.map((run) => [run.id, run]));
|
|
2127
|
+
const cache = new Map;
|
|
2128
|
+
return (runId) => {
|
|
2129
|
+
if (cache.has(runId))
|
|
2130
|
+
return cache.get(runId);
|
|
2131
|
+
const hops = boundaryHopsFrom(runById, runId);
|
|
2132
|
+
cache.set(runId, hops);
|
|
2133
|
+
return hops;
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function boundaryHopsFrom(runById, runId) {
|
|
2124
2137
|
const hops = [];
|
|
2125
2138
|
let current = runById.get(runId);
|
|
2126
2139
|
while (current !== undefined && current.parentRunId !== undefined) {
|
|
@@ -2146,6 +2159,35 @@ function workflowStagePathVariants(hops, stageSegments) {
|
|
|
2146
2159
|
function stageMatchesPathPattern(patternSegments, hops, stageSegments) {
|
|
2147
2160
|
return workflowStagePathVariants(hops, stageSegments).some((candidate) => matchStagePathSegments(patternSegments, candidate));
|
|
2148
2161
|
}
|
|
2162
|
+
function createStagePathPatternIndex(patterns) {
|
|
2163
|
+
const byFirstSegment = new Map;
|
|
2164
|
+
const globFirst = [];
|
|
2165
|
+
patterns.forEach((pattern, index) => {
|
|
2166
|
+
const first = pattern[0];
|
|
2167
|
+
if (first === undefined || first.includes("*")) {
|
|
2168
|
+
globFirst.push(index);
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
const bucket = byFirstSegment.get(first);
|
|
2172
|
+
if (bucket === undefined)
|
|
2173
|
+
byFirstSegment.set(first, [index]);
|
|
2174
|
+
else
|
|
2175
|
+
bucket.push(index);
|
|
2176
|
+
});
|
|
2177
|
+
return {
|
|
2178
|
+
matching(hops, stageSegments) {
|
|
2179
|
+
if (patterns.length === 0)
|
|
2180
|
+
return [];
|
|
2181
|
+
const variants = workflowStagePathVariants(hops, stageSegments);
|
|
2182
|
+
const candidates = new Set(globFirst);
|
|
2183
|
+
for (const variant of variants) {
|
|
2184
|
+
for (const index of byFirstSegment.get(variant[0]) ?? [])
|
|
2185
|
+
candidates.add(index);
|
|
2186
|
+
}
|
|
2187
|
+
return [...candidates].sort((left, right) => left - right).filter((index) => variants.some((variant) => matchStagePathSegments(patterns[index], variant)));
|
|
2188
|
+
}
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2149
2191
|
function pendingStageTarget(runId, stage) {
|
|
2150
2192
|
return "workflowGraphTarget" in stage ? stage.workflowGraphTarget : { runId, stageId: stage.id };
|
|
2151
2193
|
}
|
|
@@ -6808,6 +6850,17 @@ function removeProcessExitCleanup(cleanup) {
|
|
|
6808
6850
|
if (processExitCleanups.delete(cleanup) && processExitCleanups.size === 0)
|
|
6809
6851
|
process.off("exit", runProcessExitCleanups);
|
|
6810
6852
|
}
|
|
6853
|
+
function writtenHandle(event) {
|
|
6854
|
+
if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased)
|
|
6855
|
+
return event.payload.handle;
|
|
6856
|
+
if (event.type === RUN_EVENT_TYPES.checkpointRecorded || event.type === RUN_EVENT_TYPES.messageSettled || event.type === RUN_EVENT_TYPES.messageDelivered)
|
|
6857
|
+
return;
|
|
6858
|
+
return event.payload;
|
|
6859
|
+
}
|
|
6860
|
+
function snapshotNeedsHistory(tail) {
|
|
6861
|
+
const handle = writtenHandle(tail.snapshot.event);
|
|
6862
|
+
return handle !== undefined && (handle.pendingStageMessageChange !== undefined || hasPendingStageDeliveryDelta(handle.pendingStageMessages));
|
|
6863
|
+
}
|
|
6811
6864
|
function* invoke(action) {
|
|
6812
6865
|
try {
|
|
6813
6866
|
const result = action();
|
|
@@ -6920,11 +6973,11 @@ class JournalDurableBackend {
|
|
|
6920
6973
|
const payload = event.payload;
|
|
6921
6974
|
this.projection.archivePendingStageDeliveryReceipt(entry.runId, payload.messageId, payload.delivery, payload.accounting);
|
|
6922
6975
|
} else if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased) {
|
|
6923
|
-
this.projection.applyWorkflowSnapshot(event.payload.handle);
|
|
6976
|
+
this.projection.applyWorkflowSnapshot(decodeHandle(event.payload.handle, this.projection.getWorkflow(entry.runId)?.pendingStageMessages));
|
|
6924
6977
|
this.prompts.set(entry.runId, new PromptReservationState(event.payload.handle.pendingPrompts, event.payload.prompts));
|
|
6925
6978
|
} else {
|
|
6926
|
-
const handle = event.payload;
|
|
6927
6979
|
const previous = this.projection.getWorkflow(entry.runId);
|
|
6980
|
+
const handle = decodeHandle(event.payload, previous?.pendingStageMessages);
|
|
6928
6981
|
this.projection.applyWorkflowSnapshot(handle);
|
|
6929
6982
|
if (event.type === RUN_EVENT_TYPES.runStarted || previous?.pendingPrompts !== handle.pendingPrompts)
|
|
6930
6983
|
this.prompts.delete(entry.runId);
|
|
@@ -7044,6 +7097,20 @@ class JournalDurableBackend {
|
|
|
7044
7097
|
}
|
|
7045
7098
|
*append(runId, event, options) {
|
|
7046
7099
|
const lease = yield* this.ownership(runId);
|
|
7100
|
+
const base = this.sequences.get(runId);
|
|
7101
|
+
const pinned = options?.expectSeq;
|
|
7102
|
+
const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
|
|
7103
|
+
if (encoded !== undefined) {
|
|
7104
|
+
try {
|
|
7105
|
+
return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
|
|
7106
|
+
} catch (error) {
|
|
7107
|
+
if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
|
|
7108
|
+
throw error;
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
yield* this.write(runId, lease, event, options);
|
|
7112
|
+
}
|
|
7113
|
+
*write(runId, lease, event, options) {
|
|
7047
7114
|
try {
|
|
7048
7115
|
const outcome = yield* invoke(() => this.journal.append(lease, event, options));
|
|
7049
7116
|
const nextSeq = (this.sequences.get(runId) ?? 0) + 1;
|
|
@@ -7220,11 +7287,12 @@ class JournalDurableBackend {
|
|
|
7220
7287
|
for (const message of messages)
|
|
7221
7288
|
if (message.runId !== logicalRunId)
|
|
7222
7289
|
throw new JournalMessageScopeError(logicalRunId, message.runId);
|
|
7223
|
-
|
|
7290
|
+
const next = {
|
|
7224
7291
|
...handle,
|
|
7225
7292
|
pendingStageMessages: replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages),
|
|
7226
7293
|
updatedAt: Math.max(Date.now(), handle.updatedAt + 1)
|
|
7227
|
-
}
|
|
7294
|
+
};
|
|
7295
|
+
yield* this.snapshot(next, RUN_EVENT_TYPES.messageQueued);
|
|
7228
7296
|
return true;
|
|
7229
7297
|
}
|
|
7230
7298
|
async archivePendingStageMessage(runId, message) {
|
|
@@ -7318,7 +7386,7 @@ class JournalDurableBackend {
|
|
|
7318
7386
|
if (summarized !== undefined && summarized.seq === version.seq && summarized.at === version.at)
|
|
7319
7387
|
return;
|
|
7320
7388
|
const tail = yield* invoke(() => journal.snapshotTail(runId));
|
|
7321
|
-
if (tail !== undefined)
|
|
7389
|
+
if (tail !== undefined && !snapshotNeedsHistory(tail))
|
|
7322
7390
|
return this.summarize(runId, tail);
|
|
7323
7391
|
if (summarized === undefined && version.seq === 0)
|
|
7324
7392
|
return;
|
|
@@ -7544,7 +7612,182 @@ class JournalDurableBackend {
|
|
|
7544
7612
|
}
|
|
7545
7613
|
}
|
|
7546
7614
|
}
|
|
7547
|
-
|
|
7615
|
+
function identity(message) {
|
|
7616
|
+
return JSON.stringify([message.runId, message.id]);
|
|
7617
|
+
}
|
|
7618
|
+
function uniqueByIdentity(messages) {
|
|
7619
|
+
const result = new Map;
|
|
7620
|
+
const repeated = new Set;
|
|
7621
|
+
for (const message of messages) {
|
|
7622
|
+
const key = identity(message);
|
|
7623
|
+
if (result.has(key))
|
|
7624
|
+
repeated.add(key);
|
|
7625
|
+
result.set(key, message);
|
|
7626
|
+
}
|
|
7627
|
+
for (const key of repeated)
|
|
7628
|
+
result.delete(key);
|
|
7629
|
+
return result;
|
|
7630
|
+
}
|
|
7631
|
+
function isDeltaEncoded(message) {
|
|
7632
|
+
return message.deliveryDelta !== undefined;
|
|
7633
|
+
}
|
|
7634
|
+
function deliveryDelta(base, deliveries) {
|
|
7635
|
+
const drop = [];
|
|
7636
|
+
let kept = 0;
|
|
7637
|
+
base.forEach((delivery, index) => {
|
|
7638
|
+
if (kept < deliveries.length && JSON.stringify(delivery) === JSON.stringify(deliveries[kept]))
|
|
7639
|
+
kept++;
|
|
7640
|
+
else
|
|
7641
|
+
drop.push(index);
|
|
7642
|
+
});
|
|
7643
|
+
const add = deliveries.slice(kept);
|
|
7644
|
+
return drop.length === 0 ? { add } : { drop, add };
|
|
7645
|
+
}
|
|
7646
|
+
function pendingStageFields(message) {
|
|
7647
|
+
return Object.keys(message);
|
|
7648
|
+
}
|
|
7649
|
+
function copyField(target, source, key) {
|
|
7650
|
+
target[key] = source[key];
|
|
7651
|
+
}
|
|
7652
|
+
function isRemovedField(message, key) {
|
|
7653
|
+
return message[key] === undefined;
|
|
7654
|
+
}
|
|
7655
|
+
function json(message) {
|
|
7656
|
+
let text = entryJson.get(message);
|
|
7657
|
+
if (text === undefined) {
|
|
7658
|
+
text = JSON.stringify(message);
|
|
7659
|
+
entryJson.set(message, text);
|
|
7660
|
+
}
|
|
7661
|
+
return text;
|
|
7662
|
+
}
|
|
7663
|
+
function patchEntry(index, base, message) {
|
|
7664
|
+
const set = {};
|
|
7665
|
+
const unset = pendingStageFields(base).filter((key) => base[key] !== undefined && isRemovedField(message, key));
|
|
7666
|
+
for (const key of pendingStageFields(message)) {
|
|
7667
|
+
if (message[key] === undefined || key === "deliveries")
|
|
7668
|
+
continue;
|
|
7669
|
+
if (JSON.stringify(message[key]) !== JSON.stringify(base[key]))
|
|
7670
|
+
copyField(set, message, key);
|
|
7671
|
+
}
|
|
7672
|
+
let delta;
|
|
7673
|
+
if (message.deliveries !== undefined) {
|
|
7674
|
+
if (base.deliveries === undefined)
|
|
7675
|
+
set.deliveries = message.deliveries;
|
|
7676
|
+
else if (JSON.stringify(base.deliveries) !== JSON.stringify(message.deliveries))
|
|
7677
|
+
delta = deliveryDelta(base.deliveries, message.deliveries);
|
|
7678
|
+
}
|
|
7679
|
+
return {
|
|
7680
|
+
patch: index,
|
|
7681
|
+
...Object.keys(set).length === 0 ? {} : { set },
|
|
7682
|
+
...unset.length === 0 ? {} : { unset },
|
|
7683
|
+
...delta === undefined ? {} : { deliveryDelta: delta }
|
|
7684
|
+
};
|
|
7685
|
+
}
|
|
7686
|
+
function encodePendingStageList(previous, next) {
|
|
7687
|
+
const positions = new Map;
|
|
7688
|
+
const repeated = new Set;
|
|
7689
|
+
previous.forEach((message, index) => {
|
|
7690
|
+
const key = identity(message);
|
|
7691
|
+
if (positions.has(key))
|
|
7692
|
+
repeated.add(key);
|
|
7693
|
+
positions.set(key, index);
|
|
7694
|
+
});
|
|
7695
|
+
for (const key of repeated)
|
|
7696
|
+
positions.delete(key);
|
|
7697
|
+
const items = [];
|
|
7698
|
+
let reused = 0;
|
|
7699
|
+
for (const message of next) {
|
|
7700
|
+
const index = positions.get(identity(message));
|
|
7701
|
+
const base = index === undefined ? undefined : previous[index];
|
|
7702
|
+
if (base === undefined) {
|
|
7703
|
+
items.push(message);
|
|
7704
|
+
continue;
|
|
7705
|
+
}
|
|
7706
|
+
reused++;
|
|
7707
|
+
const patched = base === message || json(base) === json(message) ? undefined : patchEntry(index, base, message);
|
|
7708
|
+
if (patched === undefined || Object.keys(patched).length === 1) {
|
|
7709
|
+
const last = items.at(-1);
|
|
7710
|
+
if (Array.isArray(last) && last[0] + last[1] === index)
|
|
7711
|
+
last[1]++;
|
|
7712
|
+
else
|
|
7713
|
+
items.push([index, 1]);
|
|
7714
|
+
continue;
|
|
7715
|
+
}
|
|
7716
|
+
items.push(JSON.stringify(patched).length < json(message).length ? patched : message);
|
|
7717
|
+
}
|
|
7718
|
+
return reused > 0 ? items : undefined;
|
|
7719
|
+
}
|
|
7720
|
+
function decodePendingStageList(previous, items) {
|
|
7721
|
+
const base = (index) => {
|
|
7722
|
+
if (!Number.isInteger(index) || index < 0 || index >= previous.length)
|
|
7723
|
+
throw new Error(`atomic-workflows: journal pending-stage change names missing entry ${index}`);
|
|
7724
|
+
return previous[index];
|
|
7725
|
+
};
|
|
7726
|
+
const result = [];
|
|
7727
|
+
for (const item of items) {
|
|
7728
|
+
if (Array.isArray(item)) {
|
|
7729
|
+
const [start, count] = item;
|
|
7730
|
+
for (let index = start;index < start + count; index++)
|
|
7731
|
+
result.push(base(index));
|
|
7732
|
+
} else if (typeof item.patch === "number") {
|
|
7733
|
+
const { patch, set, unset, deliveryDelta: delta } = item;
|
|
7734
|
+
const entry = { ...base(patch), ...set };
|
|
7735
|
+
for (const key of unset ?? [])
|
|
7736
|
+
delete entry[key];
|
|
7737
|
+
if (delta !== undefined) {
|
|
7738
|
+
const dropped = new Set(delta.drop ?? []);
|
|
7739
|
+
const deliveries = base(patch).deliveries ?? [];
|
|
7740
|
+
entry.deliveries = [...deliveries.filter((_, index) => !dropped.has(index)), ...delta.add];
|
|
7741
|
+
}
|
|
7742
|
+
result.push(entry);
|
|
7743
|
+
} else
|
|
7744
|
+
result.push(item);
|
|
7745
|
+
}
|
|
7746
|
+
return result;
|
|
7747
|
+
}
|
|
7748
|
+
function encodeHandleEvent(event, previous) {
|
|
7749
|
+
const handle = writtenHandle(event);
|
|
7750
|
+
if (handle?.pendingStageMessages === undefined || previous === undefined)
|
|
7751
|
+
return;
|
|
7752
|
+
const change = encodePendingStageList(previous, handle.pendingStageMessages);
|
|
7753
|
+
if (change === undefined)
|
|
7754
|
+
return;
|
|
7755
|
+
const { pendingStageMessages: _full, ...rest } = handle;
|
|
7756
|
+
const encoded = { ...rest, pendingStageMessageChange: change };
|
|
7757
|
+
if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased)
|
|
7758
|
+
return { ...event, payload: { ...event.payload, handle: encoded } };
|
|
7759
|
+
return { ...event, payload: encoded };
|
|
7760
|
+
}
|
|
7761
|
+
function decodeHandle(handle, previous) {
|
|
7762
|
+
const { pendingStageMessageChange: change, ...rest } = handle;
|
|
7763
|
+
if (change !== undefined)
|
|
7764
|
+
return { ...rest, pendingStageMessages: decodePendingStageList(previous ?? [], change) };
|
|
7765
|
+
if (!hasPendingStageDeliveryDelta(handle.pendingStageMessages))
|
|
7766
|
+
return handle;
|
|
7767
|
+
return {
|
|
7768
|
+
...handle,
|
|
7769
|
+
pendingStageMessages: decodePendingStageDeliveries(previous ?? [], handle.pendingStageMessages ?? [])
|
|
7770
|
+
};
|
|
7771
|
+
}
|
|
7772
|
+
function decodePendingStageDeliveries(previous, messages) {
|
|
7773
|
+
if (!messages.some(isDeltaEncoded))
|
|
7774
|
+
return messages;
|
|
7775
|
+
const bases = uniqueByIdentity(previous);
|
|
7776
|
+
return messages.map((message) => {
|
|
7777
|
+
if (!isDeltaEncoded(message))
|
|
7778
|
+
return message;
|
|
7779
|
+
const base = bases.get(identity(message))?.deliveries;
|
|
7780
|
+
if (base === undefined)
|
|
7781
|
+
throw new Error(`atomic-workflows: journal delivery change for ${identity(message)} has no base entry`);
|
|
7782
|
+
const { deliveryDelta, ...rest } = message;
|
|
7783
|
+
const dropped = new Set(deliveryDelta.drop ?? []);
|
|
7784
|
+
return { ...rest, deliveries: [...base.filter((_, index) => !dropped.has(index)), ...deliveryDelta.add] };
|
|
7785
|
+
});
|
|
7786
|
+
}
|
|
7787
|
+
function hasPendingStageDeliveryDelta(messages) {
|
|
7788
|
+
return messages?.some(isDeltaEncoded) === true;
|
|
7789
|
+
}
|
|
7790
|
+
var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
|
|
7548
7791
|
var init_journal_backend = __esm(() => {
|
|
7549
7792
|
init_workflow_instance_ownership_error();
|
|
7550
7793
|
init_backend();
|
|
@@ -7602,6 +7845,7 @@ var init_journal_backend = __esm(() => {
|
|
|
7602
7845
|
this.name = "JournalMessageScopeError";
|
|
7603
7846
|
}
|
|
7604
7847
|
};
|
|
7848
|
+
entryJson = new WeakMap;
|
|
7605
7849
|
});
|
|
7606
7850
|
|
|
7607
7851
|
// dist/builtin/workflows/src/durable/journal/legacy-journal-tables.ts
|
|
@@ -60727,24 +60971,63 @@ function stickyStageDeliveryStatuses(runs, rootRunId, availableBackend) {
|
|
|
60727
60971
|
const root = runs.find((run) => run.id === rootRunId);
|
|
60728
60972
|
const entries = (root?.pendingStageMessages ?? []).filter((entry) => entry.sticky === true);
|
|
60729
60973
|
const result = [];
|
|
60974
|
+
const patternByTarget = new Map;
|
|
60975
|
+
const patterns = [];
|
|
60976
|
+
const entriesByPattern = [];
|
|
60977
|
+
const ownEntries = [];
|
|
60978
|
+
entries.forEach((entry, index) => {
|
|
60979
|
+
const target = entry.targetPath ?? entry.stageKey;
|
|
60980
|
+
let pattern = patternByTarget.get(target);
|
|
60981
|
+
if (pattern === undefined) {
|
|
60982
|
+
const parsed = parseWorkflowStageTarget(target);
|
|
60983
|
+
pattern = parsed?.rootRunId === rootRunId ? patterns.push(parsed.segments) - 1 : -1;
|
|
60984
|
+
if (pattern >= 0)
|
|
60985
|
+
entriesByPattern.push([]);
|
|
60986
|
+
patternByTarget.set(target, pattern);
|
|
60987
|
+
}
|
|
60988
|
+
if (pattern < 0)
|
|
60989
|
+
return;
|
|
60990
|
+
entriesByPattern[pattern].push(index);
|
|
60991
|
+
ownEntries.push(index);
|
|
60992
|
+
});
|
|
60993
|
+
if (ownEntries.length === 0)
|
|
60994
|
+
return result;
|
|
60995
|
+
const patternIndex = createStagePathPatternIndex(patterns);
|
|
60996
|
+
const deliveriesByEntry = new Map;
|
|
60997
|
+
const entryReceipts = (index, runId, stageId) => {
|
|
60998
|
+
let byStage = deliveriesByEntry.get(index);
|
|
60999
|
+
if (byStage === undefined) {
|
|
61000
|
+
byStage = new Map;
|
|
61001
|
+
for (const delivery of entries[index].deliveries ?? []) {
|
|
61002
|
+
const key = `${delivery.runId}\x00${delivery.stageId}`;
|
|
61003
|
+
const list = byStage.get(key);
|
|
61004
|
+
if (list === undefined)
|
|
61005
|
+
byStage.set(key, [delivery]);
|
|
61006
|
+
else
|
|
61007
|
+
list.push(delivery);
|
|
61008
|
+
}
|
|
61009
|
+
deliveriesByEntry.set(index, byStage);
|
|
61010
|
+
}
|
|
61011
|
+
return byStage.get(`${runId}\x00${stageId}`) ?? [];
|
|
61012
|
+
};
|
|
60730
61013
|
availableBackend = availableRunDurableBackend(runs, rootRunId) ?? availableBackend;
|
|
60731
61014
|
const backend = availableBackend === undefined ? undefined : durableBackendForRun(availableBackend, runs, rootRunId);
|
|
61015
|
+
const runById = new Map(runs.map((run) => [run.id, run]));
|
|
61016
|
+
const hopsFor = createWorkflowBoundaryHopsResolver(runs);
|
|
60732
61017
|
for (const run of runs) {
|
|
60733
|
-
|
|
61018
|
+
const durableRootRunId = reciprocalWorkflowRootRunId(runById, run.id);
|
|
61019
|
+
if (run.id !== rootRunId && run.rootRunId !== rootRunId && durableRootRunId !== rootRunId)
|
|
60734
61020
|
continue;
|
|
60735
|
-
const resolved =
|
|
60736
|
-
const hops =
|
|
61021
|
+
const resolved = durableRootRunId === rootRunId;
|
|
61022
|
+
const hops = hopsFor(run.id);
|
|
60737
61023
|
for (const stage of run.stages) {
|
|
60738
61024
|
if (stage.nodeKind === "tool" || stage.replayKey?.startsWith("prompt:") === true || stage.replayKey?.startsWith("workflow:") === true || stage.workflowChildRun !== undefined || stage.workflowChild !== undefined)
|
|
60739
61025
|
continue;
|
|
60740
|
-
|
|
61026
|
+
const matchedEntries = resolved && hops ? patternIndex.matching(hops, [stage.id, stage.name]).flatMap((pattern) => entriesByPattern[pattern]).sort((left, right) => left - right) : ownEntries;
|
|
61027
|
+
for (const index of matchedEntries) {
|
|
61028
|
+
const entry = entries[index];
|
|
60741
61029
|
const target = entry.targetPath ?? entry.stageKey;
|
|
60742
|
-
const
|
|
60743
|
-
if (!parsed || parsed.rootRunId !== rootRunId)
|
|
60744
|
-
continue;
|
|
60745
|
-
if (resolved && hops && !stageMatchesPathPattern(parsed.segments, hops, [stage.id, stage.name]))
|
|
60746
|
-
continue;
|
|
60747
|
-
const receipts = (entry.deliveries ?? []).filter((delivery) => delivery.runId === run.id && delivery.stageId === stage.id);
|
|
61030
|
+
const receipts = entryReceipts(index, run.id, stage.id);
|
|
60748
61031
|
const delivered = backend?.hasCachedPendingStageDeliveryReceipt?.(rootRunId, entry.id, {
|
|
60749
61032
|
runId: run.id,
|
|
60750
61033
|
stageId: stage.id,
|
|
@@ -61062,20 +61345,27 @@ function possibleStageRows(runs, rootRunId, rootRun, backend) {
|
|
|
61062
61345
|
if (isTerminalRunStatus(rootRun.status))
|
|
61063
61346
|
return [];
|
|
61064
61347
|
const stickyQueued = (rootRun.pendingStageMessages ?? []).filter((entry) => entry.sticky === true && entry.status === "queued");
|
|
61348
|
+
const segmentsByTarget = new Map;
|
|
61065
61349
|
const stickySegments = (entry) => {
|
|
61066
|
-
const
|
|
61067
|
-
|
|
61350
|
+
const target = entry.targetPath ?? entry.stageKey;
|
|
61351
|
+
if (segmentsByTarget.has(target))
|
|
61352
|
+
return segmentsByTarget.get(target);
|
|
61353
|
+
const parsed = parseWorkflowStageTarget(target);
|
|
61354
|
+
const segments = parsed?.rootRunId === rootRunId ? parsed.segments : undefined;
|
|
61355
|
+
segmentsByTarget.set(target, segments);
|
|
61356
|
+
return segments;
|
|
61068
61357
|
};
|
|
61069
61358
|
const scanEntries = stickyQueued.filter((entry) => {
|
|
61070
61359
|
const segments = stickySegments(entry);
|
|
61071
61360
|
return !(segments !== undefined && segments.length === 1 && segments[0] === "**");
|
|
61072
61361
|
});
|
|
61362
|
+
const liveStageMatches = materializedStageMatcher(runs, rootRunId);
|
|
61073
61363
|
const rows = [];
|
|
61074
61364
|
for (const scanEntry of rootRun.possibleStages ?? []) {
|
|
61075
61365
|
const rowSegments = splitStagePathSegments(scanEntry);
|
|
61076
61366
|
if (rowSegments.length === 0 || rowSegments.some((segment) => segment.length === 0))
|
|
61077
61367
|
continue;
|
|
61078
|
-
if (!rowSegments.some((segment) => segment.includes("*")) &&
|
|
61368
|
+
if (!rowSegments.some((segment) => segment.includes("*")) && liveStageMatches(rowSegments)) {
|
|
61079
61369
|
continue;
|
|
61080
61370
|
}
|
|
61081
61371
|
rows.push({
|
|
@@ -61096,28 +61386,43 @@ function possibleStageRows(runs, rootRunId, rootRun, backend) {
|
|
|
61096
61386
|
}).length
|
|
61097
61387
|
});
|
|
61098
61388
|
const statuses = stickyStageDeliveryStatuses(runs, rootRunId, backend);
|
|
61099
|
-
|
|
61100
|
-
|
|
61389
|
+
const statusesByTarget = new Map;
|
|
61390
|
+
for (const status of statuses) {
|
|
61391
|
+
const forTarget = statusesByTarget.get(status.target);
|
|
61392
|
+
if (forTarget === undefined)
|
|
61393
|
+
statusesByTarget.set(status.target, [status]);
|
|
61394
|
+
else
|
|
61395
|
+
forTarget.push(status);
|
|
61396
|
+
}
|
|
61397
|
+
const queuedByTarget = new Map;
|
|
61398
|
+
for (const entry of stickyQueued) {
|
|
61399
|
+
const target = entry.targetPath ?? entry.stageKey;
|
|
61400
|
+
queuedByTarget.set(target, (queuedByTarget.get(target) ?? 0) + 1);
|
|
61401
|
+
}
|
|
61402
|
+
const rowTargets = new Set(rows.map((row) => row.target));
|
|
61403
|
+
for (const target of statusesByTarget.keys()) {
|
|
61404
|
+
if (rowTargets.has(target))
|
|
61101
61405
|
continue;
|
|
61102
|
-
|
|
61103
|
-
|
|
61104
|
-
queuedCount: stickyQueued.filter((entry) => (entry.targetPath ?? entry.stageKey) === target).length,
|
|
61105
|
-
deliveryOnly: true
|
|
61106
|
-
});
|
|
61406
|
+
rowTargets.add(target);
|
|
61407
|
+
rows.push({ target, queuedCount: queuedByTarget.get(target) ?? 0, deliveryOnly: true });
|
|
61107
61408
|
}
|
|
61108
61409
|
for (let index = 0;index < rows.length; index++) {
|
|
61109
61410
|
const row = rows[index];
|
|
61110
|
-
const deliveryStates =
|
|
61111
|
-
if (deliveryStates
|
|
61411
|
+
const deliveryStates = statusesByTarget.get(row.target);
|
|
61412
|
+
if (deliveryStates !== undefined)
|
|
61112
61413
|
rows[index] = { ...row, deliveryStates };
|
|
61113
61414
|
}
|
|
61114
61415
|
return rows;
|
|
61115
61416
|
}
|
|
61116
|
-
function
|
|
61117
|
-
|
|
61118
|
-
|
|
61119
|
-
|
|
61120
|
-
|
|
61417
|
+
function materializedStageMatcher(runs, rootRunId) {
|
|
61418
|
+
const runById = new Map(runs.map((run) => [run.id, run]));
|
|
61419
|
+
const hopsFor = createWorkflowBoundaryHopsResolver(runs);
|
|
61420
|
+
const invocationRuns = runs.filter((run) => reciprocalWorkflowRootRunId(runById, run.id) === rootRunId);
|
|
61421
|
+
return (entrySegments) => materializedStageMatches(invocationRuns, hopsFor, entrySegments);
|
|
61422
|
+
}
|
|
61423
|
+
function materializedStageMatches(invocationRuns, hopsFor, entrySegments) {
|
|
61424
|
+
for (const run of invocationRuns) {
|
|
61425
|
+
const hops = hopsFor(run.id);
|
|
61121
61426
|
if (hops === undefined)
|
|
61122
61427
|
continue;
|
|
61123
61428
|
for (const stage of run.stages) {
|
|
@@ -61392,10 +61697,12 @@ async function recordConfirmedStickyDeliveries(activeStore, event) {
|
|
|
61392
61697
|
}
|
|
61393
61698
|
function matchingLiveStages(runs, rootRunId, patternSegments) {
|
|
61394
61699
|
const matches = [];
|
|
61700
|
+
const runById = new Map(runs.map((run) => [run.id, run]));
|
|
61701
|
+
const hopsFor = createWorkflowBoundaryHopsResolver(runs);
|
|
61395
61702
|
for (const run of runs) {
|
|
61396
|
-
if (
|
|
61703
|
+
if (reciprocalWorkflowRootRunId(runById, run.id) !== rootRunId)
|
|
61397
61704
|
continue;
|
|
61398
|
-
const hops =
|
|
61705
|
+
const hops = hopsFor(run.id);
|
|
61399
61706
|
if (hops === undefined)
|
|
61400
61707
|
continue;
|
|
61401
61708
|
for (const stage of run.stages) {
|
|
@@ -61531,11 +61838,26 @@ function writeMessage(socket, msg, callback) {
|
|
|
61531
61838
|
}
|
|
61532
61839
|
function createMessageReader(onMessage, onError) {
|
|
61533
61840
|
let buffer = Buffer.alloc(0);
|
|
61841
|
+
let pending = [];
|
|
61842
|
+
let pendingLength = 0;
|
|
61843
|
+
let awaitedLength = 0;
|
|
61534
61844
|
return (data) => {
|
|
61535
|
-
|
|
61845
|
+
if (pendingLength + data.length < awaitedLength) {
|
|
61846
|
+
pending.push(data);
|
|
61847
|
+
pendingLength += data.length;
|
|
61848
|
+
return;
|
|
61849
|
+
}
|
|
61850
|
+
buffer = pending.length === 0 ? Buffer.concat([buffer, data]) : Buffer.concat([...pending, data]);
|
|
61851
|
+
pending = [];
|
|
61852
|
+
pendingLength = 0;
|
|
61853
|
+
awaitedLength = 0;
|
|
61536
61854
|
while (buffer.length >= 4) {
|
|
61537
61855
|
const length = buffer.readUInt32BE(0);
|
|
61538
61856
|
if (buffer.length < 4 + length) {
|
|
61857
|
+
pending = [buffer];
|
|
61858
|
+
pendingLength = buffer.length;
|
|
61859
|
+
awaitedLength = 4 + length;
|
|
61860
|
+
buffer = Buffer.alloc(0);
|
|
61539
61861
|
break;
|
|
61540
61862
|
}
|
|
61541
61863
|
const payload = buffer.subarray(4, 4 + length);
|
|
@@ -61647,7 +61969,8 @@ function buildSendSignature(to, options) {
|
|
|
61647
61969
|
attachments: canonicalizeAttachmentsForSendSignature(options.attachments) ?? [],
|
|
61648
61970
|
replyTo: options.replyTo ?? null,
|
|
61649
61971
|
expectsReply: options.expectsReply ?? false,
|
|
61650
|
-
replyError: options.replyError ?? null
|
|
61972
|
+
replyError: options.replyError ?? null,
|
|
61973
|
+
...options.delivery === undefined || options.delivery === "steer" ? {} : { delivery: options.delivery }
|
|
61651
61974
|
});
|
|
61652
61975
|
}
|
|
61653
61976
|
|
|
@@ -61833,6 +62156,8 @@ function isMessage(value2) {
|
|
|
61833
62156
|
return false;
|
|
61834
62157
|
if (message.expectsReply !== undefined && typeof message.expectsReply !== "boolean")
|
|
61835
62158
|
return false;
|
|
62159
|
+
if (message.delivery !== undefined && message.delivery !== "steer" && message.delivery !== "followUp" && message.delivery !== "interrupt")
|
|
62160
|
+
return false;
|
|
61836
62161
|
if (message.replyError !== undefined && typeof message.replyError !== "string")
|
|
61837
62162
|
return false;
|
|
61838
62163
|
if (message.source !== undefined && !isMessageSource(message.source))
|
|
@@ -63042,6 +63367,7 @@ var init_client = __esm(() => {
|
|
|
63042
63367
|
timestamp: Date.now(),
|
|
63043
63368
|
replyTo: options.replyTo,
|
|
63044
63369
|
expectsReply: options.expectsReply,
|
|
63370
|
+
...options.delivery === undefined || options.delivery === "steer" ? {} : { delivery: options.delivery },
|
|
63045
63371
|
replyError: options.replyError,
|
|
63046
63372
|
source: this._messageSource,
|
|
63047
63373
|
content: { text: options.text, attachments: options.attachments }
|