@parall/agent-core 1.44.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 +8 -0
- package/dist/gateway-base.d.ts.map +1 -1
- package/dist/gateway-base.js +195 -75
- package/dist/gateway-lane-flow.d.ts +75 -5
- package/dist/gateway-lane-flow.d.ts.map +1 -1
- package/dist/gateway-lane-flow.js +234 -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 +8 -0
- package/dist/lane-ledger.d.ts.map +1 -1
- package/dist/lane-ledger.js +14 -0
- 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 +277 -93
- package/src/gateway-lane-flow.ts +270 -18
- package/src/index.ts +1 -1
- package/src/lane-ledger.ts +14 -0
- 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.d.ts
CHANGED
|
@@ -146,6 +146,14 @@ export declare class ParallAgentGateway {
|
|
|
146
146
|
*/
|
|
147
147
|
consumeTurnError(sessionKey: string): boolean;
|
|
148
148
|
private emitDispatchReceived;
|
|
149
|
+
/**
|
|
150
|
+
* Sticky: the server answered a by-id complete with 400 (predates the
|
|
151
|
+
* form). Typed resolution falls back to the legacy ack for the rest of
|
|
152
|
+
* the process lifetime.
|
|
153
|
+
*/
|
|
154
|
+
typedByIdCompleteUnsupported: boolean;
|
|
155
|
+
private typedLedgerEventIds;
|
|
156
|
+
private resolveDispatchByID;
|
|
149
157
|
/** True when this event's lifecycle is owned by the dispatch lane ledger. */
|
|
150
158
|
private usesLaneLedger;
|
|
151
159
|
private disableLedger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiC,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,KAAK,EACV,qBAAqB,EAkBtB,MAAM,aAAa,CAAC;AAOrB,OAAO,EAGL,KAAK,eAAe,EAGpB,KAAK,aAAa,EAEnB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
|
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)}`);
|
|
@@ -456,6 +480,20 @@ export class ParallAgentGateway {
|
|
|
456
480
|
source_id: sourceId,
|
|
457
481
|
});
|
|
458
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
|
+
}
|
|
459
497
|
/** True when this event's lifecycle is owned by the dispatch lane ledger. */
|
|
460
498
|
usesLaneLedger(event) {
|
|
461
499
|
return this.laneLedger != null && !this.ledgerDisabled && this.laneLedger.handles(event);
|
|
@@ -490,15 +528,16 @@ export class ParallAgentGateway {
|
|
|
490
528
|
dispatchLaneGroup(opts) {
|
|
491
529
|
return dispatchLaneGroup(this.laneFlowHost(), opts);
|
|
492
530
|
}
|
|
493
|
-
consumeTypedDispatch(ref, run,
|
|
494
|
-
return consumeTypedDispatch(this.laneFlowHost(), ref, run,
|
|
531
|
+
consumeTypedDispatch(ref, run, hooks) {
|
|
532
|
+
return consumeTypedDispatch(this.laneFlowHost(), ref, run, hooks);
|
|
495
533
|
}
|
|
496
|
-
//
|
|
497
|
-
//
|
|
498
|
-
//
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
-
//
|
|
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.
|
|
502
541
|
ackDispatchEvent(dispatchEventId, onFailure) {
|
|
503
542
|
return this.opts.client.ackDispatchByID(this.opts.config.org_id, dispatchEventId).then(() => true, (err) => {
|
|
504
543
|
// Complete will return the still-received item to pending and publish
|
|
@@ -509,6 +548,9 @@ export class ParallAgentGateway {
|
|
|
509
548
|
return false;
|
|
510
549
|
});
|
|
511
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).
|
|
512
554
|
clearTypedDispatchDedupe(item) {
|
|
513
555
|
switch (item.event_type) {
|
|
514
556
|
case 'task_assign':
|
|
@@ -1190,6 +1232,19 @@ export class ParallAgentGateway {
|
|
|
1190
1232
|
}
|
|
1191
1233
|
else {
|
|
1192
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
|
+
}
|
|
1193
1248
|
}
|
|
1194
1249
|
if (!dispatched) {
|
|
1195
1250
|
// Shutdown short-circuit — resolve un-acked so the server requeues
|
|
@@ -1366,14 +1421,21 @@ export class ParallAgentGateway {
|
|
|
1366
1421
|
// no_action sweep); no legacy acks.
|
|
1367
1422
|
continue;
|
|
1368
1423
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
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
|
+
}
|
|
1377
1439
|
}
|
|
1378
1440
|
const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
|
|
1379
1441
|
if (!dispatched) {
|
|
@@ -1384,6 +1446,13 @@ export class ParallAgentGateway {
|
|
|
1384
1446
|
this.dispatchState.pendingForkResults.unshift(...pendingFork);
|
|
1385
1447
|
break;
|
|
1386
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
|
+
}
|
|
1387
1456
|
for (const bufferedEvent of events) {
|
|
1388
1457
|
const sourceType = bufferedEvent.ackSourceType ??
|
|
1389
1458
|
(bufferedEvent.type === 'task' ? 'task_activity' : 'message');
|
|
@@ -1464,21 +1533,36 @@ export class ParallAgentGateway {
|
|
|
1464
1533
|
}
|
|
1465
1534
|
return outcome === 'dispatched';
|
|
1466
1535
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
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
|
+
}
|
|
1478
1553
|
}
|
|
1479
1554
|
let dispatched = false;
|
|
1480
1555
|
try {
|
|
1481
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
|
+
}
|
|
1482
1566
|
if (!dispatched) {
|
|
1483
1567
|
// Shutdown short-circuit — restore the fork results so a future
|
|
1484
1568
|
// pod can replay them, and return false so handleMessage skips ack.
|
|
@@ -1552,8 +1636,9 @@ export class ParallAgentGateway {
|
|
|
1552
1636
|
// — the fork's lane claim marks them received. A mark-received here
|
|
1553
1637
|
// outruns the claim, strands the row ownerless, and the chat goes
|
|
1554
1638
|
// silent (the 0713 black hole; dispatch-convergence-design.md §6).
|
|
1555
|
-
//
|
|
1556
|
-
|
|
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])) {
|
|
1557
1642
|
try {
|
|
1558
1643
|
await this.emitDispatchReceived(event);
|
|
1559
1644
|
}
|
|
@@ -1748,7 +1833,10 @@ export class ParallAgentGateway {
|
|
|
1748
1833
|
return;
|
|
1749
1834
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
1750
1835
|
dispatchEventId,
|
|
1751
|
-
}),
|
|
1836
|
+
}), {
|
|
1837
|
+
legacyAck: (dispatchEventId) => this.ackDispatchEvent(dispatchEventId ?? item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
1838
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item),
|
|
1839
|
+
});
|
|
1752
1840
|
}
|
|
1753
1841
|
consumeMessageWorkItem(item) {
|
|
1754
1842
|
return consumeMessageWorkItem(this.laneFlowHost(), item);
|
|
@@ -1810,7 +1898,7 @@ export class ParallAgentGateway {
|
|
|
1810
1898
|
}
|
|
1811
1899
|
return this.handleTaskAssignment(task, ackSourceId, opts.dispatchEventId);
|
|
1812
1900
|
}
|
|
1813
|
-
async handleTaskComment(commentId, taskId, actorId, deliveryReason) {
|
|
1901
|
+
async handleTaskComment(commentId, taskId, actorId, deliveryReason, dispatchEventId) {
|
|
1814
1902
|
if (this.shuttingDown)
|
|
1815
1903
|
return false; // drain window — let server requeue via catch-up
|
|
1816
1904
|
const dedupeKey = `comment:${commentId}`;
|
|
@@ -1872,6 +1960,7 @@ export class ParallAgentGateway {
|
|
|
1872
1960
|
deliveryReason: deliveryReason ?? undefined,
|
|
1873
1961
|
ackSourceType: 'comment',
|
|
1874
1962
|
ackSourceId: commentId,
|
|
1963
|
+
dispatchEventId,
|
|
1875
1964
|
};
|
|
1876
1965
|
let dispatched;
|
|
1877
1966
|
try {
|
|
@@ -1887,7 +1976,7 @@ export class ParallAgentGateway {
|
|
|
1887
1976
|
}
|
|
1888
1977
|
return dispatched;
|
|
1889
1978
|
}
|
|
1890
|
-
async handleWikiComment(commentId, actorId, deliveryReason) {
|
|
1979
|
+
async handleWikiComment(commentId, actorId, deliveryReason, dispatchEventId) {
|
|
1891
1980
|
if (this.shuttingDown)
|
|
1892
1981
|
return false; // drain window — let server requeue via catch-up
|
|
1893
1982
|
// Shares the comment dedupe namespace with handleTaskComment; comment IDs
|
|
@@ -1940,6 +2029,7 @@ export class ParallAgentGateway {
|
|
|
1940
2029
|
replyTargetUri: comment.target_uri,
|
|
1941
2030
|
ackSourceType: 'comment',
|
|
1942
2031
|
ackSourceId: commentId,
|
|
2032
|
+
dispatchEventId,
|
|
1943
2033
|
};
|
|
1944
2034
|
let dispatched;
|
|
1945
2035
|
try {
|
|
@@ -1963,7 +2053,7 @@ export class ParallAgentGateway {
|
|
|
1963
2053
|
* access to already-delivered run snapshots, and the runtime must not crash
|
|
1964
2054
|
* or retry forever in that case.
|
|
1965
2055
|
*/
|
|
1966
|
-
async fetchAndHandleScheduleFire(runId, actorId) {
|
|
2056
|
+
async fetchAndHandleScheduleFire(runId, actorId, dispatchEventId) {
|
|
1967
2057
|
let run = null;
|
|
1968
2058
|
try {
|
|
1969
2059
|
run = await this.opts.client.getScheduleRun(this.opts.config.org_id, runId);
|
|
@@ -1984,9 +2074,9 @@ export class ParallAgentGateway {
|
|
|
1984
2074
|
}
|
|
1985
2075
|
if (!run)
|
|
1986
2076
|
return true;
|
|
1987
|
-
return this.handleScheduleFire(run, actorId);
|
|
2077
|
+
return this.handleScheduleFire(run, actorId, dispatchEventId);
|
|
1988
2078
|
}
|
|
1989
|
-
async handleScheduleFire(run, actorId) {
|
|
2079
|
+
async handleScheduleFire(run, actorId, dispatchEventId) {
|
|
1990
2080
|
if (this.shuttingDown)
|
|
1991
2081
|
return false; // drain window — let server requeue via catch-up
|
|
1992
2082
|
const dedupeKey = `schedule_run:${run.id}`;
|
|
@@ -2010,6 +2100,7 @@ export class ParallAgentGateway {
|
|
|
2010
2100
|
attachedUri: run.fired_attached_uri ?? undefined,
|
|
2011
2101
|
ackSourceType: 'schedule_run',
|
|
2012
2102
|
ackSourceId: run.id,
|
|
2103
|
+
dispatchEventId,
|
|
2013
2104
|
};
|
|
2014
2105
|
let dispatched;
|
|
2015
2106
|
try {
|
|
@@ -2024,7 +2115,7 @@ export class ParallAgentGateway {
|
|
|
2024
2115
|
}
|
|
2025
2116
|
return dispatched;
|
|
2026
2117
|
}
|
|
2027
|
-
async fetchAndHandleExternalTriggerRun(runId) {
|
|
2118
|
+
async fetchAndHandleExternalTriggerRun(runId, dispatchEventId) {
|
|
2028
2119
|
let run = null;
|
|
2029
2120
|
try {
|
|
2030
2121
|
run = await this.opts.client.getExternalTriggerRun(this.opts.config.org_id, runId);
|
|
@@ -2040,14 +2131,14 @@ export class ParallAgentGateway {
|
|
|
2040
2131
|
}
|
|
2041
2132
|
if (!run)
|
|
2042
2133
|
return true;
|
|
2043
|
-
return this.handleExternalTriggerRun(run);
|
|
2134
|
+
return this.handleExternalTriggerRun(run, dispatchEventId);
|
|
2044
2135
|
}
|
|
2045
2136
|
// fetchAndHandleChannelMessage resolves a channel_message dispatch to its
|
|
2046
2137
|
// durable ChannelMessage + conversation and hands it to the inbound
|
|
2047
2138
|
// pipeline. targetId = the ChannelConversation id, so per-conversation
|
|
2048
2139
|
// multi-turn continuity rides the same per-target session mechanics as
|
|
2049
2140
|
// chats. Design: docs/engineering-design/external-im-channel-design.md.
|
|
2050
|
-
async fetchAndHandleChannelMessage(messageId) {
|
|
2141
|
+
async fetchAndHandleChannelMessage(messageId, dispatchEventId) {
|
|
2051
2142
|
if (this.shuttingDown)
|
|
2052
2143
|
return false;
|
|
2053
2144
|
// Capped dedupe (the chat-message path, not the unbounded task set): a busy
|
|
@@ -2121,6 +2212,7 @@ export class ParallAgentGateway {
|
|
|
2121
2212
|
channelCliCapable: cliCapable,
|
|
2122
2213
|
ackSourceType: 'channel_message',
|
|
2123
2214
|
ackSourceId: msg.id,
|
|
2215
|
+
dispatchEventId,
|
|
2124
2216
|
};
|
|
2125
2217
|
// Release the claim if the event isn't actually dispatched (or throws) so
|
|
2126
2218
|
// a retry can re-attempt — same contract as the chat-message path.
|
|
@@ -2137,7 +2229,7 @@ export class ParallAgentGateway {
|
|
|
2137
2229
|
}
|
|
2138
2230
|
return dispatched;
|
|
2139
2231
|
}
|
|
2140
|
-
async handleExternalTriggerRun(run) {
|
|
2232
|
+
async handleExternalTriggerRun(run, dispatchEventId) {
|
|
2141
2233
|
if (this.shuttingDown)
|
|
2142
2234
|
return false;
|
|
2143
2235
|
const dedupeKey = `external_trigger_run:${run.id}`;
|
|
@@ -2165,6 +2257,7 @@ export class ParallAgentGateway {
|
|
|
2165
2257
|
attachedUri,
|
|
2166
2258
|
ackSourceType: 'external_trigger_run',
|
|
2167
2259
|
ackSourceId: run.id,
|
|
2260
|
+
dispatchEventId,
|
|
2168
2261
|
};
|
|
2169
2262
|
let dispatched;
|
|
2170
2263
|
try {
|
|
@@ -2179,7 +2272,7 @@ export class ParallAgentGateway {
|
|
|
2179
2272
|
}
|
|
2180
2273
|
return dispatched;
|
|
2181
2274
|
}
|
|
2182
|
-
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId) {
|
|
2275
|
+
async fetchAndHandleApprovalDecided(approvalId, actorId, chatId, dispatchEventId) {
|
|
2183
2276
|
let approval = null;
|
|
2184
2277
|
try {
|
|
2185
2278
|
approval = await this.opts.client.getApproval(approvalId);
|
|
@@ -2212,6 +2305,11 @@ export class ParallAgentGateway {
|
|
|
2212
2305
|
senderName: 'approver',
|
|
2213
2306
|
messageId: approval.id,
|
|
2214
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,
|
|
2215
2313
|
};
|
|
2216
2314
|
let dispatched;
|
|
2217
2315
|
try {
|
|
@@ -2262,7 +2360,26 @@ export class ParallAgentGateway {
|
|
|
2262
2360
|
break;
|
|
2263
2361
|
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
2264
2362
|
try {
|
|
2265
|
-
|
|
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
|
+
}
|
|
2266
2383
|
skipped++;
|
|
2267
2384
|
const key = item.event_type;
|
|
2268
2385
|
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
@@ -2274,12 +2391,15 @@ export class ParallAgentGateway {
|
|
|
2274
2391
|
}
|
|
2275
2392
|
processed++;
|
|
2276
2393
|
try {
|
|
2277
|
-
const
|
|
2394
|
+
const typedHooks = {
|
|
2395
|
+
legacyAck: () => this.ackDispatchEvent(item.id, () => this.clearTypedDispatchDedupe(item)),
|
|
2396
|
+
clearDedupe: () => this.clearTypedDispatchDedupe(item),
|
|
2397
|
+
};
|
|
2278
2398
|
if (item.event_type === 'task_assign' && item.task_id) {
|
|
2279
2399
|
try {
|
|
2280
2400
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
2281
2401
|
dispatchEventId,
|
|
2282
|
-
}),
|
|
2402
|
+
}), typedHooks);
|
|
2283
2403
|
}
|
|
2284
2404
|
catch (err) {
|
|
2285
2405
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
@@ -2291,7 +2411,7 @@ export class ParallAgentGateway {
|
|
|
2291
2411
|
await this.consumeTypedDispatch({ dispatchEventId: item.id }, (dispatchEventId) => this.handleTaskDispatch(item.task_id ?? '', item.source_id ?? item.task_id ?? '', {
|
|
2292
2412
|
allowCreator: true,
|
|
2293
2413
|
dispatchEventId,
|
|
2294
|
-
}),
|
|
2414
|
+
}), typedHooks);
|
|
2295
2415
|
}
|
|
2296
2416
|
catch (err) {
|
|
2297
2417
|
this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
|
|
@@ -2299,22 +2419,22 @@ export class ParallAgentGateway {
|
|
|
2299
2419
|
}
|
|
2300
2420
|
}
|
|
2301
2421
|
else if (item.event_type === 'task_comment' && item.source_id && item.task_id) {
|
|
2302
|
-
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);
|
|
2303
2423
|
}
|
|
2304
2424
|
else if (item.event_type === 'wiki_comment' && item.source_id) {
|
|
2305
|
-
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);
|
|
2306
2426
|
}
|
|
2307
2427
|
else if (item.event_type === 'schedule.fire' && item.source_id) {
|
|
2308
|
-
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);
|
|
2309
2429
|
}
|
|
2310
2430
|
else if (item.event_type === 'external_trigger' && item.source_id) {
|
|
2311
|
-
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);
|
|
2312
2432
|
}
|
|
2313
2433
|
else if (item.event_type === 'channel_message' && item.source_id) {
|
|
2314
|
-
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);
|
|
2315
2435
|
}
|
|
2316
2436
|
else if (item.event_type === 'approval_decided' && item.source_id) {
|
|
2317
|
-
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);
|
|
2318
2438
|
}
|
|
2319
2439
|
else if (item.event_type === 'message' && item.source_id && item.chat_id) {
|
|
2320
2440
|
await this.consumeMessageWorkItem({
|