@bastani/atomic 0.9.45 → 0.9.46-alpha.1
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/CHANGELOG.md +34 -0
- package/dist/builtin/intercom/CHANGELOG.md +11 -0
- package/dist/builtin/intercom/broker/broker.ts +124 -10
- package/dist/builtin/intercom/broker/client.ts +177 -25
- package/dist/builtin/intercom/broker/multinode-router.ts +228 -27
- package/dist/builtin/intercom/broker/multinode-state-store.ts +10 -0
- package/dist/builtin/intercom/broker/recipient-receipts.ts +38 -4
- package/dist/builtin/intercom/broker/send-handler.ts +9 -2
- package/dist/builtin/intercom/broker/sql-outbox-store.ts +29 -4
- package/dist/builtin/intercom/group.ts +25 -0
- package/dist/builtin/intercom/index.bundle.mjs +177 -35
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/retry-policy.ts +7 -0
- package/dist/builtin/intercom/types.ts +21 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +10 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +150 -54
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +39 -0
- package/dist/builtin/workflows/builtin/{chunk-6901nsd6.js → chunk-6jpwc09k.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-vwx023ge.js → chunk-qhm35ntx.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-jvna28mq.js → chunk-zhyqnf5g.js} +331 -68
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +1 -0
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6.md +2 -2
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6_1_sol.md +2 -2
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6_1_terra.md +77 -0
- package/dist/builtin/workflows/src/authoring.d.ts +1 -1
- package/dist/builtin/workflows/src/durable/journal/internal.d.ts +2 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +7076 -3386
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +11075 -7261
- package/dist/builtin/workflows/src/index.js +6768 -3605
- package/dist/builtin/workflows/src/local-worker-entry.mjs +11075 -7261
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +19 -0
- package/dist/core/agent-session-boundaries.d.ts.map +1 -1
- package/dist/core/agent-session-boundaries.js +1 -0
- package/dist/core/agent-session-boundaries.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +2 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +15 -2
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +3 -2
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts +4 -2
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +13 -8
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-recovery.d.ts.map +1 -1
- package/dist/core/agent-session-recovery.js +92 -1
- package/dist/core/agent-session-recovery.js.map +1 -1
- package/dist/core/agent-session-transfer.d.ts.map +1 -1
- package/dist/core/agent-session-transfer.js +5 -0
- package/dist/core/agent-session-transfer.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/copilot-errors.d.ts +6 -0
- package/dist/core/copilot-errors.d.ts.map +1 -0
- package/dist/core/copilot-errors.js +17 -0
- package/dist/core/copilot-errors.js.map +1 -0
- package/dist/core/execution-model-router.d.ts.map +1 -1
- package/dist/core/execution-model-router.js +12 -2
- package/dist/core/execution-model-router.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +7 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +6 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.d.ts +4 -0
- package/dist/core/extensions/workflow-activity-hub.d.ts.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.js +26 -5
- package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
- package/dist/core/extensions/workflow-events.d.ts +5 -0
- package/dist/core/extensions/workflow-events.d.ts.map +1 -1
- package/dist/core/extensions/workflow-events.js.map +1 -1
- package/dist/core/messages.d.ts +5 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +1 -1
- package/dist/core/model-fallback-failures.d.ts.map +1 -1
- package/dist/core/model-fallback-failures.js +37 -3
- package/dist/core/model-fallback-failures.js.map +1 -1
- package/dist/core/model-runtime-streaming.js +2 -2
- package/dist/core/model-runtime-streaming.js.map +1 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +19 -11
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/provider-rate-limits.d.ts +55 -6
- package/dist/core/provider-rate-limits.d.ts.map +1 -1
- package/dist/core/provider-rate-limits.js +182 -29
- package/dist/core/provider-rate-limits.js.map +1 -1
- package/dist/core/provider-request-admission.d.ts.map +1 -1
- package/dist/core/provider-request-admission.js +42 -18
- package/dist/core/provider-request-admission.js.map +1 -1
- package/dist/core/storage/node-sqlite.d.ts.map +1 -1
- package/dist/core/storage/node-sqlite.js +176 -19
- package/dist/core/storage/node-sqlite.js.map +1 -1
- package/dist/core/storage/provider.d.ts +4 -2
- package/dist/core/storage/provider.d.ts.map +1 -1
- package/dist/core/storage/provider.js +94 -5
- package/dist/core/storage/provider.js.map +1 -1
- package/dist/core/structured-output/index.d.ts.map +1 -1
- package/dist/core/structured-output/index.js +15 -8
- package/dist/core/structured-output/index.js.map +1 -1
- package/dist/core/structured-output/provider-failure.d.ts +17 -0
- package/dist/core/structured-output/provider-failure.d.ts.map +1 -0
- package/dist/core/structured-output/provider-failure.js +28 -0
- package/dist/core/structured-output/provider-failure.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +13 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/shell-task-render.d.ts +1 -0
- package/dist/core/tools/shell-task-render.d.ts.map +1 -1
- package/dist/core/tools/shell-task-render.js +7 -2
- package/dist/core/tools/shell-task-render.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +5 -0
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +38 -5
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +3 -2
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +42 -14
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-context.js +2 -1
- package/dist/modes/interactive/interactive-extension-context.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +5 -6
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/rpc/rpc-client-process.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-process.js +8 -1
- package/dist/modes/rpc/rpc-client-process.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js +5 -0
- package/dist/utils/ansi.js.map +1 -1
- package/docs/codemode.md +1 -1
- package/docs/intercom/reference.md +3 -3
- package/docs/models/evals.md +31 -12
- package/docs/models/reference.md +23 -51
- package/docs/models.md +3 -4
- package/docs/providers.md +5 -15
- package/docs/settings.md +1 -1
- package/docs/storage.md +2 -2
- package/docs/tools.md +1 -1
- package/docs/workflows/api-reference.md +20 -1
- package/docs/workflows/operations.md +17 -4
- package/npm-shrinkwrap.json +64 -44
- package/package.json +4 -4
|
@@ -36,6 +36,34 @@ export const PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS = 10_000;
|
|
|
36
36
|
const GROUP_REQUEST_TIMEOUT_MS = 5000;
|
|
37
37
|
const PRESENCE_ACK_TIMEOUT_MS = 5000;
|
|
38
38
|
const RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000;
|
|
39
|
+
/** #3904: retries of a connection the kernel refused before it reached the broker (a full listen backlog). */
|
|
40
|
+
const BROKER_BACKLOG_RETRIES = 6;
|
|
41
|
+
const BROKER_BACKLOG_RETRY_BASE_MS = 25;
|
|
42
|
+
|
|
43
|
+
/** The connect attempt was cancelled by `disconnect()` before it registered. */
|
|
44
|
+
function connectAborted(): IntercomClientDisconnectedError {
|
|
45
|
+
return new IntercomClientDisconnectedError({ cause: new Error("Disconnected before the broker connection registered") });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function abortableDelay(ms: number, signal: AbortSignal): Promise<void> {
|
|
49
|
+
return new Promise((resolveDelay, rejectDelay) => {
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
signal.removeEventListener("abort", onAbort);
|
|
52
|
+
resolveDelay();
|
|
53
|
+
}, ms);
|
|
54
|
+
const onAbort = () => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
rejectDelay(connectAborted());
|
|
57
|
+
};
|
|
58
|
+
if (signal.aborted) onAbort();
|
|
59
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isBacklogRefusal(error: Error): boolean {
|
|
64
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
65
|
+
return code === "ECONNREFUSED" || code === "EAGAIN";
|
|
66
|
+
}
|
|
39
67
|
/** Extra wait past a broker hold, so the broker's own outcome for a held send always arrives first (#3760). */
|
|
40
68
|
const HELD_SEND_GRACE_MS = 5000;
|
|
41
69
|
|
|
@@ -93,6 +121,8 @@ export interface PendingStageMessageRequest {
|
|
|
93
121
|
readonly senderRegistrationName?: string;
|
|
94
122
|
readonly senderReturnAddress?: string;
|
|
95
123
|
readonly live?: boolean;
|
|
124
|
+
/** #4006: the broker authorized the sender as the session that launched the run, not by membership. */
|
|
125
|
+
readonly invocationControl?: true;
|
|
96
126
|
}
|
|
97
127
|
|
|
98
128
|
/** Broker → route owner: the live stage targets a sticky broadcast was actually written to. */
|
|
@@ -212,6 +242,12 @@ export class IntercomClient extends EventEmitter {
|
|
|
212
242
|
/** #3906: the broker of the current registration refuses a pending-stage route without ending the connection. */
|
|
213
243
|
private brokerRefusesPendingStageRoutesInPlace = false;
|
|
214
244
|
private brokerAnswersStatus = false;
|
|
245
|
+
/** #4006: the broker of the current registration accepts `claim_workflow_invocation`. */
|
|
246
|
+
private brokerClaimsWorkflowInvocations = false;
|
|
247
|
+
/** #3904: the connect attempt in progress, which `disconnect()` cancels. */
|
|
248
|
+
private connectAttempt: AbortController | undefined;
|
|
249
|
+
/** #3983: the broker of the current registration accepts `saving`. */
|
|
250
|
+
private brokerExtendsSaves = false;
|
|
215
251
|
private socket: net.Socket | null = null;
|
|
216
252
|
private _sessionId: string | null = null;
|
|
217
253
|
private _supervisorSessionId: string | null = null;
|
|
@@ -231,6 +267,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
231
267
|
private pendingBrokerStatus = new Map<string, { resolve: (report: BrokerStatusReport) => void; reject: (error: Error) => void }>();
|
|
232
268
|
private _groups = normalizeGroups();
|
|
233
269
|
private pendingLiveWorkflowStageRoutes = new Map<string, { resolve(): void; reject(error: Error): void }>();
|
|
270
|
+
private pendingWorkflowInvocationClaims = new Map<string, { resolve(claimed: boolean): void; reject(error: Error): void }>();
|
|
234
271
|
private pendingStageRouteRegistrations = new Map<string, { resolve(): void; reject(error: Error): void }>();
|
|
235
272
|
|
|
236
273
|
private pendingSupervisorAuthorizations = new Map<string, {
|
|
@@ -297,6 +334,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
297
334
|
for (const pending of this.pendingPresence.values()) pending.reject(error);
|
|
298
335
|
for (const pending of this.pendingMemberships.values()) pending.reject(error);
|
|
299
336
|
for (const pending of this.pendingLiveWorkflowStageRoutes.values()) pending.reject(error);
|
|
337
|
+
for (const pending of this.pendingWorkflowInvocationClaims.values()) pending.reject(error);
|
|
300
338
|
for (const pending of this.pendingStageRouteRegistrations.values()) pending.reject(error);
|
|
301
339
|
for (const pending of this.pendingBrokerStatus.values()) pending.reject(error);
|
|
302
340
|
this.pendingLists.clear();
|
|
@@ -306,6 +344,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
306
344
|
this.pendingPresence.clear();
|
|
307
345
|
this.pendingMemberships.clear();
|
|
308
346
|
this.pendingLiveWorkflowStageRoutes.clear();
|
|
347
|
+
this.pendingWorkflowInvocationClaims.clear();
|
|
309
348
|
this.pendingStageRouteRegistrations.clear();
|
|
310
349
|
this.pendingBrokerStatus.clear();
|
|
311
350
|
}
|
|
@@ -345,7 +384,43 @@ export class IntercomClient extends EventEmitter {
|
|
|
345
384
|
return socket;
|
|
346
385
|
}
|
|
347
386
|
|
|
348
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Connect and register. A connection the operating system refuses before it reaches the broker (`ECONNREFUSED`,
|
|
389
|
+
* `EAGAIN`) is retried a few times with a short jittered backoff: when many sessions start at once (a large pooled
|
|
390
|
+
* fan-out) the broker socket's listen backlog fills and the kernel refuses connections the broker would accept a
|
|
391
|
+
* moment later (#3904). Every other failure, and a refusal that persists past the retries, rejects as before.
|
|
392
|
+
*/
|
|
393
|
+
async connect(
|
|
394
|
+
session: Omit<SessionInfo, "id">,
|
|
395
|
+
supervisor?: SupervisorRegistration,
|
|
396
|
+
supervisorOwnerToken?: string,
|
|
397
|
+
messageSource?: Message["source"],
|
|
398
|
+
registrationGroup?: string,
|
|
399
|
+
): Promise<void> {
|
|
400
|
+
// #3904: `disconnect()` aborts this attempt, its retry delay and any later retry, so a session that finished
|
|
401
|
+
// its cleanup never ends up connected and registered by a retry still in flight.
|
|
402
|
+
const attempt = new AbortController();
|
|
403
|
+
this.connectAttempt = attempt;
|
|
404
|
+
try {
|
|
405
|
+
for (let retry = 0; ; retry++) {
|
|
406
|
+
if (attempt.signal.aborted) throw connectAborted();
|
|
407
|
+
try {
|
|
408
|
+
await this.connectOnce(attempt.signal, session, supervisor, supervisorOwnerToken, messageSource, registrationGroup);
|
|
409
|
+
return;
|
|
410
|
+
} catch (error) {
|
|
411
|
+
if (attempt.signal.aborted) throw connectAborted();
|
|
412
|
+
if (!(error instanceof Error) || !isBacklogRefusal(error) || retry >= BROKER_BACKLOG_RETRIES) throw error;
|
|
413
|
+
const backoff = BROKER_BACKLOG_RETRY_BASE_MS * 2 ** retry;
|
|
414
|
+
await abortableDelay(backoff * (0.5 + Math.random() / 2), attempt.signal);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
} finally {
|
|
418
|
+
if (this.connectAttempt === attempt) this.connectAttempt = undefined;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private connectOnce(
|
|
423
|
+
signal: AbortSignal,
|
|
349
424
|
session: Omit<SessionInfo, "id">,
|
|
350
425
|
supervisor?: SupervisorRegistration,
|
|
351
426
|
supervisorOwnerToken?: string,
|
|
@@ -413,6 +488,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
413
488
|
this.brokerAcknowledgesPendingStageRoutes = false;
|
|
414
489
|
this.brokerRefusesPendingStageRoutesInPlace = false;
|
|
415
490
|
this.brokerAnswersStatus = false;
|
|
491
|
+
this.brokerClaimsWorkflowInvocations = false;
|
|
492
|
+
this.brokerExtendsSaves = false;
|
|
416
493
|
this._messageSource = undefined;
|
|
417
494
|
this.disconnectError = null;
|
|
418
495
|
if (connectionEstablished && !wasDisconnecting) {
|
|
@@ -459,7 +536,38 @@ export class IntercomClient extends EventEmitter {
|
|
|
459
536
|
this.handleBrokerMessage(msg);
|
|
460
537
|
}, onReaderError);
|
|
461
538
|
|
|
539
|
+
const onConnect = (): void => {
|
|
540
|
+
if (signal.aborted) {
|
|
541
|
+
onAbort();
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
writeMessage(socket, {
|
|
546
|
+
type: "register",
|
|
547
|
+
session,
|
|
548
|
+
...(registrationGroup !== undefined ? { registrationGroup } : {}),
|
|
549
|
+
returnAddress: this.returnAddress,
|
|
550
|
+
...(this.preferredSessionId === undefined ? {} : { preferredSessionId: this.preferredSessionId }),
|
|
551
|
+
...(this.acknowledgesReceipt ? { acknowledgesReceipt: true as const } : {}),
|
|
552
|
+
...(supervisor ? { supervisor } : {}),
|
|
553
|
+
...(supervisorOwnerToken ? { supervisorOwnerToken } : {}),
|
|
554
|
+
});
|
|
555
|
+
} catch (error) {
|
|
556
|
+
cleanupConnectionAttempt();
|
|
557
|
+
cleanupSocketListeners();
|
|
558
|
+
if (this.socket === socket) {
|
|
559
|
+
this.socket = null;
|
|
560
|
+
}
|
|
561
|
+
socket.destroy();
|
|
562
|
+
reject(toError(error));
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const onAbort = () => onError(connectAborted());
|
|
567
|
+
|
|
462
568
|
const cleanupConnectionAttempt = () => {
|
|
569
|
+
signal.removeEventListener("abort", onAbort);
|
|
570
|
+
socket.off("connect", onConnect);
|
|
463
571
|
this.off("_registered", onRegistered);
|
|
464
572
|
this.off("_registration_failed", onRegistrationFailed);
|
|
465
573
|
socket.off("error", onError);
|
|
@@ -480,26 +588,9 @@ export class IntercomClient extends EventEmitter {
|
|
|
480
588
|
this.once("_registered", onRegistered);
|
|
481
589
|
this.once("_registration_failed", onRegistrationFailed);
|
|
482
590
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
session,
|
|
487
|
-
...(registrationGroup !== undefined ? { registrationGroup } : {}),
|
|
488
|
-
returnAddress: this.returnAddress,
|
|
489
|
-
...(this.preferredSessionId === undefined ? {} : { preferredSessionId: this.preferredSessionId }),
|
|
490
|
-
...(this.acknowledgesReceipt ? { acknowledgesReceipt: true as const } : {}),
|
|
491
|
-
...(supervisor ? { supervisor } : {}),
|
|
492
|
-
...(supervisorOwnerToken ? { supervisorOwnerToken } : {}),
|
|
493
|
-
});
|
|
494
|
-
} catch (error) {
|
|
495
|
-
cleanupConnectionAttempt();
|
|
496
|
-
cleanupSocketListeners();
|
|
497
|
-
if (this.socket === socket) {
|
|
498
|
-
this.socket = null;
|
|
499
|
-
}
|
|
500
|
-
socket.destroy();
|
|
501
|
-
reject(toError(error));
|
|
502
|
-
}
|
|
591
|
+
// Register only once connected, and only if the attempt was not cancelled meanwhile (#3904).
|
|
592
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
593
|
+
socket.once("connect", onConnect);
|
|
503
594
|
});
|
|
504
595
|
}
|
|
505
596
|
|
|
@@ -523,7 +614,9 @@ export class IntercomClient extends EventEmitter {
|
|
|
523
614
|
|| (brokerMessage.acknowledgesReceipt !== undefined && brokerMessage.acknowledgesReceipt !== true)
|
|
524
615
|
|| (brokerMessage.acknowledgesPendingStageRoutes !== undefined && brokerMessage.acknowledgesPendingStageRoutes !== true)
|
|
525
616
|
|| (brokerMessage.refusesPendingStageRoutesInPlace !== undefined && brokerMessage.refusesPendingStageRoutesInPlace !== true)
|
|
526
|
-
|| (brokerMessage.brokerStatus !== undefined && brokerMessage.brokerStatus !== true)
|
|
617
|
+
|| (brokerMessage.brokerStatus !== undefined && brokerMessage.brokerStatus !== true)
|
|
618
|
+
|| (brokerMessage.claimsWorkflowInvocations !== undefined && brokerMessage.claimsWorkflowInvocations !== true)
|
|
619
|
+
|| (brokerMessage.extendsSaves !== undefined && brokerMessage.extendsSaves !== true)) {
|
|
527
620
|
throw new Error("Invalid registered message");
|
|
528
621
|
}
|
|
529
622
|
|
|
@@ -539,6 +632,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
539
632
|
this.brokerAcknowledgesPendingStageRoutes = brokerMessage.acknowledgesPendingStageRoutes === true;
|
|
540
633
|
this.brokerRefusesPendingStageRoutesInPlace = brokerMessage.refusesPendingStageRoutesInPlace === true;
|
|
541
634
|
this.brokerAnswersStatus = brokerMessage.brokerStatus === true;
|
|
635
|
+
this.brokerClaimsWorkflowInvocations = brokerMessage.claimsWorkflowInvocations === true;
|
|
636
|
+
this.brokerExtendsSaves = this.brokerAcknowledgesReceipt && brokerMessage.extendsSaves === true;
|
|
542
637
|
this.emit("_registered", { type: "registered", sessionId: brokerMessage.sessionId });
|
|
543
638
|
break;
|
|
544
639
|
}
|
|
@@ -661,7 +756,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
661
756
|
break;
|
|
662
757
|
}
|
|
663
758
|
case "pending_stage_message": {
|
|
664
|
-
const { requestId, from, senderRegistrationName, senderReturnAddress, runId, target, message, live } =
|
|
759
|
+
const { requestId, from, senderRegistrationName, senderReturnAddress, runId, target, message, live, invocationControl } =
|
|
760
|
+
brokerMessage;
|
|
665
761
|
if (
|
|
666
762
|
typeof requestId !== "string" ||
|
|
667
763
|
!isSessionInfo(from) ||
|
|
@@ -670,7 +766,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
670
766
|
typeof runId !== "string" ||
|
|
671
767
|
typeof target !== "string" ||
|
|
672
768
|
!isMessage(message) ||
|
|
673
|
-
(live !== undefined && typeof live !== "boolean")
|
|
769
|
+
(live !== undefined && typeof live !== "boolean") ||
|
|
770
|
+
(invocationControl !== undefined && invocationControl !== true)
|
|
674
771
|
) {
|
|
675
772
|
throw new Error("Invalid pending-stage message event");
|
|
676
773
|
}
|
|
@@ -683,6 +780,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
683
780
|
target,
|
|
684
781
|
message,
|
|
685
782
|
...(live === true ? { live: true } : {}),
|
|
783
|
+
...(invocationControl === true ? { invocationControl: true } : {}),
|
|
686
784
|
} satisfies PendingStageMessageRequest);
|
|
687
785
|
break;
|
|
688
786
|
}
|
|
@@ -753,6 +851,15 @@ export class IntercomClient extends EventEmitter {
|
|
|
753
851
|
pending.resolve();
|
|
754
852
|
break;
|
|
755
853
|
}
|
|
854
|
+
case "workflow_invocation_claimed": {
|
|
855
|
+
const { requestId, claimed } = brokerMessage;
|
|
856
|
+
if (typeof requestId !== "string" || typeof claimed !== "boolean") throw new Error("Invalid workflow invocation claim answer");
|
|
857
|
+
const pending = this.pendingWorkflowInvocationClaims.get(requestId);
|
|
858
|
+
if (!pending) return;
|
|
859
|
+
this.pendingWorkflowInvocationClaims.delete(requestId);
|
|
860
|
+
pending.resolve(claimed);
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
756
863
|
case "live_workflow_stage_route_registered": {
|
|
757
864
|
const { requestId } = brokerMessage;
|
|
758
865
|
if (typeof requestId !== "string") throw new Error("Invalid live workflow-stage route registration");
|
|
@@ -931,6 +1038,12 @@ export class IntercomClient extends EventEmitter {
|
|
|
931
1038
|
}
|
|
932
1039
|
}
|
|
933
1040
|
async disconnect(): Promise<void> {
|
|
1041
|
+
// A connect still in progress (or waiting to retry) is cancelled: it closes any socket it opened and never
|
|
1042
|
+
// registers (#3904).
|
|
1043
|
+
if (this.connectAttempt !== undefined && this._sessionId === null) {
|
|
1044
|
+
this.connectAttempt.abort();
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
934
1047
|
const socket = this.socket;
|
|
935
1048
|
if (!socket) {
|
|
936
1049
|
return;
|
|
@@ -1194,6 +1307,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
1194
1307
|
possibleStages?: WorkflowPossibleStageAnnouncement[],
|
|
1195
1308
|
parent?: WorkflowRunParentAnnouncement,
|
|
1196
1309
|
dormant?: boolean,
|
|
1310
|
+
launcherCapability?: string,
|
|
1197
1311
|
): void {
|
|
1198
1312
|
writeMessage(this.requireActiveSocket(), {
|
|
1199
1313
|
type: "register_pending_stage_route",
|
|
@@ -1204,6 +1318,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
1204
1318
|
possibleStages,
|
|
1205
1319
|
...(parent === undefined ? {} : { parent }),
|
|
1206
1320
|
...(dormant === true ? { dormant: true as const } : {}),
|
|
1321
|
+
...(launcherCapability === undefined || !this.brokerClaimsWorkflowInvocations ? {} : { launcherCapability }),
|
|
1207
1322
|
});
|
|
1208
1323
|
}
|
|
1209
1324
|
|
|
@@ -1220,6 +1335,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
1220
1335
|
possibleStages?: WorkflowPossibleStageAnnouncement[],
|
|
1221
1336
|
parent?: WorkflowRunParentAnnouncement,
|
|
1222
1337
|
dormant?: boolean,
|
|
1338
|
+
/** #4006: the launcher-only secret, held by the process that launched the run and never by its stages. */
|
|
1339
|
+
launcherCapability?: string,
|
|
1223
1340
|
): Promise<void> {
|
|
1224
1341
|
let socket: net.Socket;
|
|
1225
1342
|
try {
|
|
@@ -1229,7 +1346,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
1229
1346
|
}
|
|
1230
1347
|
if (!this.brokerAcknowledgesPendingStageRoutes) {
|
|
1231
1348
|
try {
|
|
1232
|
-
this.registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent, dormant);
|
|
1349
|
+
this.registerPendingStageRoute(runId, group, capability, stages, possibleStages, parent, dormant, launcherCapability);
|
|
1233
1350
|
} catch (error) {
|
|
1234
1351
|
return Promise.reject(toError(error));
|
|
1235
1352
|
}
|
|
@@ -1262,6 +1379,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
1262
1379
|
possibleStages,
|
|
1263
1380
|
...(parent === undefined ? {} : { parent }),
|
|
1264
1381
|
...(dormant === true ? { dormant: true as const } : {}),
|
|
1382
|
+
...(launcherCapability === undefined || !this.brokerClaimsWorkflowInvocations ? {} : { launcherCapability }),
|
|
1265
1383
|
...(this.multiplexesPendingStageRoutes && this.brokerRefusesPendingStageRoutesInPlace
|
|
1266
1384
|
? { refusalKeepsConnection: true as const }
|
|
1267
1385
|
: {}),
|
|
@@ -1274,6 +1392,31 @@ export class IntercomClient extends EventEmitter {
|
|
|
1274
1392
|
});
|
|
1275
1393
|
}
|
|
1276
1394
|
|
|
1395
|
+
/**
|
|
1396
|
+
* #4006: prove with the run's launcher capability (registered with the run's route, never given to its
|
|
1397
|
+
* stages) that this session launched `runId`, so it may send to the run's stages without joining
|
|
1398
|
+
* `workflow:<rootRunId>`. Resolves `false` when the broker refused the claim or predates it.
|
|
1399
|
+
*/
|
|
1400
|
+
claimWorkflowInvocation(runId: string, launcherCapability: string): Promise<boolean> {
|
|
1401
|
+
let socket: net.Socket;
|
|
1402
|
+
try {
|
|
1403
|
+
socket = this.requireActiveSocket();
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
return Promise.reject(toError(error));
|
|
1406
|
+
}
|
|
1407
|
+
if (!this.brokerClaimsWorkflowInvocations) return Promise.resolve(false);
|
|
1408
|
+
const requestId = randomUUID();
|
|
1409
|
+
return new Promise((resolve, reject) => {
|
|
1410
|
+
this.pendingWorkflowInvocationClaims.set(requestId, { resolve, reject });
|
|
1411
|
+
try {
|
|
1412
|
+
writeMessage(socket, { type: "claim_workflow_invocation", requestId, runId, capability: launcherCapability });
|
|
1413
|
+
} catch (error) {
|
|
1414
|
+
this.pendingWorkflowInvocationClaims.delete(requestId);
|
|
1415
|
+
reject(toError(error));
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1277
1420
|
registerLiveWorkflowStageRoute(runId: string, stageKeys: readonly string[], capability: string): Promise<void> {
|
|
1278
1421
|
let socket: net.Socket;
|
|
1279
1422
|
try {
|
|
@@ -1343,6 +1486,15 @@ export class IntercomClient extends EventEmitter {
|
|
|
1343
1486
|
writeMessage(this.requireActiveSocket(), { type: "received", messageId });
|
|
1344
1487
|
}
|
|
1345
1488
|
|
|
1489
|
+
/**
|
|
1490
|
+
* #3983: tell the broker this message is still being saved, so its sender keeps waiting instead of hearing the
|
|
1491
|
+
* outcome is uncertain. A no-op on a broker that did not advertise `extendsSaves`, or while disconnected.
|
|
1492
|
+
*/
|
|
1493
|
+
reportSaving(messageId: string): void {
|
|
1494
|
+
if (!this.brokerExtendsSaves || !this.socket || this.socket.destroyed) return;
|
|
1495
|
+
writeMessage(this.socket, { type: "saving", messageId });
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1346
1498
|
sendPendingStageNotification(
|
|
1347
1499
|
runId: string,
|
|
1348
1500
|
capability: string,
|