@parall/agent-core 1.43.0 → 1.45.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.
@@ -13,8 +13,15 @@ import type { ParallEvent } from './types.js';
13
13
  export interface LaneFlowHost {
14
14
  laneLedger?: LaneLedger;
15
15
  ledgerDisabled: boolean;
16
+ /**
17
+ * Sticky: the server answered a by-id complete with 400 (predates the
18
+ * form, v1.44). Typed resolution falls back to the legacy ack for the
19
+ * rest of the process; claims stay on the ledger (that face is older).
20
+ */
21
+ typedByIdCompleteUnsupported: boolean;
16
22
  shuttingDown: boolean;
17
23
  dispatchedMessages: Set<string>;
24
+ dispatchedTasks: Set<string>;
18
25
  /**
19
26
  * Per-WorkItem failure backoff for typed dispatch consumption. A consume
20
27
  * that ends without an ack re-arms the entry; the next attempt for the
@@ -39,6 +46,8 @@ export interface LaneFlowHost {
39
46
  disableLedger(reason: string): void;
40
47
  usesLaneLedger(event: ParallEvent): boolean;
41
48
  emitDispatchReceived(event: ParallEvent): Promise<void>;
49
+ consumeTurnError(sessionKey: string): boolean;
50
+ noteSessionLane(sessionKey: string, laneKey: string | null): void;
42
51
  runDispatch(event: ParallEvent, sessionKey: string, bodyForAgent: string, earlierEvents?: ParallEvent[], captureText?: string[]): Promise<boolean>;
43
52
  tryClaimMessage(id: string): boolean;
44
53
  buildMessageDispatchDecision(chatId: string, message: DispatchableMessage): Promise<MessageDispatchDecision>;
@@ -57,15 +66,78 @@ export declare function dispatchLaneGroup(host: LaneFlowHost, opts: {
57
66
  earlier: ParallEvent[];
58
67
  captureText?: string[];
59
68
  hasMoreLocal: () => boolean;
60
- }): Promise<'dispatched' | 'foreign' | 'shutdown'>;
69
+ }): Promise<'dispatched' | 'foreign' | 'shutdown' | 'failed'>;
70
+ /**
71
+ * The WorkItem ids of a typed event group whose lifecycle the ledger owns
72
+ * (claimed into dsp lanes by consumeTypedDispatch), or null when the group
73
+ * must stay on the legacy received/ack surface — ledger unavailable, an id
74
+ * missing, or a member that rides a message lane. Non-null means: skip
75
+ * legacy received+ack, resolve via the by-id complete, and fold the
76
+ * turn-error signal into the outcome.
77
+ */
78
+ export declare function typedLedgerEventIds(host: LaneFlowHost, events: ParallEvent[]): string[] | null;
79
+ /** Outcome of a by-id complete attempt. */
80
+ export type TypedResolveOutcome = 'ok' | 'stale' | 'unsupported' | 'failed';
81
+ /**
82
+ * By-id complete (turn_outcome ok): terminal resolution of ONE WorkItem —
83
+ * exact where the source pair is ambiguous across task siblings. `lane`
84
+ * fences the call while the row is claim-owned (a dethroned caller gets
85
+ * 'stale' and must leave the row to its successor); omit it for the
86
+ * wrapper-less pending close (buffered drain, administrative drops).
87
+ */
88
+ export declare function resolveDispatchByID(host: LaneFlowHost, dispatchEventId: string, lane?: string): Promise<TypedResolveOutcome>;
89
+ /**
90
+ * Free a typed event's in-memory hot-path dedupe claim by its source pair —
91
+ * the ParallEvent-keyed mirror of the gateway's clearTypedDispatchDedupe
92
+ * (which keys on the wire DispatchNewData). Used when a buffered typed
93
+ * dispatch ran but its resolution failed: the member re-drives, and a stale
94
+ * local claim would make this pod reject the retry forever.
95
+ *
96
+ * PARITY: the switch below and clearTypedDispatchDedupe's must handle the
97
+ * same typed source families — when adding a new typed event type, extend
98
+ * BOTH (they key the same dedupe entries from different event shapes).
99
+ */
100
+ export declare function clearTypedDedupeForEvent(host: LaneFlowHost, event: ParallEvent): void;
101
+ /**
102
+ * Settle a drained typed group — the one wrapper-less dispatch path: these
103
+ * events buffered behind a busy main (fork-less adapter), their consume
104
+ * guards returned false and released the claims, so the drain site owns the
105
+ * terminal resolution. Rows are pending — the by-id close resolves them
106
+ * without a fence; a row a successor lane meanwhile claimed answers stale and
107
+ * is that owner's to finish. `turnErrored` (consumed at the call site before
108
+ * the drain can start another turn) leaves the rows for the renotify pacing
109
+ * instead. Either way a row left live gets its local dedupe claim freed, or
110
+ * this pod would reject the retry forever.
111
+ */
112
+ export declare function settleDrainedTypedGroup(host: LaneFlowHost, events: ParallEvent[], ids: string[], turnErrored: boolean): Promise<void>;
113
+ /** Consumption hooks for one typed dispatch. */
114
+ export interface TypedConsumeHooks {
115
+ /**
116
+ * Legacy administrative ack — invoked ONLY on the ledger-disabled fallback
117
+ * path (old server). On the ledger path the WorkItem resolves through the
118
+ * sources-form complete instead; this callback never fires there.
119
+ */
120
+ legacyAck: (dispatchEventId?: string) => boolean | void | Promise<boolean | void>;
121
+ /**
122
+ * Free the item's in-memory hot-path dedupe claim. Invoked when the handler
123
+ * ran but the resolution could not commit (sources-form complete failed) —
124
+ * the member is released for re-drive, and a stale local claim would make
125
+ * this pod reject its own retry forever.
126
+ */
127
+ clearDedupe?: () => void;
128
+ }
61
129
  /**
62
130
  * Consume one typed dispatch (task/comment/schedule/trigger/approval) under
63
131
  * its typed-lane occupancy guard: claim the dsp:<id> lane (skip when another
64
- * pod holds it or the WorkItem is already resolved), run the handler, ack on
65
- * success (the doc's option (b): notification delivered, tracked elsewhere),
66
- * then release the lane. Legacy run+ack flow when the ledger is unavailable.
132
+ * pod holds it or the WorkItem is already resolved), run the handler, then
133
+ * settle. A successful run resolves the WorkItem terminally via the
134
+ * sources-form complete (turn_outcome ok the server sweeps it, or lets a
135
+ * typed Effect committed during the turn stand, and drops the vacated lane);
136
+ * a failed / errored / unresolved run releases the member back to pending on
137
+ * the redrive budget via the lane complete. Legacy run+ack flow when the
138
+ * ledger is unavailable.
67
139
  *
68
- * Repeated failures back off: a consume that ends un-acked re-arms the
140
+ * Repeated failures back off: a consume that ends unresolved re-arms the
69
141
  * WorkItem's backoff entry, and the next attempt sleeps out the remaining
70
142
  * window before claiming. Without this, complete's release re-drives the
71
143
  * item instantly and a persistently-failing consume (e.g. buffered behind a
@@ -76,7 +148,7 @@ export declare function consumeTypedDispatch(host: LaneFlowHost, ref: {
76
148
  dispatchEventId?: string;
77
149
  sourceType?: string;
78
150
  sourceId?: string;
79
- }, run: (dispatchEventId?: string) => Promise<boolean>, ack: (dispatchEventId?: string) => boolean | void | Promise<boolean | void>): Promise<void>;
151
+ }, run: (dispatchEventId?: string) => Promise<boolean>, hooks: TypedConsumeHooks): Promise<void>;
80
152
  /**
81
153
  * Shared consumption of a message WorkItem referenced by id — the ONE
82
154
  * protocol for dispatch catch-up pages and post-complete re-drive hints
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-lane-flow.d.ts","sourceRoot":"","sources":["../src/gateway-lane-flow.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { ApiError } from '@parall/sdk';
1
2
  import { LedgerUnsupportedError } from './lane-ledger.js';
2
3
  /**
3
4
  * Dispatch one group of same-lane message events under the ledger contract:
@@ -40,6 +41,9 @@ export async function dispatchLaneGroup(host, opts) {
40
41
  }
41
42
  return 'foreign';
42
43
  }
44
+ // Register the session's active lane so external activity signals
45
+ // (touchRuntimeActivity from adapter hooks) renew exactly this lane.
46
+ host.noteSessionLane(opts.sessionKey, lane.laneKey);
43
47
  let dispatched = false;
44
48
  try {
45
49
  dispatched = await host.runDispatch(event, opts.sessionKey, opts.body, opts.earlier, opts.captureText);
@@ -47,17 +51,206 @@ export async function dispatchLaneGroup(host, opts) {
47
51
  catch (err) {
48
52
  // Failed turn: hand the members back so the retry (this pod or the
49
53
  // next) re-claims immediately instead of waiting out the lease.
54
+ host.noteSessionLane(opts.sessionKey, null);
50
55
  await ledger.release(lane.laneKey).catch(() => { });
51
56
  throw err;
52
57
  }
58
+ finally {
59
+ if (dispatched)
60
+ host.noteSessionLane(opts.sessionKey, null);
61
+ }
53
62
  if (!dispatched) {
54
63
  // Shutdown short-circuit — shutdown() releases all active lanes.
55
64
  return 'shutdown';
56
65
  }
66
+ if (host.consumeTurnError(opts.sessionKey)) {
67
+ // An error turn must not no_action-sweep its members — settle the lane
68
+ // NOW with an error complete so they release for retry on the redrive
69
+ // budget (dispatch-convergence-design.md §3). Settling immediately (even
70
+ // with same-lane work still buffered) is deliberate: carrying the error
71
+ // across buffered turns would let a later reply broad-cover the failed
72
+ // member, or requeue the later turn's successful work. Released members
73
+ // rejoin the next claim, merged with whatever was buffered. Dropping the
74
+ // local dedupe claims lets the server's re-drive hint retrigger the
75
+ // messages immediately instead of waiting out the renotify pacing.
76
+ ledger.markTurnError(lane.laneKey);
77
+ // Clear dedupe for EVERY lane member, not just this batch: an earlier
78
+ // successful batch may have deferred its complete via hasMoreLocal, so
79
+ // the error complete below releases those members too — their redrive
80
+ // would be permanently blocked by a stale local claim.
81
+ for (const msgId of lane.folded.keys()) {
82
+ host.dispatchedMessages.delete(msgId);
83
+ }
84
+ // Invalidate any armed steer state before settling: a pending injection
85
+ // left over from the failed turn would make the retry claim enter the
86
+ // "already injected" path, produce an empty turn, and no_action-sweep the
87
+ // released members without ever retrying them. abortDispatch is the
88
+ // adapter contract's idempotent "clear pending steer state" hook.
89
+ try {
90
+ host.opts.dispatchAdapter.abortDispatch?.(opts.sessionKey);
91
+ }
92
+ catch {
93
+ // best-effort — a throwing abort must not block the error settlement
94
+ }
95
+ await ledger.completeIfIdle(lane.laneKey, false);
96
+ // 'failed' — callers must NOT record these events as handled: the server
97
+ // just released them for redelivery, and an "already handled" fork prefix
98
+ // (or a consumed fork summary) on the redrive would be a lie.
99
+ return 'failed';
100
+ }
57
101
  const pendingInjections = host.opts.dispatchAdapter.hasPendingInjections?.(opts.sessionKey) ?? false;
58
102
  await ledger.completeIfIdle(lane.laneKey, pendingInjections || opts.hasMoreLocal());
59
103
  return 'dispatched';
60
104
  }
105
+ /**
106
+ * The WorkItem ids of a typed event group whose lifecycle the ledger owns
107
+ * (claimed into dsp lanes by consumeTypedDispatch), or null when the group
108
+ * must stay on the legacy received/ack surface — ledger unavailable, an id
109
+ * missing, or a member that rides a message lane. Non-null means: skip
110
+ * legacy received+ack, resolve via the by-id complete, and fold the
111
+ * turn-error signal into the outcome.
112
+ */
113
+ export function typedLedgerEventIds(host, events) {
114
+ if (!host.laneLedger || host.ledgerDisabled)
115
+ return null;
116
+ const ids = [];
117
+ for (const ev of events) {
118
+ if (!ev.dispatchEventId || host.usesLaneLedger(ev))
119
+ return null;
120
+ ids.push(ev.dispatchEventId);
121
+ }
122
+ return ids.length > 0 ? ids : null;
123
+ }
124
+ /**
125
+ * A pre-by-id server (v1.44) routes a by-id body into its lane-form
126
+ * validation and answers 400 INVALID_REQUEST. Any 400 here means the server
127
+ * did not understand the form — a well-formed by-id call never 400s on a
128
+ * current server — so the caller falls back to the legacy typed ack for the
129
+ * rest of the process (sticky; the bridge restarts on the next update).
130
+ */
131
+ function isByIDCompleteUnsupported(err) {
132
+ return err instanceof ApiError && err.status === 400;
133
+ }
134
+ /**
135
+ * By-id complete (turn_outcome ok): terminal resolution of ONE WorkItem —
136
+ * exact where the source pair is ambiguous across task siblings. `lane`
137
+ * fences the call while the row is claim-owned (a dethroned caller gets
138
+ * 'stale' and must leave the row to its successor); omit it for the
139
+ * wrapper-less pending close (buffered drain, administrative drops).
140
+ */
141
+ export async function resolveDispatchByID(host, dispatchEventId, lane) {
142
+ try {
143
+ await host.opts.client.completeDispatch(host.opts.config.org_id, {
144
+ dispatch_event_id: dispatchEventId,
145
+ ...(lane ? { lane } : {}),
146
+ turn_outcome: 'ok',
147
+ });
148
+ return 'ok';
149
+ }
150
+ catch (err) {
151
+ if (err instanceof ApiError && err.status === 409)
152
+ return 'stale';
153
+ if (isByIDCompleteUnsupported(err))
154
+ return 'unsupported';
155
+ host.opts.log?.warn(`by-id complete failed for ${dispatchEventId} — leaving for re-drive: ${String(err)}`);
156
+ return 'failed';
157
+ }
158
+ }
159
+ /**
160
+ * Free a typed event's in-memory hot-path dedupe claim by its source pair —
161
+ * the ParallEvent-keyed mirror of the gateway's clearTypedDispatchDedupe
162
+ * (which keys on the wire DispatchNewData). Used when a buffered typed
163
+ * dispatch ran but its resolution failed: the member re-drives, and a stale
164
+ * local claim would make this pod reject the retry forever.
165
+ *
166
+ * PARITY: the switch below and clearTypedDispatchDedupe's must handle the
167
+ * same typed source families — when adding a new typed event type, extend
168
+ * BOTH (they key the same dedupe entries from different event shapes).
169
+ */
170
+ export function clearTypedDedupeForEvent(host, event) {
171
+ const sourceId = event.ackSourceId;
172
+ if (!sourceId)
173
+ return;
174
+ switch (event.ackSourceType) {
175
+ case 'task_activity': {
176
+ // Task dedupe keys are `${task_id}:${updated_at}`; the task id is the
177
+ // event target. Prefix-clear mirrors clearTypedDispatchDedupe.
178
+ const prefix = `${event.targetId}:`;
179
+ for (const key of host.dispatchedTasks) {
180
+ if (key.startsWith(prefix))
181
+ host.dispatchedTasks.delete(key);
182
+ }
183
+ break;
184
+ }
185
+ case 'comment':
186
+ host.dispatchedTasks.delete(`comment:${sourceId}`);
187
+ break;
188
+ case 'schedule_run':
189
+ host.dispatchedTasks.delete(`schedule_run:${sourceId}`);
190
+ break;
191
+ case 'external_trigger_run':
192
+ host.dispatchedTasks.delete(`external_trigger_run:${sourceId}`);
193
+ break;
194
+ case 'channel_message':
195
+ host.dispatchedMessages.delete(`channel_message:${sourceId}`);
196
+ break;
197
+ case 'approval':
198
+ host.dispatchedTasks.delete(`approval:${sourceId}`);
199
+ break;
200
+ }
201
+ }
202
+ /**
203
+ * Settle a drained typed group — the one wrapper-less dispatch path: these
204
+ * events buffered behind a busy main (fork-less adapter), their consume
205
+ * guards returned false and released the claims, so the drain site owns the
206
+ * terminal resolution. Rows are pending — the by-id close resolves them
207
+ * without a fence; a row a successor lane meanwhile claimed answers stale and
208
+ * is that owner's to finish. `turnErrored` (consumed at the call site before
209
+ * the drain can start another turn) leaves the rows for the renotify pacing
210
+ * instead. Either way a row left live gets its local dedupe claim freed, or
211
+ * this pod would reject the retry forever.
212
+ */
213
+ export async function settleDrainedTypedGroup(host, events, ids, turnErrored) {
214
+ if (turnErrored) {
215
+ host.opts.log?.info(`buffered typed turn for ${events[events.length - 1]?.messageId} surfaced a runtime error — leaving for re-drive`);
216
+ for (const event of events)
217
+ clearTypedDedupeForEvent(host, event);
218
+ return;
219
+ }
220
+ // The legacy ack BY ID, never by source — task siblings share a source
221
+ // pair, and a by-source ack would sweep the undispatched one. Awaited:
222
+ // these rows are already pending (released at buffer time), so a failed
223
+ // ack must free the local dedupe claim or the pending retry would be
224
+ // self-rejected by this pod forever.
225
+ const legacyAckFrom = async (start) => {
226
+ for (const [j, id] of ids.slice(start).entries()) {
227
+ try {
228
+ await host.opts.client.ackDispatchByID(host.opts.config.org_id, id);
229
+ }
230
+ catch {
231
+ clearTypedDedupeForEvent(host, events[start + j]);
232
+ }
233
+ }
234
+ };
235
+ if (host.typedByIdCompleteUnsupported) {
236
+ // Sticky: the server already answered one by-id probe with 400 — go
237
+ // straight to the legacy acks instead of re-probing per group.
238
+ await legacyAckFrom(0);
239
+ return;
240
+ }
241
+ for (const [i, id] of ids.entries()) {
242
+ const outcome = await resolveDispatchByID(host, id);
243
+ if (outcome === 'unsupported') {
244
+ host.typedByIdCompleteUnsupported = true;
245
+ host.opts.log?.warn('server predates the by-id dispatch complete — falling back to legacy typed acks');
246
+ await legacyAckFrom(i);
247
+ return;
248
+ }
249
+ if (outcome !== 'ok') {
250
+ clearTypedDedupeForEvent(host, events[i]);
251
+ }
252
+ }
253
+ }
61
254
  /** Failure backoff pacing for typed dispatch retries (base 2s, cap 5min). */
62
255
  const TYPED_BACKOFF_BASE_MS = 2_000;
63
256
  const TYPED_BACKOFF_CAP_MS = 5 * 60_000;
@@ -65,18 +258,22 @@ const TYPED_BACKOFF_MAP_CAP = 512;
65
258
  /**
66
259
  * Consume one typed dispatch (task/comment/schedule/trigger/approval) under
67
260
  * its typed-lane occupancy guard: claim the dsp:<id> lane (skip when another
68
- * pod holds it or the WorkItem is already resolved), run the handler, ack on
69
- * success (the doc's option (b): notification delivered, tracked elsewhere),
70
- * then release the lane. Legacy run+ack flow when the ledger is unavailable.
261
+ * pod holds it or the WorkItem is already resolved), run the handler, then
262
+ * settle. A successful run resolves the WorkItem terminally via the
263
+ * sources-form complete (turn_outcome ok the server sweeps it, or lets a
264
+ * typed Effect committed during the turn stand, and drops the vacated lane);
265
+ * a failed / errored / unresolved run releases the member back to pending on
266
+ * the redrive budget via the lane complete. Legacy run+ack flow when the
267
+ * ledger is unavailable.
71
268
  *
72
- * Repeated failures back off: a consume that ends un-acked re-arms the
269
+ * Repeated failures back off: a consume that ends unresolved re-arms the
73
270
  * WorkItem's backoff entry, and the next attempt sleeps out the remaining
74
271
  * window before claiming. Without this, complete's release re-drives the
75
272
  * item instantly and a persistently-failing consume (e.g. buffered behind a
76
273
  * saturated fork pool) spins at wire speed — the client half of the
77
274
  * 2026-07-11 poison loop (the server half is the redrive budget).
78
275
  */
79
- export async function consumeTypedDispatch(host, ref, run, ack) {
276
+ export async function consumeTypedDispatch(host, ref, run, hooks) {
80
277
  const backoffKey = ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`;
81
278
  const armed = host.typedRedriveBackoff.get(backoffKey);
82
279
  if (armed) {
@@ -99,8 +296,8 @@ export async function consumeTypedDispatch(host, ref, run, ack) {
99
296
  // consume — clearing backoff there would let an ack outage re-create the
100
297
  // wire-speed release/re-drive loop against a pre-budget server.
101
298
  const settleAck = (ackResult) => ackResult !== false;
102
- const settle = (acked) => {
103
- if (acked) {
299
+ const settle = (resolved) => {
300
+ if (resolved) {
104
301
  host.typedRedriveBackoff.delete(backoffKey);
105
302
  return;
106
303
  }
@@ -125,7 +322,7 @@ export async function consumeTypedDispatch(host, ref, run, ack) {
125
322
  let acked = false;
126
323
  try {
127
324
  if (await run(ref.dispatchEventId)) {
128
- acked = settleAck(await ack(ref.dispatchEventId));
325
+ acked = settleAck(await hooks.legacyAck(ref.dispatchEventId));
129
326
  }
130
327
  }
131
328
  finally {
@@ -154,21 +351,68 @@ export async function consumeTypedDispatch(host, ref, run, ack) {
154
351
  host.opts.log?.info(`typed dispatch ${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`} not claimable (held elsewhere or already resolved) — skipping`);
155
352
  return;
156
353
  }
157
- let acked = false;
354
+ let resolved = false;
355
+ let viaLegacyAck = false;
158
356
  try {
159
- // Ack must settle before Complete. A fire-and-forget ack races the lane
160
- // release: Complete can return the still-received typed item to pending
161
- // and publish a re-drive while its successful ack is still in flight.
357
+ // A successful run resolves the member terminally through the by-id
358
+ // complete one fenced call that sweeps exactly this WorkItem (a typed
359
+ // Effect committed during the turn already made it terminal idempotent
360
+ // no-op) AND drops the vacated lane. Resolution must settle inside this
361
+ // guard: a fire-and-forget resolve would race the finally's release and
362
+ // spuriously re-drive handled work.
162
363
  if (await run(lane.typedDispatchEventId)) {
163
- acked = settleAck(await ack(lane.typedDispatchEventId));
364
+ if (host.typedByIdCompleteUnsupported || !lane.typedDispatchEventId) {
365
+ // Pre-by-id server (or a defensive claim shape without the id):
366
+ // the legacy administrative ack is still live there.
367
+ viaLegacyAck = true;
368
+ resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
369
+ }
370
+ else {
371
+ const outcome = await resolveDispatchByID(host, lane.typedDispatchEventId, lane.lane);
372
+ if (outcome === 'unsupported') {
373
+ host.typedByIdCompleteUnsupported = true;
374
+ host.opts.log?.warn('server predates the by-id dispatch complete — falling back to the legacy typed ack');
375
+ viaLegacyAck = true;
376
+ resolved = settleAck(await hooks.legacyAck(lane.typedDispatchEventId));
377
+ }
378
+ else if (outcome === 'stale') {
379
+ // A successor lane owns the row — its turn resolves it. Nothing to
380
+ // spin on locally; our claim record is already dethroned. Free the
381
+ // local dedupe claim though: if the successor later FAILS and
382
+ // releases the row, the re-drive may land back on this pod, and a
383
+ // stale local claim would self-reject the retry into the budget.
384
+ hooks.clearDedupe?.();
385
+ resolved = true;
386
+ }
387
+ else {
388
+ resolved = outcome === 'ok';
389
+ if (!resolved) {
390
+ // The member is about to be released for re-drive — free its
391
+ // hot-path dedupe claim first, or this pod rejects its own retry
392
+ // forever (same contract as the legacy ack-failure path).
393
+ hooks.clearDedupe?.();
394
+ }
395
+ }
396
+ }
164
397
  }
165
398
  }
166
399
  finally {
167
- settle(acked);
168
- // Release the occupancy row. A buffered dispatch may outlive this guard
169
- // (lane TTL) acceptable at-least-once; the ledger's resolution paths
170
- // still dedupe the persistent side effects.
171
- await host.laneLedger.completeIfIdle(lane.laneKey, false).catch(() => { });
400
+ settle(resolved);
401
+ if (resolved && !viaLegacyAck) {
402
+ // The by-id complete already dropped (or a takeover already owns) the
403
+ // server-side lane row; only the local record and context file remain.
404
+ host.laneLedger.dropLocal(lane.laneKey);
405
+ }
406
+ else {
407
+ // Two jobs, one call: an unresolved turn (unconsumed / failed /
408
+ // errored / resolution-failed) releases the member back to pending on
409
+ // the redrive budget; a legacy-acked turn still needs its server-side
410
+ // lane row dropped (the ack resolves the row but not the occupancy).
411
+ // A buffered dispatch may outlive this guard (lane TTL) — acceptable
412
+ // at-least-once; the ledger's resolution paths still dedupe the
413
+ // persistent side effects.
414
+ await host.laneLedger.completeIfIdle(lane.laneKey, false).catch(() => { });
415
+ }
172
416
  }
173
417
  }
174
418
  /**
@@ -184,7 +428,22 @@ export async function consumeMessageWorkItem(host, item) {
184
428
  return;
185
429
  if (!host.tryClaimMessage(item.source_id))
186
430
  return;
431
+ // Administrative drop (deleted source / self-sender / skip decision): on
432
+ // the ledger path the by-id complete closes the pending row terminally and
433
+ // refuses (409) a row a live lane owns — the owner's turn resolves it. The
434
+ // legacy ack remains the ledger-disabled / pre-by-id fallback.
435
+ // Fire-and-forget either way: a failed drop leaves the row live and the
436
+ // next re-drive converges on the same drop.
187
437
  const ackItem = () => {
438
+ if (host.laneLedger && !host.ledgerDisabled && !host.typedByIdCompleteUnsupported) {
439
+ void resolveDispatchByID(host, item.id).then((outcome) => {
440
+ if (outcome === 'unsupported') {
441
+ host.typedByIdCompleteUnsupported = true;
442
+ host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => { });
443
+ }
444
+ });
445
+ return;
446
+ }
188
447
  host.opts.client.ackDispatchByID(host.opts.config.org_id, item.id).catch(() => { });
189
448
  };
190
449
  let msg = null;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export * from './provider-config.js';
2
2
  export * from './types.js';
3
3
  export * from './lane-key.js';
4
4
  export type { LaneFlowHost } from './gateway-lane-flow.js';
5
- export { consumeTypedDispatch } from './gateway-lane-flow.js';
5
+ export { consumeTypedDispatch, settleDrainedTypedGroup } from './gateway-lane-flow.js';
6
6
  export * from './session-state.js';
7
7
  export * from './routing.js';
8
8
  export * from './event-format.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACvF,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from './provider-config.js';
2
2
  export * from './types.js';
3
3
  export * from './lane-key.js';
4
- export { consumeTypedDispatch } from './gateway-lane-flow.js';
4
+ export { consumeTypedDispatch, settleDrainedTypedGroup } from './gateway-lane-flow.js';
5
5
  export * from './session-state.js';
6
6
  export * from './routing.js';
7
7
  export * from './event-format.js';
@@ -14,6 +14,13 @@ export type ActiveLane = {
14
14
  /** Lease expiry (ms epoch) and TTL from the claim — renewal pacing state. */
15
15
  leaseUntilMs?: number;
16
16
  leaseTtlMs?: number;
17
+ /**
18
+ * Sticky error bit: some turn on this lane surfaced a runtime error. Read
19
+ * (and only cleared) by the lane's final complete, so an error outcome
20
+ * survives buffered same-lane turns in between — a later successful turn
21
+ * must not no_action-sweep the failed turn's members.
22
+ */
23
+ turnError?: boolean;
17
24
  };
