@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.
- package/dist/gateway-base.d.ts +33 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +283 -82
- package/dist/gateway-lane-flow.d.ts +78 -6
- package/dist/gateway-lane-flow.d.ts.map +1 -1
- package/dist/gateway-lane-flow.js +277 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lane-ledger.d.ts +30 -0
- package/dist/lane-ledger.d.ts.map +1 -1
- package/dist/lane-ledger.js +50 -1
- package/dist/skills/parall-schedules.d.ts +1 -1
- package/dist/skills/parall-schedules.d.ts.map +1 -1
- package/dist/skills/parall-schedules.js +1 -1
- package/dist/skills/parall-tasks.d.ts +1 -1
- package/dist/skills/parall-tasks.d.ts.map +1 -1
- package/dist/skills/parall-tasks.js +21 -5
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/gateway-base.ts +372 -104
- package/src/gateway-lane-flow.ts +313 -19
- package/src/index.ts +1 -1
- package/src/lane-ledger.ts +60 -3
- package/src/skills/parall-schedules.ts +1 -1
- package/src/skills/parall-tasks.ts +21 -5
- package/src/types.ts +2 -1
package/dist/gateway-base.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as path from 'node:path';
|
|
|
4
4
|
import { ApiError, MENTION_ALL_USER_ID } from '@parall/sdk';
|
|
5
5
|
import { buildEventBody, buildEventBodyForForkResult, buildForkResultPrefix, buildForkScopePrefix, } from './event-format.js';
|
|
6
6
|
import { buildErrorStepContent, } from './dispatch-adapter.js';
|
|
7
|
-
import { consumeMessageWorkItem, consumeTypedDispatch, dispatchLaneGroup, } from './gateway-lane-flow.js';
|
|
7
|
+
import { consumeMessageWorkItem, consumeTypedDispatch, dispatchLaneGroup, resolveDispatchByID, settleDrainedTypedGroup, typedLedgerEventIds, } from './gateway-lane-flow.js';
|
|
8
8
|
import { LaneLedger } from './lane-ledger.js';
|
|
9
9
|
import { routeTrigger } from './routing.js';
|
|
10
10
|
import { clearDispatchMessageId, clearDispatchMetrics, clearDispatchNoReply, clearSessionMessageId, getDispatchMetrics, recordDeliverText, recordMessageSend, recordNoReply, recordToolCall, resetDispatchMetrics, setDispatchMessageId, setDispatchNoReply, setSessionChatId, setSessionMessageId, } from './session-state.js';
|
|
@@ -256,25 +256,28 @@ export class ParallAgentGateway {
|
|
|
256
256
|
// level claim/ack would consume or clear the wrong sibling.
|
|
257
257
|
await this.consumeTypedDispatch(data.dispatch_event_id
|
|
258
258
|
? { dispatchEventId: data.dispatch_event_id }
|
|
259
|
-
: { sourceType: 'task_activity', sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId),
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
: { sourceType: 'task_activity', sourceId: data.id }, (dispatchEventId) => this.handleTaskAssignment(data, data.id, dispatchEventId), {
|
|
260
|
+
legacyAck: (dispatchEventId) => {
|
|
261
|
+
if (dispatchEventId) {
|
|
262
|
+
return this.ackDispatchEvent(dispatchEventId, () => {
|
|
263
|
+
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return this.opts.client
|
|
267
|
+
.ackDispatch(this.opts.config.org_id, {
|
|
268
|
+
source_type: 'task_activity',
|
|
269
|
+
source_id: data.id,
|
|
270
|
+
})
|
|
271
|
+
.then(() => true, (err) => {
|
|
272
|
+
// Same contract as ackDispatchEvent: a failed ack is a
|
|
273
|
+
// failed consume (arms backoff) and must free the hot-path
|
|
274
|
+
// dedupe so the re-drive isn't rejected by this pod forever.
|
|
262
275
|
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
276
|
+
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
277
|
+
return false;
|
|
263
278
|
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.ackDispatch(this.opts.config.org_id, {
|
|
267
|
-
source_type: 'task_activity',
|
|
268
|
-
source_id: data.id,
|
|
269
|
-
})
|
|
270
|
-
.then(() => true, (err) => {
|
|
271
|
-
// Same contract as ackDispatchEvent: a failed ack is a
|
|
272
|
-
// failed consume (arms backoff) and must free the hot-path
|
|
273
|
-
// dedupe so the re-drive isn't rejected by this pod forever.
|
|
274
|
-
this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`);
|
|
275
|
-
this.opts.log?.warn(`dispatch ack failed for task ${data.id}, releasing for re-drive: ${String(err)}`);
|
|
276
|
-
return false;
|
|
277
|
-
});
|
|
279
|
+
},
|
|
280
|
+
clearDedupe: () => this.dispatchedTasks.delete(`${data.id}:${data.updated_at}`),
|
|
278
281
|
});
|
|
279
282
|
}
|
|
280
283
|
catch (err) {
|
|
@@ -296,7 +299,10 @@ export class ParallAgentGateway {
|
|
|
296
299
|
if (!data.source_id || !data.task_id)
|
|
297
300
|
return;
|
|
298
301
|
try {
|
|
299
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleTaskComment(data.source_id, data.task_id ?? '', data.actor_id, data.delivery_reason
|
|
302
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskComment(data.source_id, data.task_id ?? '', data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
303
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
304
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
305
|
+
});
|
|
300
306
|
}
|
|
301
307
|
catch (err) {
|
|
302
308
|
this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -306,7 +312,10 @@ export class ParallAgentGateway {
|
|
|
306
312
|
if (!data.source_id)
|
|
307
313
|
return;
|
|
308
314
|
try {
|
|
309
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason
|
|
315
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleWikiComment(data.source_id, data.actor_id, data.delivery_reason, dispatchEventId), {
|
|
316
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
317
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
318
|
+
});
|
|
310
319
|
}
|
|
311
320
|
catch (err) {
|
|
312
321
|
this.opts.log?.error(`wiki comment dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -319,7 +328,10 @@ export class ParallAgentGateway {
|
|
|
319
328
|
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.handleTaskDispatch(data.task_id ?? '', data.source_id ?? data.task_id ?? '', {
|
|
320
329
|
allowCreator: true,
|
|
321
330
|
dispatchEventId,
|
|
322
|
-
}),
|
|
331
|
+
}), {
|
|
332
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
333
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
334
|
+
});
|
|
323
335
|
}
|
|
324
336
|
catch (err) {
|
|
325
337
|
this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
|
|
@@ -329,7 +341,10 @@ export class ParallAgentGateway {
|
|
|
329
341
|
if (!data.source_id)
|
|
330
342
|
return;
|
|
331
343
|
try {
|
|
332
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id
|
|
344
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(data.source_id, data.actor_id, dispatchEventId), {
|
|
345
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
346
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
347
|
+
});
|
|
333
348
|
}
|
|
334
349
|
catch (err) {
|
|
335
350
|
this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -339,7 +354,10 @@ export class ParallAgentGateway {
|
|
|
339
354
|
if (!data.source_id)
|
|
340
355
|
return;
|
|
341
356
|
try {
|
|
342
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleExternalTriggerRun(data.source_id
|
|
357
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(data.source_id, dispatchEventId), {
|
|
358
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
359
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
360
|
+
});
|
|
343
361
|
}
|
|
344
362
|
catch (err) {
|
|
345
363
|
this.opts.log?.error(`external trigger dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -349,7 +367,10 @@ export class ParallAgentGateway {
|
|
|
349
367
|
if (!data.source_id)
|
|
350
368
|
return;
|
|
351
369
|
try {
|
|
352
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleChannelMessage(data.source_id
|
|
370
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(data.source_id, dispatchEventId), {
|
|
371
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
372
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
373
|
+
});
|
|
353
374
|
}
|
|
354
375
|
catch (err) {
|
|
355
376
|
this.opts.log?.error(`channel message dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -359,7 +380,10 @@ export class ParallAgentGateway {
|
|
|
359
380
|
if (!data.source_id)
|
|
360
381
|
return;
|
|
361
382
|
try {
|
|
362
|
-
await this.consumeTypedDispatch({ dispatchEventId: data.id }, () => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null
|
|
383
|
+
await this.consumeTypedDispatch({ dispatchEventId: data.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(data.source_id, data.actor_id, data.chat_id ?? null, dispatchEventId), {
|
|
384
|
+
legacyAck: () => this.ackDispatchEvent(data.id, () => this.clearTypedDispatchDedupe(data)),
|
|
385
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(data),
|
|
386
|
+
});
|
|
363
387
|
}
|
|
364
388
|
catch (err) {
|
|
365
389
|
this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
@@ -410,6 +434,44 @@ export class ParallAgentGateway {
|
|
|
410
434
|
this.dispatchedMessages.add(id);
|
|
411
435
|
return true;
|
|
412
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Lane currently being dispatched per session — lets external activity
|
|
439
|
+
* signals renew exactly the caller's lane (renewing all lanes would keep
|
|
440
|
+
* an unrelated stalled fork's lane leased forever).
|
|
441
|
+
*/
|
|
442
|
+
sessionActiveLanes = new Map();
|
|
443
|
+
noteSessionLane(sessionKey, laneKey) {
|
|
444
|
+
if (laneKey == null)
|
|
445
|
+
this.sessionActiveLanes.delete(sessionKey);
|
|
446
|
+
else
|
|
447
|
+
this.sessionActiveLanes.set(sessionKey, laneKey);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* External runtime-activity signal for adapters whose tool activity does
|
|
451
|
+
* not flow through the RuntimeEvent stream (openclaw hooks call this from
|
|
452
|
+
* the tool-call lifecycle): renews the session's OWN active ledger lane so
|
|
453
|
+
* a long tool call cannot outlive the lease and get dethroned mid-turn.
|
|
454
|
+
* No-op without an active ledger lane for the session.
|
|
455
|
+
*/
|
|
456
|
+
touchRuntimeActivity(sessionKey) {
|
|
457
|
+
if (this.ledgerDisabled)
|
|
458
|
+
return;
|
|
459
|
+
const laneKey = this.sessionActiveLanes.get(sessionKey);
|
|
460
|
+
if (laneKey)
|
|
461
|
+
this.laneLedger?.renewByKey(laneKey);
|
|
462
|
+
}
|
|
463
|
+
/** Sessions whose in-flight turn surfaced a runtime error event. */
|
|
464
|
+
turnErrorSessions = new Set();
|
|
465
|
+
/**
|
|
466
|
+
* Consume (read-and-clear) the error marker for sessionKey's last turn.
|
|
467
|
+
* Feeds complete's turn_outcome so an error turn's lane members are
|
|
468
|
+
* released for retry instead of no_action-swept (design §3). Consuming
|
|
469
|
+
* (rather than peeking) keeps one-shot fork session keys from accumulating
|
|
470
|
+
* in the set forever.
|
|
471
|
+
*/
|
|
472
|
+
consumeTurnError(sessionKey) {
|
|
473
|
+
return this.turnErrorSessions.delete(sessionKey);
|
|
474
|
+
}
|
|
413
475
|
async emitDispatchReceived(event) {
|
|
414
476
|
const sourceType = event.ackSourceType ?? (event.type === 'task' ? 'task_activity' : 'message');
|
|
415
477
|
const sourceId = event.ackSourceId ?? event.messageId;
|
|
@@ -418,6 +480,20 @@ export class ParallAgentGateway {
|
|
|
418
480
|
source_id: sourceId,
|
|
419
481
|
});
|
|
420
482
|
}
|
|
483
|
+
/**
|
|
484
|
+
* Sticky: the server answered a by-id complete with 400 (predates the
|
|
485
|
+
* form). Typed resolution falls back to the legacy ack for the rest of
|
|
486
|
+
* the process lifetime.
|
|
487
|
+
*/
|
|
488
|
+
typedByIdCompleteUnsupported = false;
|
|
489
|
+
// Typed-face ledger helpers live in gateway-lane-flow.ts; thin delegates
|
|
490
|
+
// keep the site code and tests on the class surface.
|
|
491
|
+
typedLedgerEventIds(events) {
|
|
492
|
+
return typedLedgerEventIds(this.laneFlowHost(), events);
|
|
493
|
+
}
|
|
494
|
+
resolveDispatchByID(dispatchEventId, lane) {
|
|
495
|
+
return resolveDispatchByID(this.laneFlowHost(), dispatchEventId, lane);
|
|
496
|
+
}
|
|
421
497
|
/** True when this event's lifecycle is owned by the dispatch lane ledger. */
|
|
422
498
|
usesLaneLedger(event) {
|
|
423
499
|
return this.laneLedger != null && !this.ledgerDisabled && this.laneLedger.handles(event);
|
|
@@ -452,15 +528,16 @@ export class ParallAgentGateway {
|
|
|
452
528
|
dispatchLaneGroup(opts) {
|
|
453
529
|
return dispatchLaneGroup(this.laneFlowHost(), opts);
|
|
454
530
|
}
|
|
455
|
-
consumeTypedDispatch(ref, run,
|
|
456
|
-
return consumeTypedDispatch(this.laneFlowHost(), ref, run,
|
|
531
|
+
consumeTypedDispatch(ref, run, hooks) {
|
|
532
|
+
return consumeTypedDispatch(this.laneFlowHost(), ref, run, hooks);
|
|
457
533
|
}
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
//
|
|
463
|
-
//
|
|
534
|
+
// Legacy administrative ack (ledger-disabled fallback only). Typed
|
|
535
|
+
// completion must wait until the ack has either committed or failed.
|
|
536
|
+
// Errors stay best-effort: a failed ack leaves the row received, so
|
|
537
|
+
// Complete releases and re-drives it safely. The boolean outcome feeds the
|
|
538
|
+
// typed-consume backoff — an ack that failed must count as a failed
|
|
539
|
+
// consume, or an ack outage would clear the backoff entry and let the
|
|
540
|
+
// release re-drive spin at wire speed.
|
|
464
541
|
ackDispatchEvent(dispatchEventId, onFailure) {
|
|
465
542
|
return this.opts.client.ackDispatchByID(this.opts.config.org_id, dispatchEventId).then(() => true, (err) => {
|
|
466
543
|
// Complete will return the still-received item to pending and publish
|
|
@@ -471,6 +548,9 @@ export class ParallAgentGateway {
|
|
|
471
548
|
return false;
|
|
472
549
|
});
|
|
473
550
|
}
|
|
551
|
+
// PARITY: this switch and gateway-lane-flow's clearTypedDedupeForEvent must
|
|
552
|
+
// handle the same typed source families — extend BOTH when adding a typed
|
|
553
|
+
// event type (same dedupe entries, keyed from different event shapes).
|
|
474
554
|
clearTypedDispatchDedupe(item) {
|
|
475
555
|
switch (item.event_type) {
|
|
476
556
|
case 'task_assign':
|
|
@@ -814,6 +894,7 @@ export class ParallAgentGateway {
|
|
|
814
894
|
this.pendingRestartNotification = null;
|
|
815
895
|
}
|
|
816
896
|
resetDispatchMetrics(sessionKey);
|
|
897
|
+
this.turnErrorSessions.delete(sessionKey);
|
|
817
898
|
return runWithSessionKey(sessionKey, async () => {
|
|
818
899
|
let dispatchSpan = null;
|
|
819
900
|
setSessionChatId(sessionKey, event.targetId);
|
|
@@ -950,6 +1031,9 @@ export class ParallAgentGateway {
|
|
|
950
1031
|
pendingSendCallIds.delete(runtimeEvent.callId)) {
|
|
951
1032
|
recordMessageSend(sessionKey, !runtimeEvent.error);
|
|
952
1033
|
}
|
|
1034
|
+
if (runtimeEvent.type === 'error') {
|
|
1035
|
+
this.turnErrorSessions.add(sessionKey);
|
|
1036
|
+
}
|
|
953
1037
|
await this.createRuntimeStep(binding.agentSessionId, event, runtimeEvent, stepIdFilePath, contextFilePath, laneContextFilePath);
|
|
954
1038
|
}
|
|
955
1039
|
if (!binding) {
|
|
@@ -1122,7 +1206,12 @@ export class ParallAgentGateway {
|
|
|
1122
1206
|
body: buildForkScopePrefix(last) + buildEventBody(last),
|
|
1123
1207
|
earlier,
|
|
1124
1208
|
captureText: batchText,
|
|
1125
|
-
|
|
1209
|
+
// Per-LANE residue check (parity with the main-buffer path):
|
|
1210
|
+
// the fork queue can hold several lanes (channel + thread of
|
|
1211
|
+
// the same chat). A whole-queue check would defer THIS lane's
|
|
1212
|
+
// complete behind another lane's items and never revisit it —
|
|
1213
|
+
// its members would sit received until lease expiry.
|
|
1214
|
+
hasMoreLocal: () => fork.queue.some((it) => this.dispatchGroupKey(it.event) === this.dispatchGroupKey(last)),
|
|
1126
1215
|
});
|
|
1127
1216
|
if (outcome === 'foreign') {
|
|
1128
1217
|
// Another pod owns the lane — the events stay pending server-side.
|
|
@@ -1130,10 +1219,32 @@ export class ParallAgentGateway {
|
|
|
1130
1219
|
item.resolve(false);
|
|
1131
1220
|
break;
|
|
1132
1221
|
}
|
|
1222
|
+
if (outcome === 'failed') {
|
|
1223
|
+
// Error turn: complete(error) already released the members for
|
|
1224
|
+
// redelivery. Do NOT push them to processedEvents — the redrive
|
|
1225
|
+
// must not arrive wearing an "already handled" prefix. Keep
|
|
1226
|
+
// draining; the released work rejoins the next claim.
|
|
1227
|
+
for (const item of items)
|
|
1228
|
+
item.resolve(false);
|
|
1229
|
+
continue;
|
|
1230
|
+
}
|
|
1133
1231
|
dispatched = outcome === 'dispatched';
|
|
1134
1232
|
}
|
|
1135
1233
|
else {
|
|
1136
1234
|
dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
|
|
1235
|
+
if (dispatched &&
|
|
1236
|
+
this.typedLedgerEventIds(events) &&
|
|
1237
|
+
this.consumeTurnError(fork.fork.sessionKey)) {
|
|
1238
|
+
// Typed error turn in a fork: report failure to the awaiting
|
|
1239
|
+
// typed consumes so the members release for a budgeted retry,
|
|
1240
|
+
// and do NOT record the events as handled — the redrive must
|
|
1241
|
+
// not arrive wearing an "already handled" prefix. Keep draining
|
|
1242
|
+
// (an error turn is not a shutdown).
|
|
1243
|
+
this.opts.log?.info(`typed fork turn for ${last.messageId} surfaced a runtime error — releasing for retry`);
|
|
1244
|
+
for (const item of items)
|
|
1245
|
+
item.resolve(false);
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1137
1248
|
}
|
|
1138
1249
|
if (!dispatched) {
|
|
1139
1250
|
// Shutdown short-circuit — resolve un-acked so the server requeues
|
|
@@ -1168,6 +1279,10 @@ export class ParallAgentGateway {
|
|
|
1168
1279
|
}
|
|
1169
1280
|
}
|
|
1170
1281
|
finally {
|
|
1282
|
+
// One-shot fork keys are never dispatched again — drop any error marker
|
|
1283
|
+
// the legacy (non-ledger) path left unconsumed, or the set grows with
|
|
1284
|
+
// every failed ephemeral fork.
|
|
1285
|
+
this.turnErrorSessions.delete(fork.fork.sessionKey);
|
|
1171
1286
|
if (fork.deadlineTimer) {
|
|
1172
1287
|
clearTimeout(fork.deadlineTimer);
|
|
1173
1288
|
fork.deadlineTimer = null;
|
|
@@ -1295,18 +1410,32 @@ export class ParallAgentGateway {
|
|
|
1295
1410
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1296
1411
|
continue;
|
|
1297
1412
|
}
|
|
1413
|
+
if (outcome === 'failed') {
|
|
1414
|
+
// Error turn settled with complete(error) — members released for
|
|
1415
|
+
// redelivery. The fork results were not consumed by the failed
|
|
1416
|
+
// turn; keep them for the next real dispatch.
|
|
1417
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1298
1420
|
// Dispatched — resolution happened server-side (reply cover or
|
|
1299
1421
|
// no_action sweep); no legacy acks.
|
|
1300
1422
|
continue;
|
|
1301
1423
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1424
|
+
// Buffered typed events are the one wrapper-less dispatch path: their
|
|
1425
|
+
// consumeTypedDispatch guard returned long ago (buffer-main resolves
|
|
1426
|
+
// false) and released the claims, so THIS site owns their resolution.
|
|
1427
|
+
// Message groups here are the ledger-disabled legacy flow.
|
|
1428
|
+
const typedRefs = this.typedLedgerEventIds(events);
|
|
1429
|
+
if (!typedRefs) {
|
|
1430
|
+
try {
|
|
1431
|
+
await this.emitDispatchReceived(event);
|
|
1432
|
+
}
|
|
1433
|
+
catch (err) {
|
|
1434
|
+
this.opts.log?.warn?.(`mark-received failed for buffered dispatch, leaving unacked for retry: ${String(err)}`);
|
|
1435
|
+
this.dispatchState.mainBuffer.unshift(...events);
|
|
1436
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1310
1439
|
}
|
|
1311
1440
|
const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
|
|
1312
1441
|
if (!dispatched) {
|
|
@@ -1317,6 +1446,13 @@ export class ParallAgentGateway {
|
|
|
1317
1446
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1318
1447
|
break;
|
|
1319
1448
|
}
|
|
1449
|
+
if (typedRefs) {
|
|
1450
|
+
// Wrapper-less resolution of the buffered typed group — protocol
|
|
1451
|
+
// lives in gateway-lane-flow.ts. The turn-error marker is consumed
|
|
1452
|
+
// HERE, before this loop can start another turn on the session.
|
|
1453
|
+
await settleDrainedTypedGroup(this.laneFlowHost(), events, typedRefs, this.consumeTurnError(this.opts.runtimeKey));
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1320
1456
|
for (const bufferedEvent of events) {
|
|
1321
1457
|
const sourceType = bufferedEvent.ackSourceType ??
|
|
1322
1458
|
(bufferedEvent.type === 'task' ? 'task_activity' : 'message');
|
|
@@ -1397,21 +1533,36 @@ export class ParallAgentGateway {
|
|
|
1397
1533
|
}
|
|
1398
1534
|
return outcome === 'dispatched';
|
|
1399
1535
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1536
|
+
// Ledger-claimed typed events skip the legacy received write — the
|
|
1537
|
+
// claim already marked the row received, and a second mark here would
|
|
1538
|
+
// wipe its lease owner (the 0713 black-hole shape on the typed face).
|
|
1539
|
+
const typedRefs = this.typedLedgerEventIds([event]);
|
|
1540
|
+
if (!typedRefs) {
|
|
1541
|
+
try {
|
|
1542
|
+
await this.emitDispatchReceived(event);
|
|
1543
|
+
}
|
|
1544
|
+
catch (err) {
|
|
1545
|
+
this.opts.log?.warn?.(`mark-received failed, leaving unacked for retry: ${String(err)}`);
|
|
1546
|
+
this.dispatchState.mainDispatching = false;
|
|
1547
|
+
this.dispatchState.mainCurrentTargetId = undefined;
|
|
1548
|
+
this.mainCurrentGroupKey = undefined;
|
|
1549
|
+
this.dispatchState.mainPreDispatchBranchPoint = undefined;
|
|
1550
|
+
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1551
|
+
return false;
|
|
1552
|
+
}
|
|
1411
1553
|
}
|
|
1412
1554
|
let dispatched = false;
|
|
1413
1555
|
try {
|
|
1414
1556
|
dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
|
|
1557
|
+
if (dispatched && typedRefs && this.consumeTurnError(this.opts.runtimeKey)) {
|
|
1558
|
+
// Typed error turn: report failure to the enclosing typed consume
|
|
1559
|
+
// so the member releases for a budgeted retry instead of being
|
|
1560
|
+
// terminally resolved (tech-debt: typed-dispatch-error-outcome).
|
|
1561
|
+
// Consumed HERE, before the finally's drain can start another
|
|
1562
|
+
// turn on this session and clear the marker.
|
|
1563
|
+
this.opts.log?.info(`typed dispatch turn for ${event.messageId} surfaced a runtime error — releasing for retry`);
|
|
1564
|
+
dispatched = false;
|
|
1565
|
+
}
|
|
1415
1566
|
if (!dispatched) {
|
|
1416
1567
|
// Shutdown short-circuit — restore the fork results so a future
|
|
1417
1568
|
// pod can replay them, and return false so handleMessage skips ack.
|
|
@@ -1438,9 +1589,16 @@ export class ParallAgentGateway {
|
|
|
1438
1589
|
// fold leaves the event buffered — the drain claims it as its own
|
|
1439
1590
|
// turn. Injection requires an exact lane match (same chat AND same
|
|
1440
1591
|
// thread) — a thread message never rides a channel turn.
|
|
1592
|
+
// The adapter-capability check comes BEFORE the fold: on a
|
|
1593
|
+
// buffer-only adapter (openclaw — no enqueueDuringDispatch) a
|
|
1594
|
+
// folded-but-never-injected member would be broad-covered by the
|
|
1595
|
+
// current turn's reply without the model ever seeing it. Leaving
|
|
1596
|
+
// the event un-folded keeps it buffered; the drain claims it as
|
|
1597
|
+
// its own turn and folds it there.
|
|
1441
1598
|
if (this.mainCurrentGroupKey === this.dispatchGroupKey(event) &&
|
|
1599
|
+
this.opts.dispatchAdapter.enqueueDuringDispatch != null &&
|
|
1442
1600
|
(await this.laneLedger?.steerLive(event)) &&
|
|
1443
|
-
(await this.opts.dispatchAdapter.enqueueDuringDispatch
|
|
1601
|
+
(await this.opts.dispatchAdapter.enqueueDuringDispatch(this.opts.runtimeKey, buildEventBody(event)))) {
|
|
1444
1602
|
this.opts.log?.info(`steer folded+injected for ${event.messageId} (will drain for bookkeeping)`);
|
|
1445
1603
|
}
|
|
1446
1604
|
}
|
|
@@ -1474,13 +1632,21 @@ export class ParallAgentGateway {
|
|
|
1474
1632
|
this.dispatchState.mainBuffer.push(event);
|
|
1475
1633
|
return false;
|
|
1476
1634
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1635
|
+
// Ledger-managed events must never touch the legacy received surface
|
|
1636
|
+
// — the fork's lane claim marks them received. A mark-received here
|
|
1637
|
+
// outruns the claim, strands the row ownerless, and the chat goes
|
|
1638
|
+
// silent (the 0713 black hole; dispatch-convergence-design.md §6).
|
|
1639
|
+
// Same rule for ledger-claimed typed events: their dsp-lane claim
|
|
1640
|
+
// owns received-ness, and a re-mark would wipe the lease owner.
|
|
1641
|
+
if (!this.usesLaneLedger(event) && !this.typedLedgerEventIds([event])) {
|
|
1642
|
+
try {
|
|
1643
|
+
await this.emitDispatchReceived(event);
|
|
1644
|
+
}
|
|
1645
|
+
catch (err) {
|
|
1646
|
+
this.opts.log?.warn?.(`mark-received failed for fork dispatch, leaving unacked for retry: ${String(err)}`);
|
|
1647
|
+
this.dispatchState.mainBuffer.push(event);
|
|
1648
|
+
return false;
|
|
1649
|
+
}
|
|
1484
1650
|
}
|
|
1485
1651
|
const fork = await this.opts.dispatchAdapter.forkSession({
|
|
1486
1652
|
sessionKey: this.opts.runtimeKey,
|
|
@@ -1667,7 +1833,10 @@ export class ParallAgentGateway {
|
|
|
1667
1833
|
return;
|
|
1668
1834
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
1669
1835
|
dispatchEventId,
|
|
1670
|
-
}),
|
|
1836
|
+
}), {
|
|
1837
|
+
legacyAck: (dispatchEventId) => this.ackDispatchEvent(dispatchEventId ?? item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
1838
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item),
|
|
1839
|
+
});
|
|
1671
1840
|
}
|
|
1672
1841
|
consumeMessageWorkItem(item) {
|
|
1673
1842
|
return consumeMessageWorkItem(this.laneFlowHost(), item);
|
|
@@ -1729,7 +1898,7 @@ export class ParallAgentGateway {
|
|
|
1729
1898
|
}
|
|
1730
1899
|
return this.handleTaskAssignment(task, ackSourceId, opts.dispatchEventId);
|
|
1731
1900
|
}
|
|
1732
|
-
async handleTaskComment(commentId, taskId, actorId, deliveryReason) {
|
|
1901
|
+
async handleTaskComment(commentId, taskId, actorId, deliveryReason, dispatchEventId) {
|
|
1733
1902
|
if (this.shuttingDown)
|
|
1734
1903
|
return false; // drain window — let server requeue via catch-up
|
|
1735
1904
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -1791,6 +1960,7 @@ export class ParallAgentGateway {
|
|
|
1791
1960
|
deliveryReason: deliveryReason ?? undefined,
|
|
1792
1961
|
ackSourceType: 'comment',
|
|
1793
1962
|
ackSourceId: commentId,
|
|
1963
|
+
dispatchEventId,
|
|
1794
1964
|
};
|
|
1795
1965
|
let dispatched;
|
|
1796
1966
|
try {
|
|
@@ -1806,7 +1976,7 @@ export class ParallAgentGateway {
|
|
|
1806
1976
|
}
|
|
1807
1977
|
return dispatched;
|
|
1808
1978
|
}
|
|
1809
|
-
async handleWikiComment(commentId, actorId, deliveryReason) {
|
|
1979
|
+
async handleWikiComment(commentId, actorId, deliveryReason, dispatchEventId) {
|
|
1810
1980
|
if (this.shuttingDown)
|
|
1811
1981
|
return false; // drain window — let server requeue via catch-up
|
|
1812
1982
|
// Shares the comment dedupe namespace with handleTaskComment; comment IDs
|
|
@@ -1859,6 +2029,7 @@ export class ParallAgentGateway {
|
|
|
1859
2029
|
replyTargetUri: comment.target_uri,
|
|
1860
2030
|
ackSourceType: 'comment',
|
|
1861
2031
|
ackSourceId: commentId,
|
|
2032
|
+
dispatchEventId,
|
|
1862
2033
|
};
|
|
1863
2034
|
let dispatched;
|
|
1864
2035
|
try {
|
|
@@ -1882,7 +2053,7 @@ export class ParallAgentGateway {
|
|
|
1882
2053
|
* access to already-delivered run snapshots, and the runtime must not crash
|
|
1883
2054
|
* or retry forever in that case.
|
|
1884
2055
|
*/
|
|
1885
|
-
async fetchAndHandleScheduleFire(runId, actorId) {
|
|
2056
|
+
async fetchAndHandleScheduleFire(runId, actorId, dispatchEventId) {
|
|
1886
2057
|
let run = null;
|
|
1887
2058
|
try {
|
|
1888
2059
|
run = await this.opts.client.getScheduleRun(this.opts.config.org_id, runId);
|
|
@@ -1903,9 +2074,9 @@ export class ParallAgentGateway {
|
|
|
1903
2074
|
}
|
|
1904
2075
|
if (!run)
|
|
1905
2076
|
return true;
|
|
1906
|
-
return this.handleScheduleFire(run, actorId);
|
|
2077
|
+
return this.handleScheduleFire(run, actorId, dispatchEventId);
|
|
1907
2078
|
}
|
|
1908
|
-
async handleScheduleFire(run, actorId) {
|
|
2079
|
+
async handleScheduleFire(run, actorId, dispatchEventId) {
|
|
1909
2080
|
if (this.shuttingDown)
|
|
1910
2081
|
return false; // drain window — let server requeue via catch-up
|
|
1911
2082
|
const dedupeKey = `schedule_run:${run.id}`;
|
|
@@ -1929,6 +2100,7 @@ export class ParallAgentGateway {
|
|
|
1929
2100
|
attachedUri: run.fired_attached_uri ?? undefined,
|
|
1930
2101
|
ackSourceType: 'schedule_run',
|
|
1931
2102
|
ackSourceId: run.id,
|
|
2103
|
+
dispatchEventId,
|
|
1932
2104
|
};
|
|
1933
2105
|
let dispatched;
|
|
1934
2106
|
try {
|
|
@@ -1943,7 +2115,7 @@ export class ParallAgentGateway {
|
|
|
1943
2115
|
}
|
|
1944
2116
|
return dispatched;
|
|
1945
2117
|
}
|
|
1946
|
-
async fetchAndHandleExternalTriggerRun(runId) {
|
|
2118
|
+
async fetchAndHandleExternalTriggerRun(runId, dispatchEventId) {
|
|
1947
2119
|
let run = null;
|
|
1948
2120
|
try {
|
|
1949
2121
|
run = await this.opts.client.getExternalTriggerRun(this.opts.config.org_id, runId);
|
|
@@ -1959,14 +2131,14 @@ export class ParallAgentGateway {
|
|
|
1959
2131
|
}
|
|
1960
2132
|
if (!run)
|
|
1961
2133
|
return true;
|
|
1962
|
-
return this.handleExternalTriggerRun(run);
|
|
2134
|
+
return this.handleExternalTriggerRun(run, dispatchEventId);
|
|
1963
2135
|
}
|
|
1964
2136
|
// fetchAndHandleChannelMessage resolves a channel_message dispatch to its
|
|
1965
2137
|
// durable ChannelMessage + conversation and hands it to the inbound
|
|
1966
2138
|
// pipeline. targetId = the ChannelConversation id, so per-conversation
|
|
1967
2139
|
// multi-turn continuity rides the same per-target session mechanics as
|
|
1968
2140
|
// chats. Design: docs/engineering-design/external-im-channel-design.md.
|
|
1969
|
-
async fetchAndHandleChannelMessage(messageId) {
|
|
2141
|
+
async fetchAndHandleChannelMessage(messageId, dispatchEventId) {
|
|
1970
2142
|
if (this.shuttingDown)
|
|
1971
2143
|
return false;
|
|
1972
2144
|
// Capped dedupe (the chat-message path, not the unbounded task set): a busy
|
|
@@ -2040,6 +2212,7 @@ export class ParallAgentGateway {
|
|
|
2040
2212
|
channelCliCapable: cliCapable,
|
|
2041
2213
|
ackSourceType: 'channel_message',
|
|
2042
2214
|
ackSourceId: msg.id,
|
|
2215
|
+
dispatchEventId,
|
|
2043
2216
|
};
|
|
2044
2217
|
// Release the claim if the event isn't actually dispatched (or throws) so
|
|
2045
2218
|
// a retry can re-attempt — same contract as the chat-message path.
|
|
@@ -2056,7 +2229,7 @@ export class ParallAgentGateway {
|
|
|
2056
2229
|
}
|
|
2057
2230
|
return dispatched;
|
|
2058
2231
|
}
|
|
2059
|
-
async handleExternalTriggerRun(run) {
|
|
2232
|
+
async handleExternalTriggerRun(run, dispatchEventId) {
|
|
2060
2233
|
if (this.shuttingDown)
|
|
2061
2234
|
return false;
|
|
2062
2235
|
const dedupeKey = `external_trigger_run:${run.id}`;
|
|
@@ -2084,6 +2257,7 @@ export class ParallAgentGateway {
|
|
|
2084
2257
|
attachedUri,
|
|
2085
2258
|
ackSourceType: 'external_trigger_run',
|
|
2086
2259
|
ackSourceId: run.id,
|
|
2260
|
+
dispatchEventId,
|
|
2087
2261
|
};
|
|
2088
2262
|
let dispatched;
|
|
2089
2263
|
try {
|
|
@@ -2098,7 +2272,7 @@ export class ParallAgentGateway {
|
|
|
2098
2272
|
}
|
|
2099
2273
|
return dispatched;
|
|
2100
2274
|
}
|
|
2101
|
-
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId) {
|
|
2275
|
+
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId, dispatchEventId) {
|
|
2102
2276
|
let approval = null;
|
|
2103
2277
|
try {
|
|
2104
2278
|
approval = await this.opts.client.getApproval(approvalId);
|
|
@@ -2131,6 +2305,11 @@ export class ParallAgentGateway {
|
|
|
2131
2305
|
senderName: 'approver',
|
|
2132
2306
|
messageId: approval.id,
|
|
2133
2307
|
body,
|
|
2308
|
+
// The WorkItem's real source pair. Without it the legacy fallback
|
|
2309
|
+
// guessed ('message', approval_id) — a pair no row matches.
|
|
2310
|
+
ackSourceType: 'approval',
|
|
2311
|
+
ackSourceId: approval.id,
|
|
2312
|
+
dispatchEventId,
|
|
2134
2313
|
};
|
|
2135
2314
|
let dispatched;
|
|
2136
2315
|
try {
|
|
@@ -2181,7 +2360,26 @@ export class ParallAgentGateway {
|
|
|
2181
2360
|
break;
|
|
2182
2361
|
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
2183
2362
|
try {
|
|
2184
|
-
|
|
2363
|
+
// Administrative drop of the overflow backlog (summarized to the
|
|
2364
|
+
// agent instead of dispatched). Ledger path: by-id complete —
|
|
2365
|
+
// closes the pending row and refuses (stale) one a live lane
|
|
2366
|
+
// owns; the legacy ack stays as the ledger-disabled / pre-by-id
|
|
2367
|
+
// fallback.
|
|
2368
|
+
if (this.laneLedger && !this.ledgerDisabled && !this.typedByIdCompleteUnsupported) {
|
|
2369
|
+
const outcome = await this.resolveDispatchByID(item.id);
|
|
2370
|
+
if (outcome === 'unsupported') {
|
|
2371
|
+
this.typedByIdCompleteUnsupported = true;
|
|
2372
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
2373
|
+
}
|
|
2374
|
+
else if (outcome === 'failed') {
|
|
2375
|
+
throw new Error('by-id complete failed');
|
|
2376
|
+
}
|
|
2377
|
+
// 'stale' counts as skipped: a live lane owns the row and its
|
|
2378
|
+
// turn will resolve it — nothing left for catch-up to do.
|
|
2379
|
+
}
|
|
2380
|
+
else {
|
|
2381
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
2382
|
+
}
|
|
2185
2383
|
skipped++;
|
|
2186
2384
|
const key = item.event_type;
|
|
2187
2385
|
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
@@ -2193,12 +2391,15 @@ export class ParallAgentGateway {
|
|
|
2193
2391
|
}
|
|
2194
2392
|
processed++;
|
|
2195
2393
|
try {
|
|
2196
|
-
const
|
|
2394
|
+
const typedHooks = {
|
|
2395
|
+
legacyAck: () => this.ackDispatchEvent(item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
2396
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item),
|
|
2397
|
+
};
|
|
2197
2398
|
if (item.event_type === 'task_assign' && item.task_id) {
|
|
2198
2399
|
try {
|
|
2199
2400
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
2200
2401
|
dispatchEventId,
|
|
2201
|
-
}),
|
|
2402
|
+
}), typedHooks);
|
|
2202
2403
|
}
|
|
2203
2404
|
catch (err) {
|
|
2204
2405
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
@@ -2210,7 +2411,7 @@ export class ParallAgentGateway {
|
|
|
2210
2411
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
2211
2412
|
allowCreator: true,
|
|
2212
2413
|
dispatchEventId,
|
|
2213
|
-
}),
|
|
2414
|
+
}), typedHooks);
|
|
2214
2415
|
}
|
|
2215
2416
|
catch (err) {
|
|
2216
2417
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
@@ -2218,22 +2419,22 @@ export class ParallAgentGateway {
|
|
|
2218
2419
|
}
|
|
2219
2420
|
}
|
|
2220
2421
|
else if (item.event_type === 'task_comment' && item.source_id && item.task_id) {
|
|
2221
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleTaskComment(item.source_id, item.task_id ?? '', item.actor_id, item.delivery_reason),
|
|
2422
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskComment(item.source_id, item.task_id ?? '', item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
2222
2423
|
}
|
|
2223
2424
|
else if (item.event_type === 'wiki_comment' && item.source_id) {
|
|
2224
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason),
|
|
2425
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleWikiComment(item.source_id, item.actor_id, item.delivery_reason, dispatchEventId), typedHooks);
|
|
2225
2426
|
}
|
|
2226
2427
|
else if (item.event_type === 'schedule.fire' && item.source_id) {
|
|
2227
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id),
|
|
2428
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleScheduleFire(item.source_id, item.actor_id, dispatchEventId), typedHooks);
|
|
2228
2429
|
}
|
|
2229
2430
|
else if (item.event_type === 'external_trigger' && item.source_id) {
|
|
2230
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleExternalTriggerRun(item.source_id),
|
|
2431
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleExternalTriggerRun(item.source_id, dispatchEventId), typedHooks);
|
|
2231
2432
|
}
|
|
2232
2433
|
else if (item.event_type === 'channel_message' && item.source_id) {
|
|
2233
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleChannelMessage(item.source_id),
|
|
2434
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleChannelMessage(item.source_id, dispatchEventId), typedHooks);
|
|
2234
2435
|
}
|
|
2235
2436
|
else if (item.event_type === 'approval_decided' && item.source_id) {
|
|
2236
|
-
await this.consumeTypedDispatch({ dispatchEventId: item.id }, () => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null),
|
|
2437
|
+
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null, dispatchEventId), typedHooks);
|
|
2237
2438
|
}
|
|
2238
2439
|
else if (item.event_type === 'message' && item.source_id && item.chat_id) {
|
|
2239
2440
|
await this.consumeMessageWorkItem({
|