@adcp/sdk 14.0.0-beta.5 → 14.0.0-beta.6
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/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/AgentClient.js +26 -10
- package/dist/lib/core/AgentClient.js.map +1 -1
- package/dist/lib/core/AgentClient.mjs +26 -10
- package/dist/lib/core/AgentClient.mjs.map +1 -1
- package/dist/lib/core/AsyncHandler.d.mts +4 -2
- package/dist/lib/core/AsyncHandler.d.ts +4 -2
- package/dist/lib/core/AsyncHandler.d.ts.map +1 -1
- package/dist/lib/core/AsyncHandler.js +15 -1
- package/dist/lib/core/AsyncHandler.js.map +1 -1
- package/dist/lib/core/AsyncHandler.mjs +15 -1
- package/dist/lib/core/AsyncHandler.mjs.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +3 -1
- package/dist/lib/core/SingleAgentClient.d.ts +3 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +158 -39
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +167 -40
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.d.mts +57 -2
- package/dist/lib/core/TaskExecutor.d.ts +57 -2
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +382 -44
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +382 -45
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/core/request-proposals-guard.d.mts +11 -0
- package/dist/lib/core/request-proposals-guard.d.ts +12 -0
- package/dist/lib/core/request-proposals-guard.d.ts.map +1 -0
- package/dist/lib/core/request-proposals-guard.js +65 -0
- package/dist/lib/core/request-proposals-guard.js.map +1 -0
- package/dist/lib/core/request-proposals-guard.mjs +39 -0
- package/dist/lib/core/request-proposals-guard.mjs.map +1 -0
- package/dist/lib/core/webhook-registration.d.mts +5 -0
- package/dist/lib/core/webhook-registration.d.ts +5 -0
- package/dist/lib/core/webhook-registration.d.ts.map +1 -1
- package/dist/lib/core/webhook-registration.js +13 -0
- package/dist/lib/core/webhook-registration.js.map +1 -1
- package/dist/lib/core/webhook-registration.mjs +13 -0
- package/dist/lib/core/webhook-registration.mjs.map +1 -1
- package/dist/lib/media-buy/compatibility.d.mts +45 -10
- package/dist/lib/media-buy/compatibility.d.ts +45 -10
- package/dist/lib/media-buy/compatibility.d.ts.map +1 -1
- package/dist/lib/media-buy/compatibility.js +295 -113
- package/dist/lib/media-buy/compatibility.js.map +1 -1
- package/dist/lib/media-buy/compatibility.mjs +295 -113
- package/dist/lib/media-buy/compatibility.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/core.generated.d.mts +334 -85
- package/dist/lib/types/core.generated.d.ts +334 -85
- package/dist/lib/types/core.generated.d.ts.map +1 -1
- package/dist/lib/types/core.generated.js.map +1 -1
- package/dist/lib/types/decline-proposals.d.ts +0 -5
- package/dist/lib/types/index.d.mts +2 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/types/request-proposals.d.ts +254 -36
- package/dist/lib/types/schemas.generated.d.ts +3123 -835
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +192 -85
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +192 -85
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/tools.generated.d.mts +1 -121
- package/dist/lib/types/tools.generated.d.ts +1 -121
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/tools.generated.js.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md +28 -14
- package/docs/llms.txt +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomUUID } from "crypto";
|
|
1
|
+
import { createHash, randomUUID } from "crypto";
|
|
2
2
|
import {
|
|
3
3
|
ProtocolClient,
|
|
4
4
|
normalizeTransportOptions,
|
|
@@ -65,6 +65,14 @@ class BeforeProtocolDispatchHookError extends Error {
|
|
|
65
65
|
}
|
|
66
66
|
original;
|
|
67
67
|
}
|
|
68
|
+
class AfterProtocolDispatchHookError extends Error {
|
|
69
|
+
constructor(original) {
|
|
70
|
+
super("An SDK post-dispatch settlement hook failed.", { cause: original });
|
|
71
|
+
this.original = original;
|
|
72
|
+
this.name = "AfterProtocolDispatchHookError";
|
|
73
|
+
}
|
|
74
|
+
original;
|
|
75
|
+
}
|
|
68
76
|
const GOVERNED_CREDENTIAL_SCAN_MAX_NODES = 1e4;
|
|
69
77
|
const GOVERNED_CREDENTIAL_SCAN_MAX_DEPTH = 64;
|
|
70
78
|
const GOVERNED_CALLBACK_FIELDS = /* @__PURE__ */ new Set(["push_notification_config", "reporting_webhook", "artifact_webhook"]);
|
|
@@ -230,6 +238,8 @@ function resolveIdempotencyKey(taskName, params, serverVersion) {
|
|
|
230
238
|
return void 0;
|
|
231
239
|
}
|
|
232
240
|
const COMPACTED_TASK_STATE_LIMIT = 1e4;
|
|
241
|
+
const DEFAULT_EXTERNAL_TASK_SETTLEMENT_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
242
|
+
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
233
243
|
const TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set([
|
|
234
244
|
"completed",
|
|
235
245
|
"failed",
|
|
@@ -238,9 +248,14 @@ const TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set([
|
|
|
238
248
|
"governance-denied",
|
|
239
249
|
"aborted"
|
|
240
250
|
]);
|
|
251
|
+
const MAX_PENDING_EXTERNAL_TASK_OBSERVATIONS = 8;
|
|
252
|
+
const MAX_RETAINED_EXTERNAL_TASK_ERROR_CHARS = 1024;
|
|
241
253
|
class TaskExecutor {
|
|
242
254
|
constructor(config = {}) {
|
|
243
255
|
this.config = config;
|
|
256
|
+
if (config.externalTaskSettlementRetentionMs !== void 0 && (!Number.isSafeInteger(config.externalTaskSettlementRetentionMs) || config.externalTaskSettlementRetentionMs < 1)) {
|
|
257
|
+
throw new ConfigurationError("externalTaskSettlementRetentionMs must be a positive safe integer.");
|
|
258
|
+
}
|
|
244
259
|
this.responseParser = new ProtocolResponseParser();
|
|
245
260
|
if (config.enableConversationStorage) {
|
|
246
261
|
this.conversationStorage = /* @__PURE__ */ new Map();
|
|
@@ -265,6 +280,14 @@ class TaskExecutor {
|
|
|
265
280
|
}
|
|
266
281
|
}
|
|
267
282
|
config;
|
|
283
|
+
deferredTerminalPublicationTaskIds = /* @__PURE__ */ new Set();
|
|
284
|
+
settlementCapacityReservations = /* @__PURE__ */ new Set();
|
|
285
|
+
closedExternalTaskSettlementTaskIds = /* @__PURE__ */ new Set();
|
|
286
|
+
externalTaskSettlementHandlers = /* @__PURE__ */ new Map();
|
|
287
|
+
externalTaskSettlementInFlight = /* @__PURE__ */ new Map();
|
|
288
|
+
settledExternalTaskObservationKeys = /* @__PURE__ */ new Map();
|
|
289
|
+
externalTaskSettlementExpiry = /* @__PURE__ */ new Map();
|
|
290
|
+
pendingExternalTaskObservations = /* @__PURE__ */ new Map();
|
|
268
291
|
responseParser;
|
|
269
292
|
activeTasks = /* @__PURE__ */ new Map();
|
|
270
293
|
compactedTaskIds = /* @__PURE__ */ new Map();
|
|
@@ -290,9 +313,43 @@ class TaskExecutor {
|
|
|
290
313
|
*
|
|
291
314
|
* @internal
|
|
292
315
|
*/
|
|
293
|
-
observeExternalTaskStatus(taskId, status, result) {
|
|
294
|
-
if (!["completed", "failed", "rejected", "canceled"].includes(status))
|
|
316
|
+
async observeExternalTaskStatus(taskId, status, result, identity = {}) {
|
|
317
|
+
if (!["completed", "failed", "rejected", "canceled", "governance-denied", "aborted"].includes(status)) {
|
|
318
|
+
return { settled: false, result };
|
|
319
|
+
}
|
|
320
|
+
const observation = { status, result, ...identity };
|
|
321
|
+
const observationKey = this.externalTaskObservationKey(observation);
|
|
322
|
+
if (this.closedExternalTaskSettlementTaskIds.has(taskId)) {
|
|
323
|
+
const accepted = this.settledExternalTaskObservationKeys.get(taskId);
|
|
324
|
+
if (accepted?.key === observationKey) {
|
|
325
|
+
return {
|
|
326
|
+
settled: true,
|
|
327
|
+
duplicate: true,
|
|
328
|
+
status: accepted.status,
|
|
329
|
+
...accepted.error !== void 0 && { error: accepted.error }
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
throw new Error("This task already completed durable settlement; the pushed result was not accepted.");
|
|
333
|
+
}
|
|
334
|
+
if (this.deferredTerminalPublicationTaskIds.has(taskId)) {
|
|
335
|
+
const handler = this.externalTaskSettlementHandlers.get(taskId);
|
|
336
|
+
if (handler) return this.settleExternalTaskStatus(taskId, handler, observation);
|
|
337
|
+
return new Promise((resolve, reject) => {
|
|
338
|
+
const pending = this.pendingExternalTaskObservations.get(taskId) ?? [];
|
|
339
|
+
if (pending.length >= MAX_PENDING_EXTERNAL_TASK_OBSERVATIONS) {
|
|
340
|
+
reject(new Error("Too many terminal push notifications are awaiting durable task settlement."));
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
pending.push({ observation, resolve, reject });
|
|
344
|
+
this.pendingExternalTaskObservations.set(taskId, pending);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
295
347
|
this.updateTaskStatus(taskId, status, result);
|
|
348
|
+
return { settled: false, result };
|
|
349
|
+
}
|
|
350
|
+
/** Whether this process can safely settle or reject a durable callback for the operation. */
|
|
351
|
+
hasExternalTaskSettlementRoute(taskId) {
|
|
352
|
+
return this.deferredTerminalPublicationTaskIds.has(taskId) || this.closedExternalTaskSettlementTaskIds.has(taskId) || this.externalTaskSettlementHandlers.has(taskId);
|
|
296
353
|
}
|
|
297
354
|
/**
|
|
298
355
|
* Run the configured pre-send schema check against the user-facing request
|
|
@@ -389,6 +446,7 @@ class TaskExecutor {
|
|
|
389
446
|
}
|
|
390
447
|
async executeTaskWithinDeadline(agent, taskName, params, inputHandler, options = {}, serverVersion, targetCapabilities, beforeProtocolDispatch) {
|
|
391
448
|
if (serverVersion) this.lastKnownServerVersion = serverVersion;
|
|
449
|
+
params = structuredClone(params);
|
|
392
450
|
const taskId = getTaskOperationId(options) ?? randomUUID();
|
|
393
451
|
const startTime = Date.now();
|
|
394
452
|
const workingTimeout = this.config.workingTimeout || 12e4;
|
|
@@ -411,9 +469,14 @@ class TaskExecutor {
|
|
|
411
469
|
idempotencyKey
|
|
412
470
|
};
|
|
413
471
|
this.activeTasks.set(taskId, taskState);
|
|
472
|
+
let dispatchBoundaryOwnsTerminalState = false;
|
|
414
473
|
const taskAbortListener = options.signal ? () => {
|
|
415
474
|
const currentStatus = this.activeTasks.get(taskId)?.status;
|
|
416
475
|
if (currentStatus && !TERMINAL_TASK_STATUSES.has(currentStatus)) {
|
|
476
|
+
if (dispatchBoundaryOwnsTerminalState) {
|
|
477
|
+
this.compactAbandonedObserverTaskState(taskId);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
417
480
|
const reason = options.signal?.reason;
|
|
418
481
|
this.updateTaskStatus(
|
|
419
482
|
taskId,
|
|
@@ -440,6 +503,9 @@ class TaskExecutor {
|
|
|
440
503
|
let governanceResult;
|
|
441
504
|
let effectiveParams = params;
|
|
442
505
|
let governanceAdjusted = false;
|
|
506
|
+
let dispatchCommitted = false;
|
|
507
|
+
let dispatchSettlement;
|
|
508
|
+
let dispatchSettlementStarted = false;
|
|
443
509
|
try {
|
|
444
510
|
await this.config.onActivity?.({
|
|
445
511
|
type: "protocol_request",
|
|
@@ -498,14 +564,15 @@ class TaskExecutor {
|
|
|
498
564
|
effectiveParams = adjustedParams;
|
|
499
565
|
}
|
|
500
566
|
}
|
|
567
|
+
const dispatchParams = structuredClone(effectiveParams);
|
|
501
568
|
const initialMessage = {
|
|
502
569
|
id: randomUUID(),
|
|
503
570
|
role: "user",
|
|
504
|
-
content: { tool: taskName, params:
|
|
571
|
+
content: { tool: taskName, params: dispatchParams },
|
|
505
572
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
506
573
|
metadata: { toolName: taskName, type: "request" }
|
|
507
574
|
};
|
|
508
|
-
const preparedCall = prepareProtocolToolCall(agent,
|
|
575
|
+
const preparedCall = prepareProtocolToolCall(agent, dispatchParams, {
|
|
509
576
|
toolName: taskName,
|
|
510
577
|
webhookUrl,
|
|
511
578
|
webhookSecret: this.config.webhookSecret,
|
|
@@ -514,6 +581,7 @@ class TaskExecutor {
|
|
|
514
581
|
wireAdcpVersion: this.config.wireAdcpVersion,
|
|
515
582
|
versionEnvelope: this.config.versionEnvelope
|
|
516
583
|
});
|
|
584
|
+
let webhookRegistrationPersisted = false;
|
|
517
585
|
if (webhookUrl && this.config.onWebhookRegistration) {
|
|
518
586
|
const registration = webhookRegistrationFromPreparedCall(agent, preparedCall);
|
|
519
587
|
if (registration) {
|
|
@@ -523,16 +591,35 @@ class TaskExecutor {
|
|
|
523
591
|
operationId: taskId,
|
|
524
592
|
...registration
|
|
525
593
|
});
|
|
594
|
+
webhookRegistrationPersisted = true;
|
|
526
595
|
}
|
|
527
596
|
}
|
|
528
597
|
throwIfAborted(options.signal);
|
|
529
|
-
let dispatchCommitted = false;
|
|
530
598
|
if (beforeProtocolDispatch) {
|
|
531
599
|
let decision;
|
|
600
|
+
dispatchBoundaryOwnsTerminalState = true;
|
|
532
601
|
try {
|
|
533
|
-
|
|
602
|
+
if (this.deferredTerminalPublicationTaskIds.size + this.settlementCapacityReservations.size >= COMPACTED_TASK_STATE_LIMIT) {
|
|
603
|
+
throw new Error("The durable task-settlement capacity is exhausted; no mutation claim was attempted.");
|
|
604
|
+
}
|
|
605
|
+
this.settlementCapacityReservations.add(taskId);
|
|
606
|
+
if (webhookRegistrationPersisted) {
|
|
607
|
+
await this.config.onDurableSettlementRequired?.(taskId);
|
|
608
|
+
throwIfAborted(options.signal);
|
|
609
|
+
}
|
|
610
|
+
decision = await beforeProtocolDispatch(dispatchParams, {
|
|
611
|
+
governanceAdjusted,
|
|
612
|
+
publishSettledTaskStatus: (status, data, error) => this.publishSettledTaskStatus(taskId, status, data, error),
|
|
613
|
+
registerExternalTaskSettlement: (handler) => this.registerExternalTaskSettlement(taskId, handler)
|
|
614
|
+
});
|
|
615
|
+
if (decision.action === "dispatch_committed") {
|
|
616
|
+
this.deferredTerminalPublicationTaskIds.add(taskId);
|
|
617
|
+
this.retainExternalTaskSettlementState(taskId);
|
|
618
|
+
}
|
|
534
619
|
} catch (error) {
|
|
535
620
|
throw new BeforeProtocolDispatchHookError(error);
|
|
621
|
+
} finally {
|
|
622
|
+
this.settlementCapacityReservations.delete(taskId);
|
|
536
623
|
}
|
|
537
624
|
if (decision.action === "return") {
|
|
538
625
|
const earlyResult = decision.result;
|
|
@@ -542,7 +629,10 @@ class TaskExecutor {
|
|
|
542
629
|
return attachMatch(earlyResult);
|
|
543
630
|
}
|
|
544
631
|
dispatchCommitted = true;
|
|
632
|
+
dispatchSettlement = decision;
|
|
545
633
|
}
|
|
634
|
+
throwIfAborted(options.signal);
|
|
635
|
+
const postDispatchOptions = dispatchCommitted ? { ...options, signal: void 0 } : options;
|
|
546
636
|
const callOptions = {
|
|
547
637
|
debugLogs,
|
|
548
638
|
webhookUrl,
|
|
@@ -553,12 +643,9 @@ class TaskExecutor {
|
|
|
553
643
|
...this.config.wireAdcpVersion !== void 0 && { wireAdcpVersion: this.config.wireAdcpVersion },
|
|
554
644
|
...this.config.versionEnvelope !== void 0 && { versionEnvelope: this.config.versionEnvelope },
|
|
555
645
|
transport: options.transport ?? this.config.transport,
|
|
556
|
-
// Once a
|
|
557
|
-
//
|
|
558
|
-
|
|
559
|
-
// still rejects promptly and post-call handling marks the outcome
|
|
560
|
-
// ambiguous for reconciliation.
|
|
561
|
-
signal: dispatchCommitted ? void 0 : options.signal,
|
|
646
|
+
// Once dispatch begins for a live committed claim, post-call handling
|
|
647
|
+
// owns durable settlement even if the caller's deadline fires later.
|
|
648
|
+
signal: postDispatchOptions.signal,
|
|
562
649
|
onTransportActivity: this.config.onTransportActivity,
|
|
563
650
|
transportActivityContext: {
|
|
564
651
|
operationId: taskId,
|
|
@@ -568,10 +655,10 @@ class TaskExecutor {
|
|
|
568
655
|
}
|
|
569
656
|
};
|
|
570
657
|
const response = await withPreparedProtocolToolCall(
|
|
571
|
-
{ agent, toolName: taskName, args:
|
|
572
|
-
() => ProtocolClient.callTool(agent, taskName,
|
|
658
|
+
{ agent, toolName: taskName, args: dispatchParams, preparedCall },
|
|
659
|
+
() => ProtocolClient.callTool(agent, taskName, dispatchParams, callOptions)
|
|
573
660
|
);
|
|
574
|
-
throwIfAborted(
|
|
661
|
+
throwIfAborted(postDispatchOptions.signal);
|
|
575
662
|
const respStatus = this.responseParser.getStatus(response);
|
|
576
663
|
await this.config.onActivity?.({
|
|
577
664
|
type: "protocol_response",
|
|
@@ -584,7 +671,7 @@ class TaskExecutor {
|
|
|
584
671
|
payload: response,
|
|
585
672
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
586
673
|
});
|
|
587
|
-
throwIfAborted(
|
|
674
|
+
throwIfAborted(postDispatchOptions.signal);
|
|
588
675
|
const responseMessage = {
|
|
589
676
|
id: randomUUID(),
|
|
590
677
|
role: "agent",
|
|
@@ -593,22 +680,33 @@ class TaskExecutor {
|
|
|
593
680
|
metadata: { toolName: taskName, type: "response" }
|
|
594
681
|
};
|
|
595
682
|
const messages = [initialMessage, responseMessage];
|
|
596
|
-
|
|
683
|
+
let result = await this.handleAsyncResponse(
|
|
597
684
|
agent,
|
|
598
685
|
taskId,
|
|
599
686
|
taskName,
|
|
600
|
-
|
|
687
|
+
dispatchParams,
|
|
601
688
|
response,
|
|
602
689
|
messages,
|
|
603
690
|
inputHandler,
|
|
604
|
-
|
|
691
|
+
postDispatchOptions,
|
|
605
692
|
debugLogs,
|
|
606
|
-
startTime
|
|
693
|
+
startTime,
|
|
694
|
+
dispatchCommitted
|
|
607
695
|
);
|
|
608
|
-
throwIfAborted(
|
|
696
|
+
throwIfAborted(postDispatchOptions.signal);
|
|
609
697
|
if (governanceResult) {
|
|
610
698
|
result.governance = governanceResult;
|
|
611
699
|
}
|
|
700
|
+
if (dispatchSettlement?.onResult) {
|
|
701
|
+
dispatchSettlementStarted = true;
|
|
702
|
+
try {
|
|
703
|
+
result = await dispatchSettlement.onResult(attachMatch(result));
|
|
704
|
+
} catch (error) {
|
|
705
|
+
this.closeExternalTaskSettlement(taskId, error);
|
|
706
|
+
this.updateTaskStatus(taskId, "failed", void 0, error instanceof Error ? error.message : String(error));
|
|
707
|
+
throw new AfterProtocolDispatchHookError(error);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
612
710
|
if (governanceCheckId && this.governanceMiddleware) {
|
|
613
711
|
const govCtx = governanceResult?.governanceContext;
|
|
614
712
|
if (result.status === "completed" && govCtx) {
|
|
@@ -628,10 +726,10 @@ class TaskExecutor {
|
|
|
628
726
|
void 0,
|
|
629
727
|
debugLogs,
|
|
630
728
|
govCtx,
|
|
631
|
-
|
|
729
|
+
postDispatchOptions.signal,
|
|
632
730
|
outcomeIdempotencyKey
|
|
633
731
|
);
|
|
634
|
-
throwIfAborted(
|
|
732
|
+
throwIfAborted(postDispatchOptions.signal);
|
|
635
733
|
if (!result.governanceOutcome) {
|
|
636
734
|
result.governanceOutcomeError = "Outcome reporting to governance agent failed";
|
|
637
735
|
}
|
|
@@ -649,10 +747,10 @@ class TaskExecutor {
|
|
|
649
747
|
{ message: result.error },
|
|
650
748
|
debugLogs,
|
|
651
749
|
govCtx,
|
|
652
|
-
|
|
750
|
+
postDispatchOptions.signal,
|
|
653
751
|
outcomeIdempotencyKey
|
|
654
752
|
);
|
|
655
|
-
throwIfAborted(
|
|
753
|
+
throwIfAborted(postDispatchOptions.signal);
|
|
656
754
|
if (!result.governanceOutcome) {
|
|
657
755
|
result.governanceOutcomeError = "Outcome reporting to governance agent failed";
|
|
658
756
|
}
|
|
@@ -660,6 +758,12 @@ class TaskExecutor {
|
|
|
660
758
|
result.governance = { ...result.governance ?? {}, checkId: governanceCheckId };
|
|
661
759
|
}
|
|
662
760
|
}
|
|
761
|
+
if (dispatchCommitted) {
|
|
762
|
+
result = this.attachSettledContinuationTaskStatus(taskId, result);
|
|
763
|
+
if (TERMINAL_TASK_STATUSES.has(result.status)) {
|
|
764
|
+
this.publishSettledTaskStatus(taskId, result.status, result.data, result.error);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
663
767
|
if (["completed", "failed", "rejected", "canceled", "governance-denied", "aborted"].includes(result.status) && this.activeTasks.get(taskId)?.status !== result.status) {
|
|
664
768
|
this.updateTaskStatus(taskId, result.status, result.data, result.error);
|
|
665
769
|
}
|
|
@@ -669,6 +773,22 @@ class TaskExecutor {
|
|
|
669
773
|
this.updateTaskStatus(taskId, "failed", void 0, error.message);
|
|
670
774
|
throw error;
|
|
671
775
|
}
|
|
776
|
+
if (error instanceof AfterProtocolDispatchHookError) throw error;
|
|
777
|
+
if (dispatchCommitted && dispatchSettlement?.onError && !dispatchSettlementStarted) {
|
|
778
|
+
try {
|
|
779
|
+
await dispatchSettlement.onError(error);
|
|
780
|
+
} catch (settlementError) {
|
|
781
|
+
this.closeExternalTaskSettlement(taskId, settlementError);
|
|
782
|
+
this.updateTaskStatus(
|
|
783
|
+
taskId,
|
|
784
|
+
"failed",
|
|
785
|
+
void 0,
|
|
786
|
+
settlementError instanceof Error ? settlementError.message : String(settlementError)
|
|
787
|
+
);
|
|
788
|
+
throw new AfterProtocolDispatchHookError(settlementError);
|
|
789
|
+
}
|
|
790
|
+
this.closeExternalTaskSettlement(taskId, error);
|
|
791
|
+
}
|
|
672
792
|
if (isAbortOrTimeoutError(error)) {
|
|
673
793
|
if (idempotencyKey && error && typeof error === "object") {
|
|
674
794
|
error.idempotency_key = idempotencyKey;
|
|
@@ -719,12 +839,12 @@ class TaskExecutor {
|
|
|
719
839
|
debug_logs: debugLogs
|
|
720
840
|
};
|
|
721
841
|
}
|
|
722
|
-
async handleAsyncResponse(agent, taskId, taskName, params, response, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now()) {
|
|
842
|
+
async handleAsyncResponse(agent, taskId, taskName, params, response, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now(), deferTerminalTaskStatus = false) {
|
|
723
843
|
const status = this.responseParser.getStatus(response);
|
|
724
844
|
switch (status) {
|
|
725
845
|
case ADCP_STATUS.COMPLETED:
|
|
726
846
|
const completedData = this.extractResponseData(response, debugLogs, taskName);
|
|
727
|
-
this.updateTaskStatus(taskId, "completed", completedData);
|
|
847
|
+
if (!deferTerminalTaskStatus) this.updateTaskStatus(taskId, "completed", completedData);
|
|
728
848
|
const operationSuccess = this.isOperationSuccess(completedData, taskName);
|
|
729
849
|
const validationResult = this.validateResponseSchema(completedData, taskName, debugLogs);
|
|
730
850
|
const finalSuccess = operationSuccess && validationResult.valid;
|
|
@@ -780,7 +900,17 @@ class TaskExecutor {
|
|
|
780
900
|
startTime
|
|
781
901
|
);
|
|
782
902
|
case ADCP_STATUS.SUBMITTED:
|
|
783
|
-
return this.setupSubmittedTask(
|
|
903
|
+
return this.setupSubmittedTask(
|
|
904
|
+
agent,
|
|
905
|
+
taskId,
|
|
906
|
+
taskName,
|
|
907
|
+
response,
|
|
908
|
+
messages,
|
|
909
|
+
options,
|
|
910
|
+
debugLogs,
|
|
911
|
+
startTime,
|
|
912
|
+
deferTerminalTaskStatus
|
|
913
|
+
);
|
|
784
914
|
case ADCP_STATUS.INPUT_REQUIRED:
|
|
785
915
|
return this.handleInputRequired(
|
|
786
916
|
agent,
|
|
@@ -792,7 +922,8 @@ class TaskExecutor {
|
|
|
792
922
|
inputHandler,
|
|
793
923
|
options,
|
|
794
924
|
debugLogs,
|
|
795
|
-
startTime
|
|
925
|
+
startTime,
|
|
926
|
+
deferTerminalTaskStatus
|
|
796
927
|
);
|
|
797
928
|
case ADCP_STATUS.FAILED:
|
|
798
929
|
case ADCP_STATUS.REJECTED:
|
|
@@ -994,7 +1125,7 @@ class TaskExecutor {
|
|
|
994
1125
|
/**
|
|
995
1126
|
* Set up submitted task with webhook
|
|
996
1127
|
*/
|
|
997
|
-
async setupSubmittedTask(agent, taskId, taskName, response, messages, options = {}, debugLogs = [], startTime = Date.now()) {
|
|
1128
|
+
async setupSubmittedTask(agent, taskId, taskName, response, messages, options = {}, debugLogs = [], startTime = Date.now(), deferTerminalTaskStatus = false) {
|
|
998
1129
|
const partialData = this.extractResponseData(response, debugLogs, taskName);
|
|
999
1130
|
let webhookUrl = response.webhookUrl;
|
|
1000
1131
|
if (!webhookUrl && this.config.webhookManager) {
|
|
@@ -1018,14 +1149,16 @@ class TaskExecutor {
|
|
|
1018
1149
|
webhookUrl,
|
|
1019
1150
|
track: async (transport) => {
|
|
1020
1151
|
const task = await this.getTaskStatus(agent, serverTaskId, transport ?? pollingTransport);
|
|
1021
|
-
if (["completed", "failed", "rejected", "canceled"].includes(task.status)) {
|
|
1152
|
+
if (!deferTerminalTaskStatus && ["completed", "failed", "rejected", "canceled"].includes(task.status)) {
|
|
1022
1153
|
this.updateTaskStatus(taskId, task.status, task.result, task.error);
|
|
1023
1154
|
}
|
|
1024
1155
|
return task;
|
|
1025
1156
|
},
|
|
1026
1157
|
waitForCompletion: async (pollInterval = 6e4, signal) => {
|
|
1027
1158
|
const completed = await this.pollTaskCompletion(agent, serverTaskId, pollInterval, pollingTransport, signal);
|
|
1028
|
-
|
|
1159
|
+
if (!deferTerminalTaskStatus || !TERMINAL_TASK_STATUSES.has(completed.status)) {
|
|
1160
|
+
this.updateTaskStatus(taskId, completed.status, completed.data, completed.error);
|
|
1161
|
+
}
|
|
1029
1162
|
return completed;
|
|
1030
1163
|
}
|
|
1031
1164
|
};
|
|
@@ -1049,6 +1182,193 @@ class TaskExecutor {
|
|
|
1049
1182
|
debug_logs: debugLogs
|
|
1050
1183
|
};
|
|
1051
1184
|
}
|
|
1185
|
+
/**
|
|
1186
|
+
* A committed compatibility hook may replace resumable continuations with
|
|
1187
|
+
* wrappers that validate and durably persist their terminal result. Attach
|
|
1188
|
+
* local task publication only after those final wrappers return.
|
|
1189
|
+
*/
|
|
1190
|
+
attachSettledContinuationTaskStatus(taskId, result) {
|
|
1191
|
+
const publish = (status, data, error) => {
|
|
1192
|
+
this.publishSettledTaskStatus(taskId, status, data, error);
|
|
1193
|
+
};
|
|
1194
|
+
if (result.submitted) {
|
|
1195
|
+
const submitted = result.submitted;
|
|
1196
|
+
result.submitted = {
|
|
1197
|
+
...submitted,
|
|
1198
|
+
track: async (transport) => {
|
|
1199
|
+
const task = await submitted.track(transport);
|
|
1200
|
+
publish(task.status, task.result, task.error);
|
|
1201
|
+
return task;
|
|
1202
|
+
},
|
|
1203
|
+
waitForCompletion: async (pollInterval, signal) => {
|
|
1204
|
+
const completion = this.attachSettledContinuationTaskStatus(
|
|
1205
|
+
taskId,
|
|
1206
|
+
await submitted.waitForCompletion(pollInterval, signal)
|
|
1207
|
+
);
|
|
1208
|
+
publish(completion.status, completion.data, completion.error);
|
|
1209
|
+
return completion;
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
if (result.deferred) {
|
|
1214
|
+
const deferred = result.deferred;
|
|
1215
|
+
result.deferred = {
|
|
1216
|
+
...deferred,
|
|
1217
|
+
resume: async (input) => {
|
|
1218
|
+
const completion = this.attachSettledContinuationTaskStatus(taskId, await deferred.resume(input));
|
|
1219
|
+
publish(completion.status, completion.data, completion.error);
|
|
1220
|
+
return completion;
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
return result;
|
|
1225
|
+
}
|
|
1226
|
+
publishSettledTaskStatus(taskId, status, data, error, fromExternalObservation = false) {
|
|
1227
|
+
if (!TERMINAL_TASK_STATUSES.has(status)) return;
|
|
1228
|
+
const task = this.activeTasks.get(taskId);
|
|
1229
|
+
if (!task) return;
|
|
1230
|
+
if (!fromExternalObservation) {
|
|
1231
|
+
this.closeExternalTaskSettlement(
|
|
1232
|
+
taskId,
|
|
1233
|
+
new Error("The task settled through its direct response; a racing pushed result was not accepted.")
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
if (task.status !== status) this.updateTaskStatus(taskId, status, data, error);
|
|
1237
|
+
}
|
|
1238
|
+
rejectPendingExternalTaskObservations(taskId, error) {
|
|
1239
|
+
const pending = this.pendingExternalTaskObservations.get(taskId);
|
|
1240
|
+
this.pendingExternalTaskObservations.delete(taskId);
|
|
1241
|
+
for (const waiter of pending ?? []) waiter.reject(error);
|
|
1242
|
+
}
|
|
1243
|
+
closeExternalTaskSettlement(taskId, error) {
|
|
1244
|
+
this.externalTaskSettlementHandlers.delete(taskId);
|
|
1245
|
+
this.externalTaskSettlementInFlight.delete(taskId);
|
|
1246
|
+
this.closedExternalTaskSettlementTaskIds.add(taskId);
|
|
1247
|
+
this.rejectPendingExternalTaskObservations(taskId, error);
|
|
1248
|
+
}
|
|
1249
|
+
clearExternalTaskSettlementState(taskId) {
|
|
1250
|
+
this.deferredTerminalPublicationTaskIds.delete(taskId);
|
|
1251
|
+
this.closedExternalTaskSettlementTaskIds.delete(taskId);
|
|
1252
|
+
this.externalTaskSettlementHandlers.delete(taskId);
|
|
1253
|
+
this.externalTaskSettlementInFlight.delete(taskId);
|
|
1254
|
+
this.settledExternalTaskObservationKeys.delete(taskId);
|
|
1255
|
+
this.externalTaskSettlementExpiry.delete(taskId);
|
|
1256
|
+
this.rejectPendingExternalTaskObservations(
|
|
1257
|
+
taskId,
|
|
1258
|
+
new Error("The durable push-settlement retention window expired before the observation was accepted.")
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
retainExternalTaskSettlementState(taskId) {
|
|
1262
|
+
const retentionMs = this.config.externalTaskSettlementRetentionMs ?? DEFAULT_EXTERNAL_TASK_SETTLEMENT_RETENTION_MS;
|
|
1263
|
+
const expiry = Date.now() + retentionMs;
|
|
1264
|
+
if ((this.externalTaskSettlementExpiry.get(taskId) ?? 0) >= expiry) return;
|
|
1265
|
+
this.externalTaskSettlementExpiry.set(taskId, expiry);
|
|
1266
|
+
const expire = () => {
|
|
1267
|
+
if (this.externalTaskSettlementExpiry.get(taskId) !== expiry) return;
|
|
1268
|
+
const remaining = expiry - Date.now();
|
|
1269
|
+
if (remaining > 0) {
|
|
1270
|
+
const timer2 = setTimeout(expire, Math.min(remaining, MAX_TIMER_DELAY_MS));
|
|
1271
|
+
timer2.unref?.();
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
this.clearExternalTaskSettlementState(taskId);
|
|
1275
|
+
};
|
|
1276
|
+
const timer = setTimeout(expire, Math.min(retentionMs, MAX_TIMER_DELAY_MS));
|
|
1277
|
+
timer.unref?.();
|
|
1278
|
+
}
|
|
1279
|
+
/** Release short-lived task inspection state without dropping a live durable push fence. */
|
|
1280
|
+
cleanupTerminalTaskInspectionState(taskId) {
|
|
1281
|
+
this.activeTasks.delete(taskId);
|
|
1282
|
+
this.compactedTaskIds.delete(taskId);
|
|
1283
|
+
if (this.deferredTerminalPublicationTaskIds.has(taskId) || this.closedExternalTaskSettlementTaskIds.has(taskId) || this.externalTaskSettlementHandlers.has(taskId)) {
|
|
1284
|
+
if (this.externalTaskSettlementExpiry.has(taskId)) return;
|
|
1285
|
+
}
|
|
1286
|
+
this.clearExternalTaskSettlementState(taskId);
|
|
1287
|
+
}
|
|
1288
|
+
registerExternalTaskSettlement(taskId, handler) {
|
|
1289
|
+
this.externalTaskSettlementHandlers.set(taskId, handler);
|
|
1290
|
+
const pending = this.pendingExternalTaskObservations.get(taskId);
|
|
1291
|
+
if (!pending) return;
|
|
1292
|
+
this.pendingExternalTaskObservations.delete(taskId);
|
|
1293
|
+
for (const waiter of pending) {
|
|
1294
|
+
void this.settleExternalTaskStatus(taskId, handler, waiter.observation).then(waiter.resolve, waiter.reject);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
externalTaskObservationKey(observation) {
|
|
1298
|
+
return createHash("sha256").update(
|
|
1299
|
+
canonicalize({
|
|
1300
|
+
status: observation.status,
|
|
1301
|
+
serverTaskId: observation.serverTaskId ?? null,
|
|
1302
|
+
taskType: observation.taskType ?? null,
|
|
1303
|
+
result: observation.result ?? null
|
|
1304
|
+
})
|
|
1305
|
+
).digest("base64url");
|
|
1306
|
+
}
|
|
1307
|
+
async settleExternalTaskStatus(taskId, handler, observation) {
|
|
1308
|
+
const observationKey = this.externalTaskObservationKey(observation);
|
|
1309
|
+
const existing = this.externalTaskSettlementInFlight.get(taskId);
|
|
1310
|
+
if (existing) {
|
|
1311
|
+
if (existing.waiterCount >= MAX_PENDING_EXTERNAL_TASK_OBSERVATIONS) {
|
|
1312
|
+
throw new Error("Too many terminal push notifications are undergoing durable task settlement.");
|
|
1313
|
+
}
|
|
1314
|
+
existing.waiterCount += 1;
|
|
1315
|
+
try {
|
|
1316
|
+
const accepted = await existing.settlement;
|
|
1317
|
+
if (existing.observationKey !== observationKey) {
|
|
1318
|
+
throw new Error("This task already completed durable settlement; the pushed result was not accepted.");
|
|
1319
|
+
}
|
|
1320
|
+
return { ...accepted, duplicate: true };
|
|
1321
|
+
} finally {
|
|
1322
|
+
existing.waiterCount -= 1;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
const settlement = (async () => {
|
|
1326
|
+
const settled = await handler(observation);
|
|
1327
|
+
const settledStatus = settled.status;
|
|
1328
|
+
if (this.closedExternalTaskSettlementTaskIds.has(taskId)) {
|
|
1329
|
+
throw new Error("The task settled through its direct response; the racing pushed result was not accepted.");
|
|
1330
|
+
}
|
|
1331
|
+
if (this.settledExternalTaskObservationKeys.has(taskId)) {
|
|
1332
|
+
throw new Error("This task already completed durable settlement; the pushed result was not accepted.");
|
|
1333
|
+
}
|
|
1334
|
+
this.publishSettledTaskStatus(taskId, settledStatus, settled.data, settled.error, true);
|
|
1335
|
+
this.settledExternalTaskObservationKeys.set(taskId, {
|
|
1336
|
+
key: observationKey,
|
|
1337
|
+
status: settledStatus,
|
|
1338
|
+
...settled.error !== void 0 && {
|
|
1339
|
+
error: settled.error.slice(0, MAX_RETAINED_EXTERNAL_TASK_ERROR_CHARS)
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1342
|
+
this.closeExternalTaskSettlement(
|
|
1343
|
+
taskId,
|
|
1344
|
+
new Error("The task already completed durable external settlement; a later pushed result was not accepted.")
|
|
1345
|
+
);
|
|
1346
|
+
return {
|
|
1347
|
+
settled: true,
|
|
1348
|
+
result: settled.data,
|
|
1349
|
+
status: settled.status,
|
|
1350
|
+
...settled.error !== void 0 && { error: settled.error }
|
|
1351
|
+
};
|
|
1352
|
+
})();
|
|
1353
|
+
const inFlight = { observationKey, settlement, waiterCount: 1 };
|
|
1354
|
+
this.externalTaskSettlementInFlight.set(taskId, inFlight);
|
|
1355
|
+
try {
|
|
1356
|
+
return await settlement;
|
|
1357
|
+
} finally {
|
|
1358
|
+
if (this.externalTaskSettlementInFlight.get(taskId) === inFlight) {
|
|
1359
|
+
this.externalTaskSettlementInFlight.delete(taskId);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
/** Release abandoned caller data without publishing a premature terminal state. */
|
|
1364
|
+
compactAbandonedObserverTaskState(taskId) {
|
|
1365
|
+
const task = this.activeTasks.get(taskId);
|
|
1366
|
+
if (!task) return;
|
|
1367
|
+
task.params = void 0;
|
|
1368
|
+
task.messages = [];
|
|
1369
|
+
task.options = {};
|
|
1370
|
+
delete task.pendingInput;
|
|
1371
|
+
}
|
|
1052
1372
|
/**
|
|
1053
1373
|
* A working/submitted response carries everything needed to poll externally.
|
|
1054
1374
|
* Keeping the original request in activeTasks after dispatch would pin
|
|
@@ -1067,10 +1387,14 @@ class TaskExecutor {
|
|
|
1067
1387
|
this.compactedTaskIds.delete(taskId);
|
|
1068
1388
|
this.compactedTaskIds.set(taskId, true);
|
|
1069
1389
|
while (this.compactedTaskIds.size > COMPACTED_TASK_STATE_LIMIT) {
|
|
1070
|
-
const oldest = this.compactedTaskIds.keys().
|
|
1390
|
+
const oldest = [...this.compactedTaskIds.keys()].find(
|
|
1391
|
+
(candidate) => !this.deferredTerminalPublicationTaskIds.has(candidate) && !this.externalTaskSettlementHandlers.has(candidate) && !this.externalTaskSettlementInFlight.has(candidate)
|
|
1392
|
+
);
|
|
1071
1393
|
if (oldest === void 0) break;
|
|
1072
1394
|
this.compactedTaskIds.delete(oldest);
|
|
1073
1395
|
this.activeTasks.delete(oldest);
|
|
1396
|
+
this.closeExternalTaskSettlement(oldest, new Error("The compacted task was evicted before push settlement."));
|
|
1397
|
+
this.closedExternalTaskSettlementTaskIds.delete(oldest);
|
|
1074
1398
|
}
|
|
1075
1399
|
}
|
|
1076
1400
|
/**
|
|
@@ -1081,7 +1405,7 @@ class TaskExecutor {
|
|
|
1081
1405
|
* This is common for HITL (human-in-the-loop) workflows where the agent has already processed
|
|
1082
1406
|
* the request and is just signaling that async approval may be needed.
|
|
1083
1407
|
*/
|
|
1084
|
-
async handleInputRequired(agent, taskId, taskName, params, response, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now()) {
|
|
1408
|
+
async handleInputRequired(agent, taskId, taskName, params, response, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now(), deferTerminalTaskStatus = false) {
|
|
1085
1409
|
const inputRequest = this.responseParser.parseInputRequest(response);
|
|
1086
1410
|
if (!inputHandler) {
|
|
1087
1411
|
const partialData = this.extractResponseData(response, debugLogs, taskName);
|
|
@@ -1159,7 +1483,7 @@ class TaskExecutor {
|
|
|
1159
1483
|
const deferred = {
|
|
1160
1484
|
token,
|
|
1161
1485
|
question: inputRequest.question,
|
|
1162
|
-
resume: (input) => this.resumeDeferredTask(token, input)
|
|
1486
|
+
resume: (input) => this.resumeDeferredTask(token, input, !deferTerminalTaskStatus)
|
|
1163
1487
|
};
|
|
1164
1488
|
return {
|
|
1165
1489
|
success: true,
|
|
@@ -1192,7 +1516,8 @@ class TaskExecutor {
|
|
|
1192
1516
|
// Pass handler for multi-round clarification
|
|
1193
1517
|
options,
|
|
1194
1518
|
debugLogs,
|
|
1195
|
-
startTime
|
|
1519
|
+
startTime,
|
|
1520
|
+
deferTerminalTaskStatus
|
|
1196
1521
|
);
|
|
1197
1522
|
}
|
|
1198
1523
|
/**
|
|
@@ -1411,7 +1736,7 @@ class TaskExecutor {
|
|
|
1411
1736
|
/**
|
|
1412
1737
|
* Resume a deferred task (client deferral)
|
|
1413
1738
|
*/
|
|
1414
|
-
async resumeDeferredTask(token, input) {
|
|
1739
|
+
async resumeDeferredTask(token, input, publishTerminalTaskStatus = true) {
|
|
1415
1740
|
if (!this.config.deferredStorage) {
|
|
1416
1741
|
throw new Error("Deferred storage not configured");
|
|
1417
1742
|
}
|
|
@@ -1428,11 +1753,15 @@ class TaskExecutor {
|
|
|
1428
1753
|
state.contextId,
|
|
1429
1754
|
input,
|
|
1430
1755
|
state.messages,
|
|
1431
|
-
void 0
|
|
1756
|
+
void 0,
|
|
1432
1757
|
// No handler for deferred tasks - input was provided by human
|
|
1758
|
+
{},
|
|
1759
|
+
[],
|
|
1760
|
+
Date.now(),
|
|
1761
|
+
!publishTerminalTaskStatus
|
|
1433
1762
|
);
|
|
1434
1763
|
const remainsPaused = ["input-required", "auth-required", "deferred"].includes(resumed.status);
|
|
1435
|
-
if (["completed", "failed", "rejected", "canceled", "governance-denied", "aborted"].includes(resumed.status) && this.activeTasks.get(state.taskId)?.status !== resumed.status) {
|
|
1764
|
+
if (publishTerminalTaskStatus && ["completed", "failed", "rejected", "canceled", "governance-denied", "aborted"].includes(resumed.status) && this.activeTasks.get(state.taskId)?.status !== resumed.status) {
|
|
1436
1765
|
this.updateTaskStatus(state.taskId, resumed.status, resumed.data, resumed.error);
|
|
1437
1766
|
}
|
|
1438
1767
|
if (!remainsPaused) {
|
|
@@ -1440,7 +1769,14 @@ class TaskExecutor {
|
|
|
1440
1769
|
}
|
|
1441
1770
|
return attachMatch(resumed);
|
|
1442
1771
|
} catch (error) {
|
|
1443
|
-
|
|
1772
|
+
if (publishTerminalTaskStatus) {
|
|
1773
|
+
this.updateTaskStatus(
|
|
1774
|
+
state.taskId,
|
|
1775
|
+
"failed",
|
|
1776
|
+
void 0,
|
|
1777
|
+
error instanceof Error ? error.message : String(error)
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1444
1780
|
try {
|
|
1445
1781
|
await this.config.deferredStorage.delete(token);
|
|
1446
1782
|
} catch {
|
|
@@ -1451,7 +1787,7 @@ class TaskExecutor {
|
|
|
1451
1787
|
/**
|
|
1452
1788
|
* Continue a task after receiving input
|
|
1453
1789
|
*/
|
|
1454
|
-
async continueTaskWithInput(agent, taskId, taskName, params, contextId, input, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now()) {
|
|
1790
|
+
async continueTaskWithInput(agent, taskId, taskName, params, contextId, input, messages, inputHandler, options = {}, debugLogs = [], startTime = Date.now(), deferTerminalTaskStatus = false) {
|
|
1455
1791
|
const inputMessage = {
|
|
1456
1792
|
id: randomUUID(),
|
|
1457
1793
|
role: "user",
|
|
@@ -1501,7 +1837,8 @@ class TaskExecutor {
|
|
|
1501
1837
|
inputHandler,
|
|
1502
1838
|
options,
|
|
1503
1839
|
debugLogs,
|
|
1504
|
-
startTime
|
|
1840
|
+
startTime,
|
|
1841
|
+
deferTerminalTaskStatus
|
|
1505
1842
|
);
|
|
1506
1843
|
}
|
|
1507
1844
|
/**
|
|
@@ -1786,8 +2123,7 @@ class TaskExecutor {
|
|
|
1786
2123
|
task.options = {};
|
|
1787
2124
|
delete task.pendingInput;
|
|
1788
2125
|
setTimeout(() => {
|
|
1789
|
-
this.
|
|
1790
|
-
this.compactedTaskIds.delete(taskId);
|
|
2126
|
+
this.cleanupTerminalTaskInspectionState(taskId);
|
|
1791
2127
|
}, 3e4).unref();
|
|
1792
2128
|
}
|
|
1793
2129
|
}
|
|
@@ -1800,6 +2136,7 @@ class TaskExecutor {
|
|
|
1800
2136
|
}
|
|
1801
2137
|
}
|
|
1802
2138
|
export {
|
|
2139
|
+
AfterProtocolDispatchHookError,
|
|
1803
2140
|
BeforeProtocolDispatchHookError,
|
|
1804
2141
|
DeferredTaskError,
|
|
1805
2142
|
InputRequiredError,
|