@parall/agent-core 1.37.0 → 1.38.0
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/dist/dispatch-adapter.d.ts +6 -0
- package/dist/dispatch-adapter.d.ts.map +1 -1
- package/dist/gateway-base.d.ts +54 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +331 -95
- package/dist/gateway-lane-flow.d.ts +74 -0
- package/dist/gateway-lane-flow.d.ts.map +1 -0
- package/dist/gateway-lane-flow.js +167 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lane-key.d.ts +45 -0
- package/dist/lane-key.d.ts.map +1 -0
- package/dist/lane-key.js +34 -0
- package/dist/lane-ledger.d.ts +112 -0
- package/dist/lane-ledger.d.ts.map +1 -0
- package/dist/lane-ledger.js +333 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/dispatch-adapter.ts +6 -0
- package/src/gateway-base.ts +493 -142
- package/src/gateway-lane-flow.ts +235 -0
- package/src/index.ts +2 -0
- package/src/lane-key.ts +67 -0
- package/src/lane-ledger.ts +370 -0
- package/src/types.ts +2 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { ApiError } from '@parall/sdk';
|
|
3
|
+
import { laneContextFilePath, laneKeyForTarget } from './lane-key.js';
|
|
4
|
+
/**
|
|
5
|
+
* Thrown when the server predates the dispatch ledger (claim endpoint 404s
|
|
6
|
+
* during a rolling deploy). The gateway falls back to the legacy
|
|
7
|
+
* received/ack flow for the rest of its lifetime.
|
|
8
|
+
*/
|
|
9
|
+
export class LedgerUnsupportedError extends Error {
|
|
10
|
+
}
|
|
11
|
+
function isStaleLane(err) {
|
|
12
|
+
return err instanceof ApiError && err.status === 409 && err.code === 'STALE_LANE';
|
|
13
|
+
}
|
|
14
|
+
function isNotFound(err) {
|
|
15
|
+
return err instanceof ApiError && err.status === 404;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A pre-ledger server (or an edge that doesn't know the route) answers the
|
|
19
|
+
* claim endpoint with an UNSTRUCTURED 404 — no app error code. Our own
|
|
20
|
+
* handlers always attach a code, so a coded 404 is a semantic answer, not a
|
|
21
|
+
* missing endpoint. Transient edge 404s during rolling deploys are further
|
|
22
|
+
* contained by the reconnect re-probe (ledgerDisabled resets on hello).
|
|
23
|
+
*/
|
|
24
|
+
function isEndpointMissing(err) {
|
|
25
|
+
return err instanceof ApiError && err.status === 404 && !err.code;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* LaneLedger is the bridge-side client of the server dispatch ledger
|
|
29
|
+
* (docs/engineering-design/agent-dispatch-idempotency-design.md): it claims
|
|
30
|
+
* lane occupancy just-in-time before a message dispatch, folds mid-turn
|
|
31
|
+
* same-target messages via steer, completes (no_action sweep + release) when
|
|
32
|
+
* the local queue for a lane runs dry, and releases leftovers on shutdown.
|
|
33
|
+
*
|
|
34
|
+
* It is also the single writer of the per-lane dispatch context files under
|
|
35
|
+
* PRLL_CONTEXT_DIR (`<lane-key>.json`) that the CLI reads to derive dispatch
|
|
36
|
+
* effect keys. The CLI's reply-state sidecar lives next to it and is never
|
|
37
|
+
* touched here (two writers, two files).
|
|
38
|
+
*/
|
|
39
|
+
export class LaneLedger {
|
|
40
|
+
opts;
|
|
41
|
+
lanes = new Map();
|
|
42
|
+
constructor(opts) {
|
|
43
|
+
this.opts = opts;
|
|
44
|
+
}
|
|
45
|
+
get contextDir() {
|
|
46
|
+
return this.opts.contextDir;
|
|
47
|
+
}
|
|
48
|
+
/** Only chat message events ride the lane ledger; typed events stay on the legacy ack path. */
|
|
49
|
+
handles(event) {
|
|
50
|
+
return event.type === 'message' && event.targetId.startsWith('cht_');
|
|
51
|
+
}
|
|
52
|
+
laneKeyFor(event) {
|
|
53
|
+
if (event.type !== 'message' && event.dispatchEventId) {
|
|
54
|
+
return laneKeyForTarget(`dsp:${event.dispatchEventId}`);
|
|
55
|
+
}
|
|
56
|
+
return laneKeyForTarget(`prll://${event.targetId}`, event.threadRootId);
|
|
57
|
+
}
|
|
58
|
+
getForEvent(event) {
|
|
59
|
+
return this.lanes.get(this.laneKeyFor(event));
|
|
60
|
+
}
|
|
61
|
+
laneContextPath(lane) {
|
|
62
|
+
return laneContextFilePath(this.opts.contextDir, lane.targetUri, lane.threadRootId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Claim (or reuse) the lane for a group of same-lane message events and
|
|
66
|
+
* fold every group member into it. Returns 'foreign' when a healthy
|
|
67
|
+
* incumbent (another pod) holds the resource — the caller must not
|
|
68
|
+
* dispatch; the events stay pending server-side and re-drive after the
|
|
69
|
+
* incumbent completes.
|
|
70
|
+
*/
|
|
71
|
+
async ensureLane(events) {
|
|
72
|
+
const trigger = events[events.length - 1];
|
|
73
|
+
const laneKey = this.laneKeyFor(trigger);
|
|
74
|
+
let lane = this.lanes.get(laneKey);
|
|
75
|
+
if (!lane) {
|
|
76
|
+
const targetUri = `prll://${trigger.targetId}`;
|
|
77
|
+
let res;
|
|
78
|
+
try {
|
|
79
|
+
res = await this.opts.client.claimDispatch(this.opts.orgId, {
|
|
80
|
+
target_uri: targetUri,
|
|
81
|
+
thread_root_id: trigger.threadRootId,
|
|
82
|
+
limit: 100,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (isEndpointMissing(err))
|
|
87
|
+
throw new LedgerUnsupportedError('claim endpoint unavailable');
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
if (!res.claimed || !res.lane) {
|
|
91
|
+
this.opts.log?.info(`lane for ${targetUri} held by a healthy incumbent — leaving events pending for re-drive`);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const leaseUntilMs = Date.parse(res.lease_until ?? '');
|
|
95
|
+
lane = {
|
|
96
|
+
laneKey,
|
|
97
|
+
lane: res.lane,
|
|
98
|
+
targetUri,
|
|
99
|
+
threadRootId: trigger.threadRootId,
|
|
100
|
+
folded: new Map(),
|
|
101
|
+
...(Number.isNaN(leaseUntilMs)
|
|
102
|
+
? {}
|
|
103
|
+
: { leaseUntilMs, leaseTtlMs: Math.max(leaseUntilMs - Date.now(), 60_000) }),
|
|
104
|
+
};
|
|
105
|
+
for (const ev of res.events ?? []) {
|
|
106
|
+
lane.folded.set(ev.source_id, ev.id);
|
|
107
|
+
}
|
|
108
|
+
this.lanes.set(laneKey, lane);
|
|
109
|
+
}
|
|
110
|
+
// Fold group members the claim didn't cover (they arrived after the
|
|
111
|
+
// claim, or this group reuses an already-active lane). Fail closed on ANY
|
|
112
|
+
// fold failure: an un-folded message dispatched now would not be covered
|
|
113
|
+
// by this lane's reply/complete, so its still-live WorkItem would re-drive
|
|
114
|
+
// later and the model would handle it twice. Releasing hands the folded
|
|
115
|
+
// members back to pending immediately; the re-drive / live hint path
|
|
116
|
+
// re-delivers the whole group under a fresh claim.
|
|
117
|
+
for (const ev of events) {
|
|
118
|
+
if (lane.folded.has(ev.messageId))
|
|
119
|
+
continue;
|
|
120
|
+
try {
|
|
121
|
+
const res = await this.opts.client.steerDispatch(this.opts.orgId, {
|
|
122
|
+
lane: lane.lane,
|
|
123
|
+
target_uri: lane.targetUri,
|
|
124
|
+
thread_root_id: lane.threadRootId,
|
|
125
|
+
...(ev.dispatchEventId
|
|
126
|
+
? { dispatch_event_id: ev.dispatchEventId }
|
|
127
|
+
: { source_type: 'message', source_id: ev.messageId }),
|
|
128
|
+
});
|
|
129
|
+
lane.folded.set(ev.messageId, res.dispatch_event_id);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (isStaleLane(err)) {
|
|
133
|
+
// We lost the lane mid-group — drop local state; the takeover
|
|
134
|
+
// owner (or the next claim) picks the members up.
|
|
135
|
+
this.lanes.delete(laneKey);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
this.opts.log?.warn(`steer fold failed for ${ev.messageId} — failing closed, releasing lane: ${String(err)}`);
|
|
139
|
+
await this.release(laneKey);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return lane;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Fold a live mid-turn message into its active lane BEFORE injecting it
|
|
147
|
+
* into the running turn. Injection without a successful fold is forbidden —
|
|
148
|
+
* an un-folded injected message would be re-driven after complete and the
|
|
149
|
+
* model would handle it twice.
|
|
150
|
+
*/
|
|
151
|
+
async steerLive(event) {
|
|
152
|
+
const laneKey = this.laneKeyFor(event);
|
|
153
|
+
const lane = this.lanes.get(laneKey);
|
|
154
|
+
if (!lane)
|
|
155
|
+
return false;
|
|
156
|
+
if (lane.folded.has(event.messageId))
|
|
157
|
+
return true;
|
|
158
|
+
try {
|
|
159
|
+
const res = await this.opts.client.steerDispatch(this.opts.orgId, {
|
|
160
|
+
lane: lane.lane,
|
|
161
|
+
target_uri: lane.targetUri,
|
|
162
|
+
thread_root_id: lane.threadRootId,
|
|
163
|
+
...(event.dispatchEventId
|
|
164
|
+
? { dispatch_event_id: event.dispatchEventId }
|
|
165
|
+
: { source_type: 'message', source_id: event.messageId }),
|
|
166
|
+
});
|
|
167
|
+
lane.folded.set(event.messageId, res.dispatch_event_id);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (isStaleLane(err)) {
|
|
172
|
+
this.lanes.delete(laneKey);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
this.opts.log?.warn(`live steer failed for ${event.messageId}: ${String(err)}`);
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Complete the lane when no local work remains for it: the server sweeps
|
|
182
|
+
* still-leased members as no_action, releases the occupancy row, and
|
|
183
|
+
* re-drives any same-target pending work. A STALE_LANE answer means a
|
|
184
|
+
* takeover already owns the resource — local state is dropped either way.
|
|
185
|
+
*/
|
|
186
|
+
async completeIfIdle(laneKey, hasMoreLocal) {
|
|
187
|
+
const lane = this.lanes.get(laneKey);
|
|
188
|
+
if (!lane || hasMoreLocal)
|
|
189
|
+
return;
|
|
190
|
+
this.lanes.delete(laneKey);
|
|
191
|
+
this.removeLaneContext(lane);
|
|
192
|
+
try {
|
|
193
|
+
const res = await this.opts.client.completeDispatch(this.opts.orgId, {
|
|
194
|
+
lane: lane.lane,
|
|
195
|
+
target_uri: lane.targetUri,
|
|
196
|
+
thread_root_id: lane.threadRootId,
|
|
197
|
+
});
|
|
198
|
+
if (res.swept_no_action > 0 || res.redriven) {
|
|
199
|
+
this.opts.log?.info(`lane complete for ${lane.targetUri}: swept ${res.swept_no_action} no_action, redriven=${res.redriven}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
if (isStaleLane(err)) {
|
|
204
|
+
this.opts.log?.info(`lane complete skipped for ${lane.targetUri} — taken over`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// Lease expiry recovers the members; complete is not retried here.
|
|
208
|
+
this.opts.log?.warn(`lane complete failed for ${lane.targetUri}: ${String(err)}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Long-turn keepalive: renew the lane's lease on runtime activity, throttled
|
|
213
|
+
* so a chatty turn doesn't spam the server. Without this, a legitimately
|
|
214
|
+
* long turn (> lane TTL) would be dethroned mid-flight and every subsequent
|
|
215
|
+
* write misfired with STALE_LANE — the design doc's "long turns renew via
|
|
216
|
+
* step writes". Fire-and-forget: a failed renewal is surfaced by the next
|
|
217
|
+
* write's incumbency check anyway.
|
|
218
|
+
*/
|
|
219
|
+
maybeRenew(lane) {
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
// Server-driven pacing: renew once less than half the lease TTL remains.
|
|
222
|
+
// Hardcoding a client-side rhythm would silently break every published
|
|
223
|
+
// runtime image the day the server shortens its lane TTL.
|
|
224
|
+
const ttl = lane.leaseTtlMs ?? 10 * 60_000;
|
|
225
|
+
const until = lane.leaseUntilMs ?? now; // unknown lease → renew now
|
|
226
|
+
if (until - now > ttl / 2)
|
|
227
|
+
return;
|
|
228
|
+
lane.leaseUntilMs = now + ttl; // optimistic; corrected by the response
|
|
229
|
+
void this.opts.client
|
|
230
|
+
.heartbeatDispatchLane(this.opts.orgId, {
|
|
231
|
+
lane: lane.lane,
|
|
232
|
+
target_uri: lane.targetUri,
|
|
233
|
+
thread_root_id: lane.threadRootId,
|
|
234
|
+
})
|
|
235
|
+
.then((res) => {
|
|
236
|
+
const until = Date.parse(res?.lease_until ?? '');
|
|
237
|
+
if (!Number.isNaN(until))
|
|
238
|
+
lane.leaseUntilMs = until;
|
|
239
|
+
})
|
|
240
|
+
.catch((err) => {
|
|
241
|
+
if (isStaleLane(err)) {
|
|
242
|
+
this.lanes.delete(lane.laneKey);
|
|
243
|
+
this.opts.log?.warn(`lane ${lane.targetUri} was taken over during the turn`);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
this.opts.log?.warn(`lane heartbeat failed for ${lane.targetUri}: ${String(err)}`);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Release a lane's unresolved members back to pending (dispatch error /
|
|
251
|
+
* shutdown) so the next pod re-claims immediately instead of waiting out
|
|
252
|
+
* the lease.
|
|
253
|
+
*/
|
|
254
|
+
async release(laneKey) {
|
|
255
|
+
const lane = this.lanes.get(laneKey);
|
|
256
|
+
if (!lane)
|
|
257
|
+
return;
|
|
258
|
+
this.lanes.delete(laneKey);
|
|
259
|
+
this.removeLaneContext(lane);
|
|
260
|
+
try {
|
|
261
|
+
await this.opts.client.releaseDispatchLane(this.opts.orgId, lane.lane);
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
this.opts.log?.warn(`lane release failed for ${lane.targetUri}: ${String(err)}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async releaseAll() {
|
|
268
|
+
const keys = [...this.lanes.keys()];
|
|
269
|
+
for (const key of keys) {
|
|
270
|
+
await this.release(key);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** True when any lane is currently active (used by shutdown logging). */
|
|
274
|
+
get activeCount() {
|
|
275
|
+
return this.lanes.size;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Claim the single-member lane of one typed WorkItem (resource = dsp:<id>),
|
|
279
|
+
* by WorkItem id or by source identity (the live task.assigned event has no
|
|
280
|
+
* WorkItem id). Returns null when a healthy incumbent (another pod) holds
|
|
281
|
+
* it or the WorkItem is already resolved — the caller must skip processing.
|
|
282
|
+
*/
|
|
283
|
+
async claimTyped(ref) {
|
|
284
|
+
let res;
|
|
285
|
+
try {
|
|
286
|
+
res = await this.opts.client.claimDispatch(this.opts.orgId, {
|
|
287
|
+
dispatch_event_id: ref.dispatchEventId,
|
|
288
|
+
source_type: ref.dispatchEventId ? undefined : ref.sourceType,
|
|
289
|
+
source_id: ref.dispatchEventId ? undefined : ref.sourceId,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
if (isEndpointMissing(err))
|
|
294
|
+
throw new LedgerUnsupportedError('claim endpoint unavailable');
|
|
295
|
+
throw err;
|
|
296
|
+
}
|
|
297
|
+
if (!res.claimed || !res.lane || !res.events?.length)
|
|
298
|
+
return null;
|
|
299
|
+
const workItem = res.events[0];
|
|
300
|
+
const targetUri = `dsp:${workItem.id}`;
|
|
301
|
+
const leaseUntilMs = Date.parse(res.lease_until ?? '');
|
|
302
|
+
const lane = {
|
|
303
|
+
laneKey: laneKeyForTarget(targetUri),
|
|
304
|
+
lane: res.lane,
|
|
305
|
+
targetUri,
|
|
306
|
+
folded: new Map([[workItem.source_id, workItem.id]]),
|
|
307
|
+
typedDispatchEventId: workItem.id,
|
|
308
|
+
...(Number.isNaN(leaseUntilMs)
|
|
309
|
+
? {}
|
|
310
|
+
: { leaseUntilMs, leaseTtlMs: Math.max(leaseUntilMs - Date.now(), 60_000) }),
|
|
311
|
+
};
|
|
312
|
+
this.lanes.set(lane.laneKey, lane);
|
|
313
|
+
return lane;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Remove the per-lane context file (and its CLI sidecar) when the lane
|
|
317
|
+
* ends. A leftover file would make a later cross-context send to the same
|
|
318
|
+
* target bind a dead lane token and misfire with STALE_LANE instead of
|
|
319
|
+
* taking the plain non-ledger path.
|
|
320
|
+
*/
|
|
321
|
+
removeLaneContext(lane) {
|
|
322
|
+
const contextPath = this.laneContextPath(lane);
|
|
323
|
+
for (const p of [contextPath, contextPath.replace(/\.json$/, '.reply-state.json')]) {
|
|
324
|
+
try {
|
|
325
|
+
fs.rmSync(p, { force: true });
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
// Best-effort: a stale file only re-surfaces as a server-side
|
|
329
|
+
// STALE_LANE, never as a wrong write.
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -72,6 +72,8 @@ export type ParallEvent = {
|
|
|
72
72
|
sentAt?: string;
|
|
73
73
|
ackSourceType?: 'message' | 'task_activity' | 'comment' | 'schedule_run' | 'external_trigger_run' | 'channel_message';
|
|
74
74
|
ackSourceId?: string;
|
|
75
|
+
/** WorkItem id, when known (dispatch catch-up / re-drive hints carry it; live message.new does not). */
|
|
76
|
+
dispatchEventId?: string;
|
|
75
77
|
/** Unread message count in the target chat since agent's last interaction. */
|
|
76
78
|
unreadCount?: number;
|
|
77
79
|
/** Channel cursor: the last message ID the agent read. */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/agent-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Shared agent runtime orchestration helpers for Parall",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@opentelemetry/sdk-logs": "^0.57.0",
|
|
36
36
|
"@opentelemetry/sdk-metrics": "^1.30.0",
|
|
37
37
|
"@opentelemetry/sdk-trace-node": "^1.30.0",
|
|
38
|
-
"@parall/sdk": "1.
|
|
38
|
+
"@parall/sdk": "1.38.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^22.0.0",
|
package/src/dispatch-adapter.ts
CHANGED
|
@@ -23,6 +23,12 @@ export type DispatchContext = {
|
|
|
23
23
|
contextFilePath?: string;
|
|
24
24
|
/** @deprecated Use contextFilePath. Kept for runtimes that haven't migrated. */
|
|
25
25
|
stepIdFilePath?: string;
|
|
26
|
+
/**
|
|
27
|
+
* PRLL_CONTEXT_DIR contract: the per-agent directory holding per-lane
|
|
28
|
+
* dispatch context files (`<lane-key>.json`, see lane-key.ts). Stable for
|
|
29
|
+
* the life of the bridge — safe to pin into spawn env.
|
|
30
|
+
*/
|
|
31
|
+
contextDirPath?: string;
|
|
26
32
|
client: ParallClient;
|
|
27
33
|
log?: GatewayLogger;
|
|
28
34
|
};
|