18
25
  /**
19
26
  * Thrown when the server predates the dispatch ledger (claim endpoint 404s
@@ -71,7 +78,22 @@ export declare class LaneLedger {
71
78
  * re-drives any same-target pending work. A STALE_LANE answer means a
72
79
  * takeover already owns the resource — local state is dropped either way.
73
80
  */
81
+ /**
82
+ * Record that the turn on this lane surfaced a runtime error. The flow
83
+ * settles an errored lane immediately (dispatchLaneGroup returns 'failed'
84
+ * after a forced complete), so the bit normally lives for one turn only —
85
+ * it is the transport between the gateway's per-session error signal and
86
+ * this lane's complete request.
87
+ */
88
+ markTurnError(laneKey: string): void;
74
89
  completeIfIdle(laneKey: string, hasMoreLocal: boolean): Promise<void>;
90
+ /**
91
+ * Renew one lane by its key — the external runtime-activity hook for
92
+ * adapters whose tool traffic bypasses the RuntimeEvent stream (openclaw
93
+ * hooks). Scoped to the session's own lane: renewing every lane would let
94
+ * one busy fork keep an unrelated stalled fork's lane leased forever.
95
+ */
96
+ renewByKey(laneKey: string): void;
75
97
  /**
76
98
  * Long-turn keepalive: renew the lane's lease on runtime activity, throttled
77
99
  * so a chatty turn doesn't spam the server. Without this, a legitimately
@@ -101,6 +123,14 @@ export declare class LaneLedger {
101
123
  sourceType?: string;
102
124
  sourceId?: string;
103
125
  }): Promise<ActiveLane | null>;
126
+ /**
127
+ * Drop a lane's local record without any server call — for a typed lane
128
+ * whose member the by-id complete just resolved (the server dropped the
129
+ * vacated lane row in the same transaction). Calling completeIfIdle
130
+ * instead would fire a lane-form Complete at a lane that no longer exists
131
+ * and burn an RPC on the guaranteed STALE_LANE answer.
132
+ */
133
+ dropLocal(laneKey: string): void;
104
134
  /**
105
135
  * Remove the per-lane context file (and its CLI sidecar) when the lane
106
136
  * ends. A leftover file would make a later cross-context send to the same
@@ -1 +1 @@
1
- {"version":3,"file":"lane-ledger.d.ts","sourceRoot":"","sources":["../src/lane-ledger.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;CAAG;AAEpD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAqBrD;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU;IAInB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;gBAGpC,IAAI,EAAE;QACrB,MAAM,EAAE,YAAY,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,aAAa,CAAC;KACrB;IAGH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,+FAA+F;IAC/F,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;IAIpC,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM;IAOtC,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS;IAIvD,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAIzC;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA4EnE;;;;;OAKG;IACG,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BrD;;;;;OAKG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B3E;;;;;;;OAOG;IACH,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IA6BlC;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,yEAAyE;IACzE,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA8B9B;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;CAW1B"}
1
+ {"version":3,"file":"lane-ledger.d.ts","sourceRoot":"","sources":["../src/lane-ledger.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;CAAG;AAEpD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAqBrD;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU;IAInB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;gBAGpC,IAAI,EAAE;QACrB,MAAM,EAAE,YAAY,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,aAAa,CAAC;KACrB;IAGH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,+FAA+F;IAC/F,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;IAIpC,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM;IAOtC,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS;IAIvD,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAIzC;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAsFnE;;;;;OAKG;IACG,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BrD;;;;;OAKG;IACH;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK9B,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B3E;;;;;OAKG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKjC;;;;;;;OAOG;IACH,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IA6BlC;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,yEAAyE;IACzE,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;;;;OAKG;IACG,UAAU,CAAC,GAAG,EAAE;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA8B9B;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;CAW1B"}