@bastani/atomic 0.9.57 → 0.9.58-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 +52 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +12 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +39 -5
- package/dist/builtin/web-access/CHANGELOG.md +12 -0
- package/dist/builtin/web-access/index.bundle.mjs +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +42 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +885 -228
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/index.js +630 -162
- package/dist/builtin/workflows/src/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +1 -1
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +13 -0
- package/dist/builtin/workflows/src/workers/public-options.d.ts +10 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts +5 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +16 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +20 -0
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +4 -0
- package/dist/core/settings-defaults.d.ts.map +1 -1
- package/dist/core/settings-defaults.js +4 -0
- package/dist/core/settings-defaults.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +2 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +6 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-schema.d.ts +9 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +11 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/tasks/agent-adapter.d.ts +10 -1
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -1
- package/dist/core/tasks/agent-adapter.js +20 -0
- package/dist/core/tasks/agent-adapter.js.map +1 -1
- package/dist/core/tasks/contracts.d.ts +6 -0
- package/dist/core/tasks/contracts.d.ts.map +1 -1
- package/dist/core/tasks/contracts.js.map +1 -1
- package/dist/core/tasks/heartbeat-notice.d.ts +64 -0
- package/dist/core/tasks/heartbeat-notice.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat-notice.js +98 -0
- package/dist/core/tasks/heartbeat-notice.js.map +1 -0
- package/dist/core/tasks/heartbeat.d.ts +75 -0
- package/dist/core/tasks/heartbeat.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat.js +440 -0
- package/dist/core/tasks/heartbeat.js.map +1 -0
- package/dist/core/tasks/supervisor.d.ts +2 -0
- package/dist/core/tasks/supervisor.d.ts.map +1 -1
- package/dist/core/tasks/supervisor.js +32 -4
- package/dist/core/tasks/supervisor.js.map +1 -1
- package/dist/core/tasks/task-view-source.d.ts +72 -0
- package/dist/core/tasks/task-view-source.d.ts.map +1 -0
- package/dist/core/tasks/task-view-source.js +155 -0
- package/dist/core/tasks/task-view-source.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +2 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.js +1 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -1
- package/dist/core/tools/bash.d.ts +3 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +16 -8
- package/dist/core/tools/powershell.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +7 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +4 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.d.ts +11 -0
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +15 -8
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +12 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/task-detail.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-detail.js +5 -0
- package/dist/modes/interactive/components/task-detail.js.map +1 -1
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts +14 -0
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js +76 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js.map +1 -0
- package/dist/modes/interactive/components/task-inspector.d.ts +6 -3
- package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-inspector.js +53 -100
- package/dist/modes/interactive/components/task-inspector.js.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.d.ts +22 -2
- package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.js +28 -9
- package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -1
- package/docs/background-tasks.md +65 -1
- package/docs/settings.md +12 -0
- package/docs/subagents.md +2 -0
- package/docs/tools.md +2 -1
- package/docs/workflows/operations.md +5 -3
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +24 -0
|
@@ -2050,7 +2050,7 @@ class JournalDurableBackend {
|
|
|
2050
2050
|
timer;
|
|
2051
2051
|
state = "open";
|
|
2052
2052
|
closing;
|
|
2053
|
-
renewing;
|
|
2053
|
+
renewing = new Map;
|
|
2054
2054
|
mutationContext = new AsyncLocalStorage;
|
|
2055
2055
|
processExitCleanup;
|
|
2056
2056
|
unregisterExecutionStorages = registerExecutionStorages(this.executionContext, this.mutationContext);
|
|
@@ -2771,27 +2771,21 @@ class JournalDurableBackend {
|
|
|
2771
2771
|
yield this.enqueue(runId, () => this.deleteOwned(runId));
|
|
2772
2772
|
}
|
|
2773
2773
|
renewLeases() {
|
|
2774
|
-
if (this.renewing !== undefined)
|
|
2775
|
-
return this.renewing;
|
|
2776
2774
|
if (this.state !== "open")
|
|
2777
2775
|
return Promise.resolve();
|
|
2778
|
-
this.renewing = this.renewOwnedLeases().finally(() => {
|
|
2779
|
-
this.renewing = undefined;
|
|
2780
|
-
});
|
|
2781
|
-
return this.renewing;
|
|
2782
|
-
}
|
|
2783
|
-
async renewOwnedLeases() {
|
|
2784
2776
|
for (const [runId, lease] of this.leases) {
|
|
2785
|
-
if (this.
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
} catch (error) {
|
|
2790
|
-
if (error instanceof Error)
|
|
2791
|
-
this.lost.set(runId, error);
|
|
2777
|
+
if (this.renewing.has(runId))
|
|
2778
|
+
continue;
|
|
2779
|
+
const renewal = this.serialize(runId, () => this.renewLease(runId, lease), false).catch((error) => {
|
|
2780
|
+
this.lost.set(runId, error);
|
|
2792
2781
|
this.dropLease(runId);
|
|
2793
|
-
}
|
|
2782
|
+
}).finally(() => {
|
|
2783
|
+
if (this.renewing.get(runId) === renewal)
|
|
2784
|
+
this.renewing.delete(runId);
|
|
2785
|
+
});
|
|
2786
|
+
this.renewing.set(runId, renewal);
|
|
2794
2787
|
}
|
|
2788
|
+
return Promise.all(this.renewing.values()).then(() => {});
|
|
2795
2789
|
}
|
|
2796
2790
|
*renewLease(runId, lease) {
|
|
2797
2791
|
if (this.leases.get(runId) !== lease || this.lost.has(runId))
|
|
@@ -2799,9 +2793,10 @@ class JournalDurableBackend {
|
|
|
2799
2793
|
try {
|
|
2800
2794
|
yield* invoke(() => this.journal.renew(lease));
|
|
2801
2795
|
} catch (error) {
|
|
2796
|
+
if (!(error instanceof StaleLeaseError))
|
|
2797
|
+
return;
|
|
2802
2798
|
if (this.leases.get(runId) === lease) {
|
|
2803
|
-
|
|
2804
|
-
this.lost.set(runId, yield* this.mapOwnership(error, runId));
|
|
2799
|
+
this.lost.set(runId, yield* this.mapOwnership(error, runId));
|
|
2805
2800
|
this.dropLease(runId);
|
|
2806
2801
|
}
|
|
2807
2802
|
}
|
|
@@ -2895,7 +2890,7 @@ class JournalDurableBackend {
|
|
|
2895
2890
|
}
|
|
2896
2891
|
async drainAndClose() {
|
|
2897
2892
|
try {
|
|
2898
|
-
await this.renewing;
|
|
2893
|
+
await Promise.all(this.renewing.values());
|
|
2899
2894
|
while (this.pending.size > 0)
|
|
2900
2895
|
await Promise.all(this.pending.values());
|
|
2901
2896
|
for (const runId of this.leases.keys())
|
|
@@ -5102,6 +5097,75 @@ function redactSensitiveText(value2) {
|
|
|
5102
5097
|
return value2.replace(/(sk-[A-Za-z0-9_-]{8})[A-Za-z0-9_-]+/g, redactedSecretReplacement("$1")).replace(/\b(authorization\s*:\s*bearer\s+)[^\s,;]+/gi, "$1[redacted]").replace(/\b(bearer\s+)[A-Za-z0-9._~+/-]{8,}=*/gi, "$1[redacted]").replace(/((?:api[_-]?key|token|credential|secret)\s*[:=]\s*)[^\s,;]+/gi, "$1[redacted]");
|
|
5103
5098
|
}
|
|
5104
5099
|
|
|
5100
|
+
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
5101
|
+
function isInfrastructureError(value2) {
|
|
5102
|
+
if (value2 instanceof WorkflowInfrastructureError)
|
|
5103
|
+
return true;
|
|
5104
|
+
if (typeof value2 !== "object" || value2 === null)
|
|
5105
|
+
return false;
|
|
5106
|
+
const candidate = value2;
|
|
5107
|
+
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
5108
|
+
}
|
|
5109
|
+
function isRetryableWorkflowError(error) {
|
|
5110
|
+
let current = error;
|
|
5111
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
|
|
5112
|
+
if (isInfrastructureError(current))
|
|
5113
|
+
return true;
|
|
5114
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
5115
|
+
}
|
|
5116
|
+
return false;
|
|
5117
|
+
}
|
|
5118
|
+
function workflowInfrastructureFault(message) {
|
|
5119
|
+
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
5120
|
+
}
|
|
5121
|
+
function asWorkflowInfrastructureError(error) {
|
|
5122
|
+
if (isInfrastructureError(error))
|
|
5123
|
+
return error;
|
|
5124
|
+
if (!(error instanceof Error))
|
|
5125
|
+
return;
|
|
5126
|
+
const code = workflowInfrastructureFault(error.message);
|
|
5127
|
+
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
5128
|
+
}
|
|
5129
|
+
function failedOnInfrastructureFault(result) {
|
|
5130
|
+
if (result.status !== "failed")
|
|
5131
|
+
return false;
|
|
5132
|
+
const names = (value2) => typeof value2 === "string" && (WORKFLOW_INFRASTRUCTURE_FAULTS.has(value2) || workflowInfrastructureFault(value2) !== undefined);
|
|
5133
|
+
const failure = result.failure;
|
|
5134
|
+
if (names(failure?.code) || names(result.error))
|
|
5135
|
+
return true;
|
|
5136
|
+
return Array.isArray(result.stages) && result.stages.some((stage) => stage?.status === "failed" && (names(stage.failureCode) || names(stage.error)));
|
|
5137
|
+
}
|
|
5138
|
+
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", WORKFLOW_INFRASTRUCTURE_FAULTS, MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
5139
|
+
var init_workflow_infrastructure_error = __esm(() => {
|
|
5140
|
+
WORKFLOW_INFRASTRUCTURE_FAULTS = new Set([
|
|
5141
|
+
"worker_lost",
|
|
5142
|
+
"worker_cleanup_unconfirmed",
|
|
5143
|
+
"worker_retry_limit",
|
|
5144
|
+
"worker_startup_failed",
|
|
5145
|
+
"stale_work_lease",
|
|
5146
|
+
"intercom_unavailable",
|
|
5147
|
+
"storage_unavailable"
|
|
5148
|
+
]);
|
|
5149
|
+
FAULT_PATTERNS = [
|
|
5150
|
+
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
5151
|
+
[/Local worker retry limit/, "worker_retry_limit"],
|
|
5152
|
+
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
5153
|
+
[/Worker exited before delivery acknowledgement|Local worker pool coordinator exited/, "worker_lost"],
|
|
5154
|
+
[/Stale work lease|Stale resource admission attempt/, "stale_work_lease"],
|
|
5155
|
+
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
5156
|
+
[/Storage unavailable/, "storage_unavailable"]
|
|
5157
|
+
];
|
|
5158
|
+
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
5159
|
+
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
5160
|
+
retryable = true;
|
|
5161
|
+
code;
|
|
5162
|
+
constructor(code, message, options) {
|
|
5163
|
+
super(message, options);
|
|
5164
|
+
this.code = code;
|
|
5165
|
+
}
|
|
5166
|
+
};
|
|
5167
|
+
});
|
|
5168
|
+
|
|
5105
5169
|
// dist/builtin/workflows/src/shared/workflow-failures-decisions.ts
|
|
5106
5170
|
function authDecision(code) {
|
|
5107
5171
|
if (code === "invalid_api_key") {
|
|
@@ -5190,6 +5254,16 @@ function cancelledDecision() {
|
|
|
5190
5254
|
disposition: "terminal_killed"
|
|
5191
5255
|
};
|
|
5192
5256
|
}
|
|
5257
|
+
function infrastructureFaultDecision(code) {
|
|
5258
|
+
return {
|
|
5259
|
+
kind: "unknown",
|
|
5260
|
+
code,
|
|
5261
|
+
retryable: true,
|
|
5262
|
+
resumable: true,
|
|
5263
|
+
recoverability: "recoverable",
|
|
5264
|
+
disposition: "terminal_failed"
|
|
5265
|
+
};
|
|
5266
|
+
}
|
|
5193
5267
|
function unknownDecision() {
|
|
5194
5268
|
return {
|
|
5195
5269
|
kind: "unknown",
|
|
@@ -5217,6 +5291,8 @@ function strongDecisionFromNormalizedCode(normalized, retryAfterMs) {
|
|
|
5217
5291
|
disposition: "active_blocked"
|
|
5218
5292
|
};
|
|
5219
5293
|
}
|
|
5294
|
+
if (WORKFLOW_INFRASTRUCTURE_FAULTS.has(normalized))
|
|
5295
|
+
return infrastructureFaultDecision(normalized);
|
|
5220
5296
|
if (CANCELLED_CODES.has(normalized))
|
|
5221
5297
|
return cancelledDecision();
|
|
5222
5298
|
if (INVALID_API_KEY_CODES.has(normalized))
|
|
@@ -5329,6 +5405,9 @@ function classificationFromNormalizedCode(normalized, retryAfterMs, source, mess
|
|
|
5329
5405
|
return weak !== undefined ? { weak: classificationForDecision(weak, source, message, "weak_signal") } : {};
|
|
5330
5406
|
}
|
|
5331
5407
|
function fallbackDecisionFromMessage(message, name) {
|
|
5408
|
+
const fault = workflowInfrastructureFault(message);
|
|
5409
|
+
if (fault !== undefined)
|
|
5410
|
+
return infrastructureFaultDecision(fault);
|
|
5332
5411
|
const tokens = tokenize(message);
|
|
5333
5412
|
const decision = decisionFromMessageTokens(tokens, name);
|
|
5334
5413
|
const providerAuthDecision = classifyFallbackProviderAuthMessage(message, tokens);
|
|
@@ -5343,6 +5422,7 @@ function fallbackDecisionFromMessage(message, name) {
|
|
|
5343
5422
|
var INVALID_API_KEY_CODES, LOGIN_REQUIRED_CODES, MISSING_API_KEY_CODES, RATE_LIMIT_CODES, QUOTA_LIMIT_CODES, CANCELLED_CODES, PROVIDER_UNAVAILABLE_CODES, UNKNOWN_MODEL_CODES, FORBIDDEN_CONFIG_CODES, REQUEST_AUTH_TIMEOUT_PHRASES, LOGIN_REQUIRED_PHRASES, LOCAL_LOGIN_REQUIRED_PHRASES, PROVIDER_AUTH_FALLBACK_PHRASES, MISSING_API_KEY_PHRASES, INVALID_API_KEY_PHRASES, INVALID_API_KEY_CONTEXT, HTTP_RATE_LIMIT_PHRASES, RATE_LIMIT_PHRASES, QUOTA_LIMIT_PHRASES, CANCELLED_PHRASES, UNKNOWN_MODEL_PHRASES, FORBIDDEN_CONFIG_PHRASES, PROVIDER_UNAVAILABLE_PHRASES, AUTH_CONTEXT, MODEL_PROVIDER_CONTEXT, PROVIDER_CONTEXT, STATUS_MESSAGE_REFINEMENT_CODES, BROAD_AUTH_MESSAGE_REFINEMENT_CODES, STATUS_RELATED_MESSAGE_REFINEMENT_CODES;
|
|
5344
5423
|
var init_workflow_failures_decisions = __esm(() => {
|
|
5345
5424
|
init_workflow_failures_contract();
|
|
5425
|
+
init_workflow_infrastructure_error();
|
|
5346
5426
|
INVALID_API_KEY_CODES = new Set([
|
|
5347
5427
|
"401",
|
|
5348
5428
|
"invalid_api_key",
|
|
@@ -5530,6 +5610,13 @@ function decisionOfRecordedCode(code, retryAfterMs) {
|
|
|
5530
5610
|
case "cancelled":
|
|
5531
5611
|
return cancelledDecision();
|
|
5532
5612
|
case "pending_stage_delivery_failed":
|
|
5613
|
+
case "worker_lost":
|
|
5614
|
+
case "worker_cleanup_unconfirmed":
|
|
5615
|
+
case "worker_retry_limit":
|
|
5616
|
+
case "worker_startup_failed":
|
|
5617
|
+
case "stale_work_lease":
|
|
5618
|
+
case "intercom_unavailable":
|
|
5619
|
+
case "storage_unavailable":
|
|
5533
5620
|
return strongDecisionFromNormalizedCode(code, retryAfterMs);
|
|
5534
5621
|
case "unknown":
|
|
5535
5622
|
return;
|
|
@@ -16906,7 +16993,7 @@ class SqlResourceAdmission {
|
|
|
16906
16993
|
for (const value2 of Object.values(limits ?? {}))
|
|
16907
16994
|
if (!Number.isSafeInteger(value2) || value2 < 1)
|
|
16908
16995
|
throw new Error("Invalid resource limit");
|
|
16909
|
-
for (const value2 of Object.values(options.host ?? {}))
|
|
16996
|
+
for (const value2 of [...Object.values(options.host ?? {}), options.stageStartMaxLoadPerCpu ?? 0])
|
|
16910
16997
|
if (!Number.isFinite(value2) || value2 < 0)
|
|
16911
16998
|
throw new Error("Invalid host admission threshold");
|
|
16912
16999
|
const admission = new SqlResourceAdmission(storage, {
|
|
@@ -16924,6 +17011,8 @@ class SqlResourceAdmission {
|
|
|
16924
17011
|
for (const column of ["owner", "attempt", "process_identity"])
|
|
16925
17012
|
if (!columns.some((entry) => entry.name === column))
|
|
16926
17013
|
await tx.exec(`ALTER TABLE ${admission.permits} ADD COLUMN ${column} TEXT`);
|
|
17014
|
+
if (!columns.some((entry) => entry.name === "granted_at"))
|
|
17015
|
+
await tx.exec(`ALTER TABLE ${admission.permits} ADD COLUMN granted_at INTEGER`);
|
|
16927
17016
|
await tx.exec(`CREATE INDEX IF NOT EXISTS ${admission.permits}_owner ON ${admission.permits}(owner, state);
|
|
16928
17017
|
CREATE INDEX IF NOT EXISTS ${admission.permits}_state ON ${admission.permits}(state)`);
|
|
16929
17018
|
if (!(await tx.all(`PRAGMA table_info(${admission.owners})`)).some((entry) => entry.name === "boot"))
|
|
@@ -16953,14 +17042,24 @@ class SqlResourceAdmission {
|
|
|
16953
17042
|
await admission.reconcile();
|
|
16954
17043
|
return admission;
|
|
16955
17044
|
}
|
|
17045
|
+
sampleHost() {
|
|
17046
|
+
return this.options.sampleHost?.() ?? {
|
|
17047
|
+
freeMemoryBytes: freemem(),
|
|
17048
|
+
load: process.platform === "win32" ? undefined : loadavg()[0] / cpus().length
|
|
17049
|
+
};
|
|
17050
|
+
}
|
|
17051
|
+
stageStartPressure(kind, delegated) {
|
|
17052
|
+
const threshold = this.options.stageStartMaxLoadPerCpu;
|
|
17053
|
+
if (kind !== "session" || delegated === true || threshold === undefined || threshold === 0)
|
|
17054
|
+
return false;
|
|
17055
|
+
const load = this.sampleHost().load;
|
|
17056
|
+
return load !== undefined && load > threshold;
|
|
17057
|
+
}
|
|
16956
17058
|
hostReason() {
|
|
16957
17059
|
const host = this.options.host;
|
|
16958
17060
|
if (!host)
|
|
16959
17061
|
return;
|
|
16960
|
-
const sample = this.
|
|
16961
|
-
freeMemoryBytes: freemem(),
|
|
16962
|
-
load: process.platform === "win32" ? undefined : loadavg()[0] / cpus().length
|
|
16963
|
-
};
|
|
17062
|
+
const sample = this.sampleHost();
|
|
16964
17063
|
if (host.minFreeMemoryBytes !== undefined) {
|
|
16965
17064
|
if (sample.freeMemoryBytes === undefined)
|
|
16966
17065
|
return "host memory unsupported";
|
|
@@ -16974,21 +17073,32 @@ class SqlResourceAdmission {
|
|
|
16974
17073
|
return "host load";
|
|
16975
17074
|
}
|
|
16976
17075
|
}
|
|
16977
|
-
async
|
|
17076
|
+
async attemptStanding(tx) {
|
|
16978
17077
|
const { root, attempt } = this.options;
|
|
16979
17078
|
if (!attempt)
|
|
16980
|
-
return;
|
|
16981
|
-
const work = await tx.get(`SELECT
|
|
17079
|
+
return "current";
|
|
17080
|
+
const work = await tx.get(`SELECT (w.expires_at < ${NOW_MS} OR l.renewed_at + p.timeout < ${NOW_MS}) AS late
|
|
17081
|
+
FROM ${this.storage.tables.runs}_work w JOIN ${this.storage.tables.leases} l ON l.run_id = w.root
|
|
16982
17082
|
JOIN ${this.storage.tables.runs}_pool p ON p.root = w.root JOIN ${this.storage.tables.runs} r ON r.run_id = w.root
|
|
16983
17083
|
WHERE w.id = ? AND w.root = ? AND w.generation = ? AND w.epoch = ? AND w.state = 'leased' AND r.status IN ('running', 'paused')
|
|
16984
|
-
AND
|
|
16985
|
-
AND l.epoch = w.epoch AND l.renewed_at + p.timeout >= CAST(unixepoch('subsec') * 1000 AS INTEGER)`, attempt.id, root, attempt.generation, attempt.epoch);
|
|
17084
|
+
AND l.epoch = w.epoch`, attempt.id, root, attempt.generation, attempt.epoch);
|
|
16986
17085
|
if (!work)
|
|
17086
|
+
return "stale";
|
|
17087
|
+
return Number(work.late) === 1 ? "late" : "current";
|
|
17088
|
+
}
|
|
17089
|
+
async assertCurrentAttempt(tx) {
|
|
17090
|
+
const standing = await this.attemptStanding(tx);
|
|
17091
|
+
if (standing === "stale")
|
|
16987
17092
|
throw new Error("Stale resource admission attempt");
|
|
17093
|
+
return standing === "current";
|
|
16988
17094
|
}
|
|
16989
17095
|
async validate(signal) {
|
|
16990
|
-
|
|
16991
|
-
|
|
17096
|
+
for (;; ) {
|
|
17097
|
+
signal?.throwIfAborted();
|
|
17098
|
+
if (await this.storage.transaction((tx) => this.assertCurrentAttempt(tx)))
|
|
17099
|
+
return;
|
|
17100
|
+
await delay(LATE_ATTEMPT_POLL_MS, undefined, { signal });
|
|
17101
|
+
}
|
|
16992
17102
|
}
|
|
16993
17103
|
async acquire(kind, signal, request) {
|
|
16994
17104
|
signal?.throwIfAborted();
|
|
@@ -17022,11 +17132,19 @@ class SqlResourceAdmission {
|
|
|
17022
17132
|
this.nextReconciliation = performance.now() + 1000;
|
|
17023
17133
|
}
|
|
17024
17134
|
const hostReason = this.hostReason();
|
|
17135
|
+
const pressure = this.stageStartPressure(kind, request?.delegated);
|
|
17025
17136
|
const granted = await this.storage.transaction(async (tx) => {
|
|
17026
17137
|
await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
|
|
17027
17138
|
const { root } = this.options;
|
|
17028
|
-
await this.assertCurrentAttempt(tx)
|
|
17139
|
+
if (!await this.assertCurrentAttempt(tx)) {
|
|
17140
|
+
const waiting = await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE operation = ? AND state = 'waiting'`, LATE_ATTEMPT_REASON, operation);
|
|
17141
|
+
if (waiting.changes !== 1)
|
|
17142
|
+
throw new Error("Resource admission holder was stopped");
|
|
17143
|
+
return false;
|
|
17144
|
+
}
|
|
17029
17145
|
let reason = hostReason;
|
|
17146
|
+
if (pressure && (await tx.get(`SELECT 1 AS recent FROM ${this.permits} WHERE root = ? AND kind = 'session' AND granted_at >= ${NOW_MS} - ? LIMIT 1`, root, STAGE_START_SPACING_MS) || await tx.get(`SELECT 1 AS older FROM ${this.permits} WHERE root = ? AND kind = 'session' AND state = 'waiting' AND reason = ? AND ticket < (SELECT ticket FROM ${this.permits} WHERE operation = ?) LIMIT 1`, root, STAGE_START_PRESSURE_REASON, operation)))
|
|
17147
|
+
reason ??= STAGE_START_PRESSURE_REASON;
|
|
17030
17148
|
const controls = `${this.storage.tables.runs}_pool_control`;
|
|
17031
17149
|
if (await tx.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?", controls)) {
|
|
17032
17150
|
const control = await tx.get(`SELECT state FROM ${controls} WHERE root = ?`, root);
|
|
@@ -17041,13 +17159,14 @@ class SqlResourceAdmission {
|
|
|
17041
17159
|
const rootClause = scope === "user" ? "" : "AND root = ?";
|
|
17042
17160
|
const args = scope === "user" ? [kind] : [kind, root];
|
|
17043
17161
|
const count = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted'`, ...args);
|
|
17044
|
-
const older = await tx.get(`SELECT 1 AS waiting FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'waiting' AND ticket < (SELECT ticket FROM ${this.permits} WHERE operation = ?) LIMIT 1`, ...args, operation);
|
|
17162
|
+
const older = await tx.get(`SELECT 1 AS waiting FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'waiting' AND reason IS NOT ? AND ticket < (SELECT ticket FROM ${this.permits} WHERE operation = ?) LIMIT 1`, ...args, STAGE_START_PRESSURE_REASON, operation);
|
|
17045
17163
|
if (Number(count?.count) >= limit || older)
|
|
17046
17164
|
reason ??= `${scope} ${kind}`;
|
|
17047
17165
|
}
|
|
17048
17166
|
if (reason && request?.delegated)
|
|
17049
17167
|
throw new Error(`Delegated session cannot be admitted without capacity headroom: ${reason}`);
|
|
17050
|
-
const
|
|
17168
|
+
const stageStart = kind === "session" && request?.delegated !== true;
|
|
17169
|
+
const updated = await tx.run(`UPDATE ${this.permits} SET state = ?, reason = ?, granted_at = CASE WHEN ? IS NULL AND ? THEN ${NOW_MS} ELSE NULL END WHERE operation = ? AND state = 'waiting'`, reason ? "waiting" : "granted", reason ?? null, reason ?? null, stageStart ? 1 : 0, operation);
|
|
17051
17170
|
if (updated.changes !== 1)
|
|
17052
17171
|
throw new Error("Resource admission holder was stopped");
|
|
17053
17172
|
return !reason;
|
|
@@ -17207,7 +17326,7 @@ async function reapProcessGroups(journal, root, scope) {
|
|
|
17207
17326
|
return { survivors: [], unprobeable: [] };
|
|
17208
17327
|
return settleProcessGroups(storage, root, scope, true);
|
|
17209
17328
|
}
|
|
17210
|
-
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)";
|
|
17329
|
+
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
|
|
17211
17330
|
var init_resource_admission = __esm(() => {
|
|
17212
17331
|
init_internal();
|
|
17213
17332
|
init_sql_run_journal();
|
|
@@ -59780,14 +59899,23 @@ class SqlPoolQueue {
|
|
|
59780
59899
|
}
|
|
59781
59900
|
await tx.run(`UPDATE ${this.meta} SET version = ?`, POOL_SCHEMA_VERSION);
|
|
59782
59901
|
}
|
|
59902
|
+
leaseRow(tx, lease) {
|
|
59903
|
+
return tx.get(`SELECT l.*, r.status, p.timeout, ${STORE_NOW2} AS now FROM ${this.journal.leases} l JOIN ${this.journal.runs} r ON r.run_id = l.run_id LEFT JOIN ${this.roots} p ON p.root = l.run_id WHERE l.run_id = ?`, lease.runId);
|
|
59904
|
+
}
|
|
59783
59905
|
async authority(tx, lease, timeout) {
|
|
59784
|
-
const row = await
|
|
59906
|
+
const row = await this.leaseRow(tx, lease);
|
|
59785
59907
|
if (row?.timeout === null && timeout === undefined)
|
|
59786
59908
|
throw new Error("Pool not initialized");
|
|
59787
59909
|
if (!row || row.epoch !== lease.epoch || row.holder_id !== lease.holderId || isWorkflowLeaseExpired(row.renewed_at, row.timeout ?? timeout ?? 0, row.now))
|
|
59788
59910
|
throw new StaleLeaseError(lease.runId, lease.epoch, Number(row?.epoch ?? 0));
|
|
59789
59911
|
return row;
|
|
59790
59912
|
}
|
|
59913
|
+
async rootLease(lease, timeout) {
|
|
59914
|
+
const row = await this.storage.read((executor) => this.leaseRow(executor, lease));
|
|
59915
|
+
if (!row || row.epoch !== lease.epoch || row.holder_id !== lease.holderId)
|
|
59916
|
+
return "lost";
|
|
59917
|
+
return isWorkflowLeaseExpired(row.renewed_at, row.timeout ?? timeout, row.now) ? "late" : "current";
|
|
59918
|
+
}
|
|
59791
59919
|
async initialize(lease, coordinatorTimeoutMs) {
|
|
59792
59920
|
positive(coordinatorTimeoutMs);
|
|
59793
59921
|
lease = snapshotLease(lease);
|
|
@@ -59799,6 +59927,9 @@ class SqlPoolQueue {
|
|
|
59799
59927
|
throw new Error("Pool configuration is immutable");
|
|
59800
59928
|
});
|
|
59801
59929
|
}
|
|
59930
|
+
async initialized(root) {
|
|
59931
|
+
return await this.storage.read((executor) => executor.get(`SELECT 1 AS held FROM ${this.roots} WHERE root = ?`, root)) !== undefined;
|
|
59932
|
+
}
|
|
59802
59933
|
async control(lease) {
|
|
59803
59934
|
return this.transaction(async (tx) => {
|
|
59804
59935
|
await this.authority(tx, lease);
|
|
@@ -60193,6 +60324,21 @@ class SqlPoolQueue {
|
|
|
60193
60324
|
return row ? JSON.parse(String(row.result)) : undefined;
|
|
60194
60325
|
});
|
|
60195
60326
|
}
|
|
60327
|
+
async reopenCompleted(lease, id, rerun) {
|
|
60328
|
+
lease = snapshotLease(lease);
|
|
60329
|
+
return this.transaction(async (tx) => {
|
|
60330
|
+
await this.authority(tx, lease);
|
|
60331
|
+
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, id, lease.runId);
|
|
60332
|
+
if (row?.state !== "completed" || row.epoch >= lease.epoch)
|
|
60333
|
+
return;
|
|
60334
|
+
const stored = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, id);
|
|
60335
|
+
if (!stored || !rerun(JSON.parse(String(stored.result))))
|
|
60336
|
+
return;
|
|
60337
|
+
await tx.run(`DELETE FROM ${this.work}_results WHERE work = ?`, id);
|
|
60338
|
+
await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0, epoch = ? WHERE id = ?`, lease.epoch, id);
|
|
60339
|
+
return fromRow({ ...row, state: "ready", worker: null, expires_at: 0, epoch: lease.epoch });
|
|
60340
|
+
});
|
|
60341
|
+
}
|
|
60196
60342
|
async expire(lease, token) {
|
|
60197
60343
|
lease = snapshotLease(lease);
|
|
60198
60344
|
token = { ...token };
|
|
@@ -60314,7 +60460,7 @@ function reportsClosedSession(error) {
|
|
|
60314
60460
|
}
|
|
60315
60461
|
function isSessionClosedError(error) {
|
|
60316
60462
|
let current = error;
|
|
60317
|
-
for (let depth = 0;depth <
|
|
60463
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined; depth++) {
|
|
60318
60464
|
try {
|
|
60319
60465
|
if (reportsClosedSession(current))
|
|
60320
60466
|
return true;
|
|
@@ -60325,7 +60471,7 @@ function isSessionClosedError(error) {
|
|
|
60325
60471
|
}
|
|
60326
60472
|
return false;
|
|
60327
60473
|
}
|
|
60328
|
-
var
|
|
60474
|
+
var MAX_CAUSE_DEPTH2 = 8;
|
|
60329
60475
|
var init_session_closed_error = () => {};
|
|
60330
60476
|
|
|
60331
60477
|
// dist/builtin/workflows/src/shared/external-run-routes.ts
|
|
@@ -64649,57 +64795,6 @@ var init_sdk_intercom = __esm(() => {
|
|
|
64649
64795
|
owners2 = new WeakMap;
|
|
64650
64796
|
});
|
|
64651
64797
|
|
|
64652
|
-
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
64653
|
-
function isInfrastructureError(value2) {
|
|
64654
|
-
if (value2 instanceof WorkflowInfrastructureError)
|
|
64655
|
-
return true;
|
|
64656
|
-
if (typeof value2 !== "object" || value2 === null)
|
|
64657
|
-
return false;
|
|
64658
|
-
const candidate = value2;
|
|
64659
|
-
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
64660
|
-
}
|
|
64661
|
-
function isRetryableWorkflowError(error) {
|
|
64662
|
-
let current = error;
|
|
64663
|
-
for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined && current !== null; depth++) {
|
|
64664
|
-
if (isInfrastructureError(current))
|
|
64665
|
-
return true;
|
|
64666
|
-
current = current instanceof Error ? current.cause : undefined;
|
|
64667
|
-
}
|
|
64668
|
-
return false;
|
|
64669
|
-
}
|
|
64670
|
-
function workflowInfrastructureFault(message) {
|
|
64671
|
-
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
64672
|
-
}
|
|
64673
|
-
function asWorkflowInfrastructureError(error) {
|
|
64674
|
-
if (isInfrastructureError(error))
|
|
64675
|
-
return error;
|
|
64676
|
-
if (!(error instanceof Error))
|
|
64677
|
-
return;
|
|
64678
|
-
const code = workflowInfrastructureFault(error.message);
|
|
64679
|
-
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
64680
|
-
}
|
|
64681
|
-
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH2 = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
64682
|
-
var init_workflow_infrastructure_error = __esm(() => {
|
|
64683
|
-
FAULT_PATTERNS = [
|
|
64684
|
-
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
64685
|
-
[/Local worker retry limit/, "worker_retry_limit"],
|
|
64686
|
-
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
64687
|
-
[/Worker exited before delivery acknowledgement|Local worker pool coordinator exited/, "worker_lost"],
|
|
64688
|
-
[/Stale work lease/, "stale_work_lease"],
|
|
64689
|
-
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
64690
|
-
[/Storage unavailable/, "storage_unavailable"]
|
|
64691
|
-
];
|
|
64692
|
-
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
64693
|
-
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
64694
|
-
retryable = true;
|
|
64695
|
-
code;
|
|
64696
|
-
constructor(code, message, options) {
|
|
64697
|
-
super(message, options);
|
|
64698
|
-
this.code = code;
|
|
64699
|
-
}
|
|
64700
|
-
};
|
|
64701
|
-
});
|
|
64702
|
-
|
|
64703
64798
|
// dist/builtin/workflows/src/workers/coordinator-protocol.ts
|
|
64704
64799
|
var POOL_COORDINATOR_ROLE = "pool-coordinator", POOL_SUMMARY_INTERVAL_MS = 250;
|
|
64705
64800
|
|
|
@@ -64983,6 +65078,16 @@ class RateLimitObservationOutbox {
|
|
|
64983
65078
|
}
|
|
64984
65079
|
var RATE_LIMIT_SHARE_INTERVAL_MS = 250;
|
|
64985
65080
|
|
|
65081
|
+
// dist/builtin/workflows/src/workers/stage-session-commands.ts
|
|
65082
|
+
function runsWhilePaused(command) {
|
|
65083
|
+
if (command.kind === "abort-bash" || command.kind === "abort-compaction")
|
|
65084
|
+
return true;
|
|
65085
|
+
if (command.kind !== "task")
|
|
65086
|
+
return false;
|
|
65087
|
+
const action = command.action.kind;
|
|
65088
|
+
return action === "cancel" || action === "output" || action === "detail" || action === "transcript";
|
|
65089
|
+
}
|
|
65090
|
+
|
|
64986
65091
|
// dist/builtin/workflows/src/workers/stage-watch-coalesce.ts
|
|
64987
65092
|
function streamedDelta(event) {
|
|
64988
65093
|
if (event.type !== "message_update")
|
|
@@ -65309,6 +65414,7 @@ class PoolCoordinator {
|
|
|
65309
65414
|
closing;
|
|
65310
65415
|
replacements = 0;
|
|
65311
65416
|
rootLeaseLost = false;
|
|
65417
|
+
lateRoot;
|
|
65312
65418
|
attemptBase = new Map;
|
|
65313
65419
|
constructor(port) {
|
|
65314
65420
|
this.port = port;
|
|
@@ -65322,6 +65428,47 @@ class PoolCoordinator {
|
|
|
65322
65428
|
await this.journal?.close().catch(() => {});
|
|
65323
65429
|
await this.durable?.close().catch(() => {});
|
|
65324
65430
|
}
|
|
65431
|
+
async whileRootLate(queue, action, resume) {
|
|
65432
|
+
for (let waited = false;; ) {
|
|
65433
|
+
try {
|
|
65434
|
+
if (waited)
|
|
65435
|
+
await resume?.();
|
|
65436
|
+
return await action();
|
|
65437
|
+
} catch (error) {
|
|
65438
|
+
if (!(error instanceof Error) || !isRootLeaseLost(error) || !await this.rootRenewal(queue))
|
|
65439
|
+
throw error;
|
|
65440
|
+
waited = true;
|
|
65441
|
+
}
|
|
65442
|
+
}
|
|
65443
|
+
}
|
|
65444
|
+
rootRenewal(queue) {
|
|
65445
|
+
this.lateRoot ??= this.awaitRootRenewal(queue).finally(() => {
|
|
65446
|
+
this.lateRoot = undefined;
|
|
65447
|
+
});
|
|
65448
|
+
return this.lateRoot;
|
|
65449
|
+
}
|
|
65450
|
+
async awaitRootRenewal(queue) {
|
|
65451
|
+
const lease = this.lease;
|
|
65452
|
+
const since = performance.now();
|
|
65453
|
+
let late = false;
|
|
65454
|
+
try {
|
|
65455
|
+
for (;; ) {
|
|
65456
|
+
if (this.closed)
|
|
65457
|
+
return false;
|
|
65458
|
+
const lost = await this.remote?.fresh(lease).then(() => false, () => true);
|
|
65459
|
+
if (lost)
|
|
65460
|
+
return false;
|
|
65461
|
+
const standing = await queue.rootLease(lease, COORDINATOR_LEASE_MS);
|
|
65462
|
+
if (standing !== "late")
|
|
65463
|
+
return standing === "current";
|
|
65464
|
+
late = true;
|
|
65465
|
+
await delay2(LATE_ROOT_POLL_MS);
|
|
65466
|
+
}
|
|
65467
|
+
} finally {
|
|
65468
|
+
if (late)
|
|
65469
|
+
this.stalledMs += performance.now() - since;
|
|
65470
|
+
}
|
|
65471
|
+
}
|
|
65325
65472
|
receive(message) {
|
|
65326
65473
|
if (message.kind === "request-reply") {
|
|
65327
65474
|
const pending = this.requests.get(message.id);
|
|
@@ -65390,6 +65537,8 @@ class PoolCoordinator {
|
|
|
65390
65537
|
return this.stageAnswer(command.runId, command.stageId, command.answer);
|
|
65391
65538
|
case "stage-pause":
|
|
65392
65539
|
return this.stageControl(command.watch, { op: "pause" });
|
|
65540
|
+
case "stage-session":
|
|
65541
|
+
return this.stageSession(command.watch, command.command);
|
|
65393
65542
|
case "stage-resume":
|
|
65394
65543
|
return this.stageControl(command.watch, {
|
|
65395
65544
|
op: "resume",
|
|
@@ -65419,8 +65568,8 @@ class PoolCoordinator {
|
|
|
65419
65568
|
this.usageTotal = await this.usageLedger.total(root);
|
|
65420
65569
|
this.lease = lease;
|
|
65421
65570
|
const queue = await openSqlPoolQueue(this.journal, this.remote);
|
|
65422
|
-
await queue.initialize(lease, COORDINATOR_LEASE_MS);
|
|
65423
|
-
await queue.drainOutbox(lease);
|
|
65571
|
+
await this.whileRootLate(queue, () => queue.initialize(lease, COORDINATOR_LEASE_MS));
|
|
65572
|
+
await this.whileRootLate(queue, () => queue.drainOutbox(lease));
|
|
65424
65573
|
if (this.remote !== undefined) {
|
|
65425
65574
|
const remote = this.remote;
|
|
65426
65575
|
this.mirrorTimer = setInterval(() => void remote.fresh(lease, 0).catch(() => {}), MIRROR_INTERVAL_MS).unref();
|
|
@@ -65429,10 +65578,10 @@ class PoolCoordinator {
|
|
|
65429
65578
|
for (const work of await queue.inspect(root))
|
|
65430
65579
|
if (work.state === "leased" && work.epoch < lease.epoch && (await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
|
|
65431
65580
|
retained.push(work);
|
|
65432
|
-
await queue.releasePreviousIncarnations(lease, retained.map((work) => work.id));
|
|
65581
|
+
await this.whileRootLate(queue, () => queue.releasePreviousIncarnations(lease, retained.map((work) => work.id)));
|
|
65433
65582
|
for (;; ) {
|
|
65434
65583
|
const intended = this.desiredControl ?? "running";
|
|
65435
|
-
await queue.setControl(lease, intended);
|
|
65584
|
+
await this.whileRootLate(queue, () => queue.setControl(lease, intended));
|
|
65436
65585
|
if (intended === (this.desiredControl ?? "running"))
|
|
65437
65586
|
break;
|
|
65438
65587
|
}
|
|
@@ -65468,7 +65617,7 @@ class PoolCoordinator {
|
|
|
65468
65617
|
return this.retainedTransition(async () => {
|
|
65469
65618
|
const record = this.retained.get(work.id);
|
|
65470
65619
|
this.retained.delete(work.id);
|
|
65471
|
-
await this.queue.releaseRetained(this.lease, work, record?.enqueued === true).catch((error) => {
|
|
65620
|
+
await this.whileRootLate(this.queue, () => this.queue.releaseRetained(this.lease, work, record?.enqueued === true)).catch((error) => {
|
|
65472
65621
|
if (error.message !== STALE_WORK_LEASE)
|
|
65473
65622
|
throw error;
|
|
65474
65623
|
});
|
|
@@ -65482,20 +65631,29 @@ class PoolCoordinator {
|
|
|
65482
65631
|
async control(state) {
|
|
65483
65632
|
this.desiredControl = state;
|
|
65484
65633
|
if (!this.queue || !this.lease)
|
|
65485
|
-
return;
|
|
65486
|
-
const
|
|
65487
|
-
const
|
|
65488
|
-
|
|
65634
|
+
return 0;
|
|
65635
|
+
const queue = this.queue;
|
|
65636
|
+
const lease = this.lease;
|
|
65637
|
+
const control = await this.whileRootLate(queue, () => queue.setControl(lease, state));
|
|
65638
|
+
const unacknowledged = () => [...this.readyWorkers].filter((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision).length;
|
|
65639
|
+
let pending = unacknowledged();
|
|
65640
|
+
let progressAt = performance.now();
|
|
65641
|
+
let stalledAt = this.stalledMs;
|
|
65642
|
+
while (pending > 0) {
|
|
65489
65643
|
if (this.desiredControl !== state)
|
|
65490
|
-
return;
|
|
65491
|
-
if (Date.now() >= deadline) {
|
|
65492
|
-
if (state === "quit")
|
|
65493
|
-
break;
|
|
65494
|
-
throw new Error("Worker control acknowledgement unresolved");
|
|
65495
|
-
}
|
|
65644
|
+
return pending;
|
|
65496
65645
|
await delay2(25);
|
|
65646
|
+
this.observeResponsiveness();
|
|
65647
|
+
const now = unacknowledged();
|
|
65648
|
+
if (now < pending) {
|
|
65649
|
+
pending = now;
|
|
65650
|
+
progressAt = performance.now();
|
|
65651
|
+
stalledAt = this.stalledMs;
|
|
65652
|
+
} else if (performance.now() - progressAt - (this.stalledMs - stalledAt) >= CONTROL_ACKNOWLEDGEMENT_STALL_MS)
|
|
65653
|
+
break;
|
|
65497
65654
|
}
|
|
65498
65655
|
this.flush();
|
|
65656
|
+
return pending;
|
|
65499
65657
|
}
|
|
65500
65658
|
async start(sources, cwd, publish, rootRun) {
|
|
65501
65659
|
if (this.closed)
|
|
@@ -65523,7 +65681,11 @@ class PoolCoordinator {
|
|
|
65523
65681
|
return;
|
|
65524
65682
|
});
|
|
65525
65683
|
this.recoveryTimer = setInterval(() => {
|
|
65526
|
-
this.recoverExpired().catch((error) =>
|
|
65684
|
+
this.recoverExpired().catch(async (error) => {
|
|
65685
|
+
if (this.queue && isRootLeaseLost(error) && await this.rootRenewal(this.queue).catch(() => false))
|
|
65686
|
+
return;
|
|
65687
|
+
this.fail(error);
|
|
65688
|
+
});
|
|
65527
65689
|
}, RECOVERY_INTERVAL_MS).unref();
|
|
65528
65690
|
const workers = Array.from({ length: this.options.workers }, () => this.spawn());
|
|
65529
65691
|
try {
|
|
@@ -65540,7 +65702,9 @@ class PoolCoordinator {
|
|
|
65540
65702
|
const queue = this.queue;
|
|
65541
65703
|
const lease = this.lease;
|
|
65542
65704
|
const work = await this.retainedTransition(async () => {
|
|
65543
|
-
|
|
65705
|
+
let enqueued = await this.whileRootLate(queue, () => queue.enqueue(lease, command.descriptor, command.boundary));
|
|
65706
|
+
if (enqueued.state === "completed" && enqueued.epoch < lease.epoch)
|
|
65707
|
+
enqueued = await this.whileRootLate(queue, () => queue.reopenCompleted(lease, enqueued.id, failedOnInfrastructureFault)) ?? enqueued;
|
|
65544
65708
|
const retained = this.retained.get(enqueued.id);
|
|
65545
65709
|
if (retained)
|
|
65546
65710
|
retained.enqueued = true;
|
|
@@ -65553,7 +65717,9 @@ class PoolCoordinator {
|
|
|
65553
65717
|
}
|
|
65554
65718
|
async transport(request, payload) {
|
|
65555
65719
|
const target = this.deliveryRequests.get(request);
|
|
65556
|
-
if (target === undefined
|
|
65720
|
+
if (target === undefined)
|
|
65721
|
+
throw new Error("Pooled stage delivery request already answered");
|
|
65722
|
+
if (!this.incarnations.has(target.slot.worker))
|
|
65557
65723
|
throw new Error("Worker exited before delivery acknowledgement");
|
|
65558
65724
|
const { slot, workerRequest } = target;
|
|
65559
65725
|
await new Promise((resolve, reject) => {
|
|
@@ -65781,6 +65947,34 @@ class PoolCoordinator {
|
|
|
65781
65947
|
return { ok: false, refusal: "StaleAttempt" };
|
|
65782
65948
|
return { ok: true, ...result.action === undefined ? {} : { action: result.action } };
|
|
65783
65949
|
}
|
|
65950
|
+
async stageSession(id, command) {
|
|
65951
|
+
const watch = this.watches.get(id);
|
|
65952
|
+
if (watch === undefined || !watch.open)
|
|
65953
|
+
return {
|
|
65954
|
+
ok: false,
|
|
65955
|
+
refusal: this.endedWatches.get(id) === "stage_finished" ? "StageNotLive" : "StaleAttempt"
|
|
65956
|
+
};
|
|
65957
|
+
const { slot, attempt } = watch;
|
|
65958
|
+
if (slot.work?.id !== attempt.workId || slot.work.generation !== attempt.generation)
|
|
65959
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
65960
|
+
if (this.desiredControl !== undefined && this.desiredControl !== "running" && !runsWhilePaused(command))
|
|
65961
|
+
return { ok: false, refusal: "PoolPausedOrQuitting" };
|
|
65962
|
+
const result = await this.stageCommand(slot, { attempt, op: "session", watch: id, command });
|
|
65963
|
+
if (result === undefined)
|
|
65964
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
65965
|
+
if (result.error !== undefined)
|
|
65966
|
+
throw new Error(result.error);
|
|
65967
|
+
const refusal = result.refusal;
|
|
65968
|
+
if (refusal === "StageNotLive" || refusal === "PoolPausedOrQuitting")
|
|
65969
|
+
return { ok: false, refusal };
|
|
65970
|
+
if (refusal !== undefined)
|
|
65971
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
65972
|
+
return {
|
|
65973
|
+
ok: true,
|
|
65974
|
+
...result.bash === undefined ? {} : { bash: result.bash },
|
|
65975
|
+
...result.task === undefined ? {} : { task: result.task }
|
|
65976
|
+
};
|
|
65977
|
+
}
|
|
65784
65978
|
stageCommand(slot, command) {
|
|
65785
65979
|
if (!this.incarnations.has(slot.worker)) {
|
|
65786
65980
|
tracePooledWatch("coordinator.command.no-worker", { op: command.op, worker: slot.worker });
|
|
@@ -65896,7 +66090,8 @@ class PoolCoordinator {
|
|
|
65896
66090
|
root,
|
|
65897
66091
|
definitions: this.sources,
|
|
65898
66092
|
admission: options.admission,
|
|
65899
|
-
...this.promptNodes ? { promptNodes: true } : {}
|
|
66093
|
+
...this.promptNodes ? { promptNodes: true } : {},
|
|
66094
|
+
...options.stageStartMaxLoadPerCpu === undefined ? {} : { stageStartMaxLoadPerCpu: options.stageStartMaxLoadPerCpu }
|
|
65900
66095
|
})
|
|
65901
66096
|
], {
|
|
65902
66097
|
stdio: ["ignore", "ignore", "pipe", "ipc"],
|
|
@@ -66017,7 +66212,10 @@ class PoolCoordinator {
|
|
|
66017
66212
|
if (this.closed)
|
|
66018
66213
|
return;
|
|
66019
66214
|
const exhausted = work !== undefined && this.attempts(work) >= MAX_CHILD_ATTEMPTS;
|
|
66020
|
-
const
|
|
66215
|
+
const queue = this.queue;
|
|
66216
|
+
const lease = this.lease;
|
|
66217
|
+
const attempt = work;
|
|
66218
|
+
const settled = attempt !== undefined && await this.whileRootLate(queue, () => exhausted ? queue.failExited(lease, attempt) : queue.releaseExited(lease, attempt));
|
|
66021
66219
|
const superseded = work !== undefined && !settled && await this.superseded(work);
|
|
66022
66220
|
if (work !== undefined && exhausted && !superseded)
|
|
66023
66221
|
this.failWork(work, diagnosed(childRetryLimit(work, "lost its worker")));
|
|
@@ -66079,21 +66277,40 @@ class PoolCoordinator {
|
|
|
66079
66277
|
await this.starting;
|
|
66080
66278
|
const queue = this.queue;
|
|
66081
66279
|
const lease = this.lease;
|
|
66280
|
+
const renewAttempt = async () => {
|
|
66281
|
+
const attempt = slot.work;
|
|
66282
|
+
if (attempt === undefined)
|
|
66283
|
+
return;
|
|
66284
|
+
const renewed = await queue.extend(lease, attempt, options.leaseMs);
|
|
66285
|
+
if (slot.work === attempt)
|
|
66286
|
+
slot.work = renewed;
|
|
66287
|
+
};
|
|
66288
|
+
const current = async (action) => {
|
|
66289
|
+
try {
|
|
66290
|
+
return await action();
|
|
66291
|
+
} catch (error) {
|
|
66292
|
+
if (!(error instanceof Error) || error.message !== STALE_WORK_LEASE || slot.work === undefined)
|
|
66293
|
+
throw error;
|
|
66294
|
+
await renewAttempt();
|
|
66295
|
+
return action();
|
|
66296
|
+
}
|
|
66297
|
+
};
|
|
66298
|
+
const leased = (action) => this.whileRootLate(queue, () => current(action), renewAttempt);
|
|
66082
66299
|
if (message.kind === "control")
|
|
66083
|
-
return queue.control(lease);
|
|
66300
|
+
return leased(() => queue.control(lease));
|
|
66084
66301
|
if (message.kind === "fenced") {
|
|
66085
66302
|
const fenced = slot.work;
|
|
66086
66303
|
slot.work = undefined;
|
|
66087
66304
|
if (fenced && !await this.superseded(fenced)) {
|
|
66088
66305
|
if (this.attempts(fenced) < MAX_CHILD_ATTEMPTS)
|
|
66089
|
-
await queue.releaseExited(lease, fenced);
|
|
66090
|
-
else if (await queue.failExited(lease, fenced))
|
|
66306
|
+
await leased(() => queue.releaseExited(lease, fenced));
|
|
66307
|
+
else if (await leased(() => queue.failExited(lease, fenced)))
|
|
66091
66308
|
this.failWork(fenced, new Error(childRetryLimit(fenced, "was refused by the root as stale on every attempt")));
|
|
66092
66309
|
}
|
|
66093
66310
|
return;
|
|
66094
66311
|
}
|
|
66095
66312
|
if (message.kind === "controlled") {
|
|
66096
|
-
const control = await queue.control(lease);
|
|
66313
|
+
const control = await leased(() => queue.control(lease));
|
|
66097
66314
|
if (message.revision > control.revision)
|
|
66098
66315
|
throw new Error("Unknown control revision");
|
|
66099
66316
|
this.controlAcks.set(worker, Math.max(this.controlAcks.get(worker) ?? -1, message.revision));
|
|
@@ -66104,21 +66321,21 @@ class PoolCoordinator {
|
|
|
66104
66321
|
throw new Error("Worker already holds an attempt");
|
|
66105
66322
|
if (this.budgetBlocked)
|
|
66106
66323
|
return;
|
|
66107
|
-
await
|
|
66108
|
-
|
|
66109
|
-
|
|
66110
|
-
|
|
66111
|
-
|
|
66112
|
-
|
|
66324
|
+
slot.work = await leased(async () => {
|
|
66325
|
+
await this.recoverExpired();
|
|
66326
|
+
slot.runs.clear();
|
|
66327
|
+
return queue.claim(lease, worker, this.sources.map((source) => ({
|
|
66328
|
+
definition: `${source.path}#${source.exportName}`,
|
|
66329
|
+
digest: source.digest
|
|
66330
|
+
})), options.leaseMs);
|
|
66331
|
+
});
|
|
66113
66332
|
return slot.work;
|
|
66114
66333
|
}
|
|
66115
|
-
|
|
66116
|
-
if (!
|
|
66334
|
+
const held = slot.work;
|
|
66335
|
+
if (!held)
|
|
66117
66336
|
throw new Error("Worker has no active attempt");
|
|
66118
|
-
|
|
66119
|
-
|
|
66120
|
-
slot.work = work;
|
|
66121
|
-
}
|
|
66337
|
+
const work = message.kind === "renew" || held.expiresAt - Date.now() < options.leaseMs / 2 ? await leased(() => queue.extend(lease, held, options.leaseMs)) : held;
|
|
66338
|
+
slot.work = work;
|
|
66122
66339
|
if (message.kind === "activity") {
|
|
66123
66340
|
for (const run of message.runs)
|
|
66124
66341
|
slot.runs.add(run.id);
|
|
@@ -66178,24 +66395,24 @@ class PoolCoordinator {
|
|
|
66178
66395
|
if (message.kind === "renew")
|
|
66179
66396
|
return;
|
|
66180
66397
|
if (message.kind === "commit") {
|
|
66181
|
-
const receipt = await queue.commit(lease, work, message.operation, message.mutation);
|
|
66398
|
+
const receipt = await leased(() => queue.commit(lease, work, message.operation, message.mutation));
|
|
66182
66399
|
if (message.mutation.kind !== "session-append")
|
|
66183
66400
|
this.noteUsage(await this.usageLedger.total(root));
|
|
66184
66401
|
return receipt;
|
|
66185
66402
|
}
|
|
66186
66403
|
if (message.kind === "usage") {
|
|
66187
|
-
this.noteUsage(await this.usageLedger.report(lease, work, message.reports));
|
|
66404
|
+
this.noteUsage(await leased(() => this.usageLedger.report(lease, work, message.reports)));
|
|
66188
66405
|
return;
|
|
66189
66406
|
}
|
|
66190
66407
|
if (message.kind === "budget") {
|
|
66191
|
-
await queue.assertCurrent(lease, work);
|
|
66408
|
+
await leased(() => queue.assertCurrent(lease, work));
|
|
66192
66409
|
if (this.budgetBlocked)
|
|
66193
66410
|
throw new Error("Root workflow budget exhausted");
|
|
66194
|
-
return queue.control(lease);
|
|
66411
|
+
return leased(() => queue.control(lease));
|
|
66195
66412
|
}
|
|
66196
66413
|
if (message.kind !== "complete")
|
|
66197
66414
|
throw new Error("Invalid worker operation");
|
|
66198
|
-
await queue.complete(lease, work, message.result);
|
|
66415
|
+
await leased(() => queue.complete(lease, work, message.result));
|
|
66199
66416
|
this.endStageWatches((watch) => watch.slot === slot, "stage_finished");
|
|
66200
66417
|
this.replacements = 0;
|
|
66201
66418
|
slot.work = undefined;
|
|
@@ -66234,7 +66451,7 @@ class PoolCoordinator {
|
|
|
66234
66451
|
if (this.recovering)
|
|
66235
66452
|
return this.recovering;
|
|
66236
66453
|
const root = this.root;
|
|
66237
|
-
if (this.closed || root === undefined || !this.queue || performance.now() < this.nextRecoveryAt)
|
|
66454
|
+
if (this.closed || root === undefined || !this.queue || this.lateRoot !== undefined || performance.now() < this.nextRecoveryAt)
|
|
66238
66455
|
return Promise.resolve();
|
|
66239
66456
|
const queue = this.queue;
|
|
66240
66457
|
const lease = this.lease;
|
|
@@ -66243,9 +66460,12 @@ class PoolCoordinator {
|
|
|
66243
66460
|
await new Promise((resolve) => setImmediate(resolve));
|
|
66244
66461
|
await this.admission?.reconcile();
|
|
66245
66462
|
const expiredBefore = Date.now();
|
|
66246
|
-
|
|
66247
|
-
|
|
66248
|
-
|
|
66463
|
+
const expired = (await queue.inspect(root)).filter((work) => work.state === "leased" && work.expiresAt < expiredBefore);
|
|
66464
|
+
if (expired.length > 0 && await queue.rootLease(lease, COORDINATOR_LEASE_MS) === "late") {
|
|
66465
|
+
this.rootRenewal(queue).catch(() => {});
|
|
66466
|
+
return;
|
|
66467
|
+
}
|
|
66468
|
+
for (const work of expired) {
|
|
66249
66469
|
if (this.quarantined.has(work.id))
|
|
66250
66470
|
continue;
|
|
66251
66471
|
if (this.held.has(work.id)) {
|
|
@@ -66387,7 +66607,7 @@ function runPoolCoordinator() {
|
|
|
66387
66607
|
port.onClose(() => process.exit(0));
|
|
66388
66608
|
return coordinator;
|
|
66389
66609
|
}
|
|
66390
|
-
var
|
|
66610
|
+
var CONTROL_ACKNOWLEDGEMENT_STALL_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, LATE_ROOT_POLL_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
|
|
66391
66611
|
var init_pool_coordinator = __esm(() => {
|
|
66392
66612
|
init_internal();
|
|
66393
66613
|
init_pool_remote_journal();
|
|
@@ -66401,12 +66621,14 @@ var init_pool_coordinator = __esm(() => {
|
|
|
66401
66621
|
init_pending_stage_route_capability();
|
|
66402
66622
|
init_pending_stage_route_readiness();
|
|
66403
66623
|
init_store();
|
|
66624
|
+
init_workflow_infrastructure_error();
|
|
66404
66625
|
init_pool_journal();
|
|
66405
66626
|
init_pooled_watch_trace();
|
|
66406
66627
|
init_resource_admission();
|
|
66407
66628
|
init_stage_watch_coalesce();
|
|
66408
66629
|
init_startup_timeout();
|
|
66409
66630
|
COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
|
|
66631
|
+
LATE_ROOT_POLL_MS = RECOVERY_INTERVAL_MS;
|
|
66410
66632
|
STAGE_WATCH_BACKLOG_BYTES = 8 * 1024 * 1024;
|
|
66411
66633
|
});
|
|
66412
66634
|
|
|
@@ -66436,6 +66658,26 @@ function isWorkflowPendingStageDeliveryFailure(error) {
|
|
|
66436
66658
|
return true;
|
|
66437
66659
|
return error?.code === "pending_stage_delivery_failed";
|
|
66438
66660
|
}
|
|
66661
|
+
function untilDrainedOrStalled(drain) {
|
|
66662
|
+
let lastProgressAt = Date.now();
|
|
66663
|
+
const running = drain(() => {
|
|
66664
|
+
lastProgressAt = Date.now();
|
|
66665
|
+
});
|
|
66666
|
+
return new Promise((resolve, reject) => {
|
|
66667
|
+
let timer;
|
|
66668
|
+
const check = () => {
|
|
66669
|
+
const remaining = lastProgressAt + PENDING_STAGE_READY_STALL_MS - Date.now();
|
|
66670
|
+
if (remaining <= 0) {
|
|
66671
|
+
resolve();
|
|
66672
|
+
return;
|
|
66673
|
+
}
|
|
66674
|
+
timer = setTimeout(check, remaining);
|
|
66675
|
+
timer.unref?.();
|
|
66676
|
+
};
|
|
66677
|
+
running.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
66678
|
+
check();
|
|
66679
|
+
});
|
|
66680
|
+
}
|
|
66439
66681
|
function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName, commit = (action) => action(), options = {}) {
|
|
66440
66682
|
let resolveReady;
|
|
66441
66683
|
let rejectReady;
|
|
@@ -66497,7 +66739,8 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
66497
66739
|
const boundedDrain = (drain, sessionId) => {
|
|
66498
66740
|
const waiting = new Promise((resolve, reject) => {
|
|
66499
66741
|
drain.then(resolve, reject);
|
|
66500
|
-
|
|
66742
|
+
if (options.holdUntilDrained !== true)
|
|
66743
|
+
watchStall(drain, sessionId, resolve);
|
|
66501
66744
|
});
|
|
66502
66745
|
waiting.catch(() => {});
|
|
66503
66746
|
return waiting;
|
|
@@ -66879,10 +67122,14 @@ class PoolStageHandoff {
|
|
|
66879
67122
|
if (run.endedAt !== undefined || this.owners.get(run.id) !== work.id)
|
|
66880
67123
|
continue;
|
|
66881
67124
|
if (run.id === work.childRunId) {
|
|
66882
|
-
const
|
|
67125
|
+
const executions = new Map(run.stages.map((stage) => [stage.id, stage.workerExecution]));
|
|
67126
|
+
const attempt = run.stages.flatMap((stage) => stage.workerExecution === undefined ? [] : [stage.workerExecution]).reduce((latest, execution) => latest === undefined || execution.renewedAt > latest.renewedAt ? execution : latest, undefined);
|
|
66883
67127
|
this.store.recordRunStart({
|
|
66884
67128
|
...run,
|
|
66885
|
-
stages: result.stages.map((stage) =>
|
|
67129
|
+
stages: result.stages.map((stage) => {
|
|
67130
|
+
const execution = executions.get(stage.id) ?? attempt;
|
|
67131
|
+
return execution === undefined ? stage : { ...stage, workerExecution: execution };
|
|
67132
|
+
}),
|
|
66886
67133
|
toolNodes: result.toolNodes
|
|
66887
67134
|
});
|
|
66888
67135
|
this.store.recordRunEnd(run.id, result.status, result.result, result.error);
|
|
@@ -66936,7 +67183,7 @@ class PoolStageHandoff {
|
|
|
66936
67183
|
pendingStageMessages: [
|
|
66937
67184
|
...known.get(run.id)?.pendingStageMessages ?? pendingStageMessagesForDurableRun(this.backend, run.id, root)
|
|
66938
67185
|
],
|
|
66939
|
-
stages: withReconnectingStages(known.get(run.id), run, run.stages.map((stage) => ({ ...stage, workerExecution: execution })), work.generation)
|
|
67186
|
+
stages: withReconnectingStages(known.get(run.id), run, run.stages.map((stage) => ({ ...stage, workerExecution: endedUnder(known.get(run.id), stage, execution) })), work.generation)
|
|
66940
67187
|
}));
|
|
66941
67188
|
const changed = published.some((run) => activity(known.get(run.id)) !== activity(run));
|
|
66942
67189
|
for (const run of published)
|
|
@@ -67067,7 +67314,7 @@ class PoolStageHandoff {
|
|
|
67067
67314
|
throw new Error(STALE);
|
|
67068
67315
|
if (attempt.sessions.get(key) !== sessionId)
|
|
67069
67316
|
throw new Error(`Stage session ${sessionId} was replaced before it acknowledged delivery`);
|
|
67070
|
-
}, action));
|
|
67317
|
+
}, action), { holdUntilDrained: true });
|
|
67071
67318
|
attempt.deliveries.set(key, delivery);
|
|
67072
67319
|
}
|
|
67073
67320
|
return delivery;
|
|
@@ -67079,6 +67326,12 @@ function outside2(runId) {
|
|
|
67079
67326
|
function isLive(stage) {
|
|
67080
67327
|
return (stage.sessionId !== undefined || stage.sessionFile !== undefined) && stage.status !== "completed" && stage.status !== "failed" && stage.status !== "skipped";
|
|
67081
67328
|
}
|
|
67329
|
+
function endedUnder(known, stage, execution) {
|
|
67330
|
+
if (!isTerminalStageStatus(stage.status))
|
|
67331
|
+
return execution;
|
|
67332
|
+
const previous = known?.stages.find((candidate) => candidate.id === stage.id);
|
|
67333
|
+
return previous !== undefined && isTerminalStageStatus(previous.status) && previous.workerExecution?.generation === execution.generation && previous.workerExecution.worker === execution.worker ? previous.workerExecution : execution;
|
|
67334
|
+
}
|
|
67082
67335
|
function withReconnectingStages(previous, run, stages, generation) {
|
|
67083
67336
|
if (previous === undefined || run.endedAt !== undefined || isTerminalRunStatus(run.status))
|
|
67084
67337
|
return stages;
|
|
@@ -67215,6 +67468,116 @@ class StageToolExecutionBuffer {
|
|
|
67215
67468
|
}
|
|
67216
67469
|
}
|
|
67217
67470
|
|
|
67471
|
+
// dist/builtin/workflows/src/workers/pooled-stage-task-source.ts
|
|
67472
|
+
function failure2(error) {
|
|
67473
|
+
return { ok: false, error: { message: typeof error === "string" ? error : error.message } };
|
|
67474
|
+
}
|
|
67475
|
+
|
|
67476
|
+
class PooledStageTaskSource {
|
|
67477
|
+
run;
|
|
67478
|
+
state = EMPTY;
|
|
67479
|
+
records = [];
|
|
67480
|
+
backgroundRecords = [];
|
|
67481
|
+
settlements = new Map;
|
|
67482
|
+
activity = new Map;
|
|
67483
|
+
statuses = new Map;
|
|
67484
|
+
stdin = new Set;
|
|
67485
|
+
listeners = new Set;
|
|
67486
|
+
constructor(run) {
|
|
67487
|
+
this.run = run;
|
|
67488
|
+
}
|
|
67489
|
+
apply(state) {
|
|
67490
|
+
this.state = state;
|
|
67491
|
+
this.records = [...state.tasks];
|
|
67492
|
+
const background = new Set(state.background);
|
|
67493
|
+
this.backgroundRecords = this.records.filter((task) => background.has(task.ref.taskId));
|
|
67494
|
+
this.settlements = new Map(state.settlement.map(([id, sequence]) => [id, BigInt(sequence)]));
|
|
67495
|
+
this.activity = new Map(state.activity.map((entry) => [entry.id, entry]));
|
|
67496
|
+
this.statuses = new Map(state.statuses.map((entry) => [entry.id, new Map(entry.entries)]));
|
|
67497
|
+
this.stdin = new Set(state.stdin);
|
|
67498
|
+
for (const listener of [...this.listeners])
|
|
67499
|
+
listener();
|
|
67500
|
+
}
|
|
67501
|
+
get empty() {
|
|
67502
|
+
return this.state.tasks.length === 0;
|
|
67503
|
+
}
|
|
67504
|
+
get tasks() {
|
|
67505
|
+
return this.records;
|
|
67506
|
+
}
|
|
67507
|
+
get backgroundTasks() {
|
|
67508
|
+
return this.backgroundRecords;
|
|
67509
|
+
}
|
|
67510
|
+
get settlementOrder() {
|
|
67511
|
+
return this.settlements;
|
|
67512
|
+
}
|
|
67513
|
+
recentActivity(id) {
|
|
67514
|
+
return [...this.activity.get(id)?.entries ?? []];
|
|
67515
|
+
}
|
|
67516
|
+
activityOmitted(id) {
|
|
67517
|
+
return this.activity.get(id)?.omitted === true;
|
|
67518
|
+
}
|
|
67519
|
+
subscribe(listener) {
|
|
67520
|
+
this.listeners.add(listener);
|
|
67521
|
+
return () => {
|
|
67522
|
+
this.listeners.delete(listener);
|
|
67523
|
+
};
|
|
67524
|
+
}
|
|
67525
|
+
async foregroundTask(id) {
|
|
67526
|
+
const reply = await this.request(id, { kind: "foreground" });
|
|
67527
|
+
return reply.ok ? reply.value.kind === "foreground" ? reply.value.result : unexpected() : reply;
|
|
67528
|
+
}
|
|
67529
|
+
async cancelTask(id) {
|
|
67530
|
+
const reply = await this.request(id, { kind: "cancel" });
|
|
67531
|
+
if (!reply.ok)
|
|
67532
|
+
return reply;
|
|
67533
|
+
return reply.value.kind === "cancel" ? reply.value.result ?? { ok: true, value: undefined } : unexpected();
|
|
67534
|
+
}
|
|
67535
|
+
stdinAvailable(id) {
|
|
67536
|
+
return this.stdin.has(id);
|
|
67537
|
+
}
|
|
67538
|
+
async writeTaskInput(id, text) {
|
|
67539
|
+
const reply = await this.request(id, { kind: "input", text });
|
|
67540
|
+
return reply.ok ? reply.value.kind === "input" ? reply.value.result : unexpected() : reply;
|
|
67541
|
+
}
|
|
67542
|
+
async readTaskOutput(id, range) {
|
|
67543
|
+
const reply = await this.request(id, { kind: "output", start: range.start, maximumBytes: range.maximumBytes });
|
|
67544
|
+
return reply.ok ? reply.value.kind === "output" ? reply.value.result : unexpected() : reply;
|
|
67545
|
+
}
|
|
67546
|
+
async taskDetailText(id) {
|
|
67547
|
+
const reply = await this.request(id, { kind: "detail" });
|
|
67548
|
+
return reply.ok && reply.value.kind === "detail" ? reply.value.detail : {};
|
|
67549
|
+
}
|
|
67550
|
+
async readTaskTranscript(id, cursor) {
|
|
67551
|
+
const reply = await this.request(id, { kind: "transcript", ...cursor === undefined ? {} : { cursor } });
|
|
67552
|
+
return reply.ok ? reply.value.kind === "transcript" ? reply.value.result : unexpected() : reply;
|
|
67553
|
+
}
|
|
67554
|
+
followTaskTranscript(id) {
|
|
67555
|
+
return this.records.some((task) => task.ref.taskId === id && task.kind === "agent") ? { historyOnly: true } : undefined;
|
|
67556
|
+
}
|
|
67557
|
+
extensionStatuses(id) {
|
|
67558
|
+
return this.statuses.get(id) ?? NO_STATUSES;
|
|
67559
|
+
}
|
|
67560
|
+
watchExtensionStatuses(_id, listener) {
|
|
67561
|
+
return this.subscribe(listener);
|
|
67562
|
+
}
|
|
67563
|
+
async request(id, action) {
|
|
67564
|
+
try {
|
|
67565
|
+
const reply = await this.run(id, action);
|
|
67566
|
+
return reply === undefined ? failure2("Task unavailable") : { ok: true, value: reply };
|
|
67567
|
+
} catch (error) {
|
|
67568
|
+
return failure2(error instanceof Error ? error : String(error));
|
|
67569
|
+
}
|
|
67570
|
+
}
|
|
67571
|
+
}
|
|
67572
|
+
function unexpected() {
|
|
67573
|
+
return failure2("Unexpected reply from the local worker");
|
|
67574
|
+
}
|
|
67575
|
+
var EMPTY, NO_STATUSES;
|
|
67576
|
+
var init_pooled_stage_task_source = __esm(() => {
|
|
67577
|
+
EMPTY = { tasks: [], background: [], settlement: [], activity: [], stdin: [], statuses: [] };
|
|
67578
|
+
NO_STATUSES = new Map;
|
|
67579
|
+
});
|
|
67580
|
+
|
|
67218
67581
|
// dist/builtin/workflows/src/workers/pooled-stage-handle.ts
|
|
67219
67582
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
67220
67583
|
|
|
@@ -67245,6 +67608,11 @@ class PooledStageHandle {
|
|
|
67245
67608
|
undelivered;
|
|
67246
67609
|
disposed = false;
|
|
67247
67610
|
session;
|
|
67611
|
+
commands;
|
|
67612
|
+
sessionStarted = true;
|
|
67613
|
+
started = Promise.withResolvers();
|
|
67614
|
+
bashRuns = new Map;
|
|
67615
|
+
taskView = new PooledStageTaskSource(async (taskId, action) => (await this.sessionCommand({ kind: "task", taskId, action })).task);
|
|
67248
67616
|
pumping;
|
|
67249
67617
|
pumpAgain = false;
|
|
67250
67618
|
watchGone = Promise.withResolvers();
|
|
@@ -67307,6 +67675,43 @@ class PooledStageHandle {
|
|
|
67307
67675
|
streamingMessage() {
|
|
67308
67676
|
return this.streaming;
|
|
67309
67677
|
}
|
|
67678
|
+
commandCatalog() {
|
|
67679
|
+
return this.commands;
|
|
67680
|
+
}
|
|
67681
|
+
taskSource() {
|
|
67682
|
+
return this.taskView;
|
|
67683
|
+
}
|
|
67684
|
+
get isSessionStarting() {
|
|
67685
|
+
return !this.sessionStarted && this.ended === undefined;
|
|
67686
|
+
}
|
|
67687
|
+
get isBashRunning() {
|
|
67688
|
+
return this.bashRuns.size > 0;
|
|
67689
|
+
}
|
|
67690
|
+
async executeBash(command, onChunk, options) {
|
|
67691
|
+
const id = randomUUID17();
|
|
67692
|
+
this.bashRuns.set(id, onChunk);
|
|
67693
|
+
try {
|
|
67694
|
+
const result = await this.sessionCommand({
|
|
67695
|
+
kind: "bash",
|
|
67696
|
+
id,
|
|
67697
|
+
command,
|
|
67698
|
+
...options?.excludeFromContext === undefined ? {} : { excludeFromContext: options.excludeFromContext }
|
|
67699
|
+
});
|
|
67700
|
+
return result.bash ?? { output: "", exitCode: undefined, cancelled: true, truncated: false };
|
|
67701
|
+
} finally {
|
|
67702
|
+
this.bashRuns.delete(id);
|
|
67703
|
+
}
|
|
67704
|
+
}
|
|
67705
|
+
abortBash() {
|
|
67706
|
+
for (const id of this.bashRuns.keys())
|
|
67707
|
+
this.sessionCommand({ kind: "abort-bash", id }).catch(() => {});
|
|
67708
|
+
}
|
|
67709
|
+
async compact() {
|
|
67710
|
+
await this.sessionCommand({ kind: "compact" });
|
|
67711
|
+
}
|
|
67712
|
+
abortCompaction() {
|
|
67713
|
+
this.sessionCommand({ kind: "abort-compaction" }).catch(() => {});
|
|
67714
|
+
}
|
|
67310
67715
|
pendingToolExecutionEvents() {
|
|
67311
67716
|
return this.toolExecutions.replayEvents();
|
|
67312
67717
|
}
|
|
@@ -67454,6 +67859,17 @@ class PooledStageHandle {
|
|
|
67454
67859
|
if (this.disposed)
|
|
67455
67860
|
throw new Error(`Stage chat "${this.stageName}" is closed.`);
|
|
67456
67861
|
}
|
|
67862
|
+
async sessionCommand(command) {
|
|
67863
|
+
this.throwIfClosed();
|
|
67864
|
+
if (this.ended !== undefined)
|
|
67865
|
+
throw new PooledStageDeliveryError("StageNotLive", this.stageName);
|
|
67866
|
+
if (this.transport.session === undefined)
|
|
67867
|
+
throw new Error(`Stage "${this.stageName}" runs on a local worker that cannot run this command.`);
|
|
67868
|
+
const result = await this.transport.session(this.watchId, command);
|
|
67869
|
+
if (!result.ok)
|
|
67870
|
+
throw new PooledStageDeliveryError(result.refusal, this.stageName);
|
|
67871
|
+
return result;
|
|
67872
|
+
}
|
|
67457
67873
|
undeliveredCount() {
|
|
67458
67874
|
if (this.undelivered !== undefined)
|
|
67459
67875
|
return this.undelivered;
|
|
@@ -67519,6 +67935,16 @@ class PooledStageHandle {
|
|
|
67519
67935
|
entry.waiter = undefined;
|
|
67520
67936
|
}
|
|
67521
67937
|
}
|
|
67938
|
+
markSessionStarted(started) {
|
|
67939
|
+
if (started) {
|
|
67940
|
+
this.sessionStarted = true;
|
|
67941
|
+
this.started.resolve();
|
|
67942
|
+
return;
|
|
67943
|
+
}
|
|
67944
|
+
if (this.sessionStarted)
|
|
67945
|
+
this.started = Promise.withResolvers();
|
|
67946
|
+
this.sessionStarted = false;
|
|
67947
|
+
}
|
|
67522
67948
|
forget(op) {
|
|
67523
67949
|
const index = this.outbound.findIndex((entry) => entry.op === op);
|
|
67524
67950
|
if (index >= 0)
|
|
@@ -67575,10 +68001,17 @@ class PooledStageHandle {
|
|
|
67575
68001
|
const gone = this.watchGone.promise.then(() => ({ ok: false, refusal: "StaleAttempt" }));
|
|
67576
68002
|
const sending = this.sendEntry(entry, watch);
|
|
67577
68003
|
let bound;
|
|
68004
|
+
let stopped = false;
|
|
67578
68005
|
const unconfirmed = new Promise((resolve) => {
|
|
67579
|
-
|
|
68006
|
+
this.started.promise.then(() => {
|
|
68007
|
+
if (!stopped)
|
|
68008
|
+
bound = setTimeout(() => resolve("unconfirmed"), this.admissionWaitMs);
|
|
68009
|
+
});
|
|
68010
|
+
});
|
|
68011
|
+
const outcome = await Promise.race([sending, gone, unconfirmed]).finally(() => {
|
|
68012
|
+
stopped = true;
|
|
68013
|
+
clearTimeout(bound);
|
|
67580
68014
|
});
|
|
67581
|
-
const outcome = await Promise.race([sending, gone, unconfirmed]).finally(() => clearTimeout(bound));
|
|
67582
68015
|
if (outcome === "unconfirmed") {
|
|
67583
68016
|
tracePooledWatch("root.outbox.unconfirmed", { op: entry.op, watch, generation });
|
|
67584
68017
|
entry.unconfirmedOn = generation;
|
|
@@ -67668,6 +68101,10 @@ class PooledStageHandle {
|
|
|
67668
68101
|
}
|
|
67669
68102
|
adopt(snapshot) {
|
|
67670
68103
|
this.session = snapshot.sessionId;
|
|
68104
|
+
this.commands = snapshot.commands;
|
|
68105
|
+
if (!this.taskView.empty)
|
|
68106
|
+
this.taskView.apply(NO_TASKS);
|
|
68107
|
+
this.markSessionStarted(snapshot.sessionStarted !== false);
|
|
67671
68108
|
this.settled = [...snapshot.messages];
|
|
67672
68109
|
this.streaming = snapshot.streamingMessage;
|
|
67673
68110
|
this.currentStatus = snapshot.status;
|
|
@@ -67688,6 +68125,25 @@ class PooledStageHandle {
|
|
|
67688
68125
|
this.forget(event.op);
|
|
67689
68126
|
return false;
|
|
67690
68127
|
}
|
|
68128
|
+
if (event.type === STAGE_SESSION_STARTED_EVENT) {
|
|
68129
|
+
this.commands = event.commands;
|
|
68130
|
+
this.markSessionStarted(true);
|
|
68131
|
+
const queued = this.queuedUserMessages();
|
|
68132
|
+
const redraw = { type: "queue_update", steering: [...queued.steering], followUp: [...queued.followUp] };
|
|
68133
|
+
for (const listener of [...this.listeners])
|
|
68134
|
+
listener(redraw);
|
|
68135
|
+
return false;
|
|
68136
|
+
}
|
|
68137
|
+
if (event.type === STAGE_TASKS_EVENT) {
|
|
68138
|
+
this.taskView.apply(event.tasks);
|
|
68139
|
+
return false;
|
|
68140
|
+
}
|
|
68141
|
+
if (event.type === STAGE_MESSAGES_EVENT) {
|
|
68142
|
+
this.settled = [...event.messages];
|
|
68143
|
+
return false;
|
|
68144
|
+
}
|
|
68145
|
+
if (event.type === "bash_execution_update" && event.id !== undefined)
|
|
68146
|
+
this.bashRuns.get(event.id)?.(event.delta);
|
|
67691
68147
|
this.applyEvent(event);
|
|
67692
68148
|
const turnUnderway = TURN_EVENTS.has(event.type) || (event.type === "message_start" || event.type === "message_update") && event.message.role === "assistant";
|
|
67693
68149
|
if (turnUnderway && this.awaitingTurn) {
|
|
@@ -67770,10 +68226,12 @@ async function reconnectPooledStageHandle(handle, transport, wanted = () => true
|
|
|
67770
68226
|
await rebinding;
|
|
67771
68227
|
return !handle.isReconnecting;
|
|
67772
68228
|
}
|
|
67773
|
-
var DELIVERY_RECEIPT_EVENT = "atomic_pooled_delivery_receipt", POOLED_ADMISSION_WAIT_MS = 15000, RECONNECTABLE, TURN_EVENTS, PooledStageDeliveryError;
|
|
68229
|
+
var DELIVERY_RECEIPT_EVENT = "atomic_pooled_delivery_receipt", STAGE_SESSION_STARTED_EVENT = "atomic_pooled_stage_session_started", STAGE_MESSAGES_EVENT = "atomic_pooled_stage_messages", STAGE_TASKS_EVENT = "atomic_pooled_stage_tasks", NO_TASKS, POOLED_ADMISSION_WAIT_MS = 15000, RECONNECTABLE, TURN_EVENTS, PooledStageDeliveryError;
|
|
67774
68230
|
var init_pooled_stage_handle = __esm(() => {
|
|
67775
68231
|
init_stage_queued_user_messages();
|
|
68232
|
+
init_pooled_stage_task_source();
|
|
67776
68233
|
init_pooled_watch_trace();
|
|
68234
|
+
NO_TASKS = { tasks: [], background: [], settlement: [], activity: [], stdin: [], statuses: [] };
|
|
67777
68235
|
RECONNECTABLE = new Set(["attempt_fenced", "worker_exited", "resync"]);
|
|
67778
68236
|
TURN_EVENTS = new Set(["agent_start", "turn_start", "tool_execution_start", "tool_execution_update"]);
|
|
67779
68237
|
PooledStageDeliveryError = class PooledStageDeliveryError extends Error {
|
|
@@ -67833,6 +68291,9 @@ class RegisteredPooledStageHandle {
|
|
|
67833
68291
|
pendingToolExecutionEvents() {
|
|
67834
68292
|
return this.current()?.pendingToolExecutionEvents?.() ?? [];
|
|
67835
68293
|
}
|
|
68294
|
+
commandCatalog() {
|
|
68295
|
+
return this.current()?.commandCatalog?.();
|
|
68296
|
+
}
|
|
67836
68297
|
update(stage) {
|
|
67837
68298
|
this.stage = stage;
|
|
67838
68299
|
}
|
|
@@ -68131,6 +68592,7 @@ class LocalWorkerPool {
|
|
|
68131
68592
|
rootSignature;
|
|
68132
68593
|
completing = 0;
|
|
68133
68594
|
rootFlush;
|
|
68595
|
+
connecting;
|
|
68134
68596
|
starting;
|
|
68135
68597
|
failure;
|
|
68136
68598
|
closed = false;
|
|
@@ -68160,6 +68622,8 @@ class LocalWorkerPool {
|
|
|
68160
68622
|
throw new Error("Invalid local worker startup timeout");
|
|
68161
68623
|
if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
|
|
68162
68624
|
throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
|
|
68625
|
+
if (options.maxLoadPerCpu !== undefined && (!Number.isFinite(options.maxLoadPerCpu) || options.maxLoadPerCpu < 0))
|
|
68626
|
+
throw new Error("Invalid local worker load threshold: maxLoadPerCpu must be a number of at least 0");
|
|
68163
68627
|
this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
|
|
68164
68628
|
this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
|
|
68165
68629
|
if (options.admission && options.rootId === undefined)
|
|
@@ -68187,23 +68651,35 @@ class LocalWorkerPool {
|
|
|
68187
68651
|
if (!state || state.holderId !== this.backend.holderId)
|
|
68188
68652
|
throw new Error("Local worker pool requires the root owner");
|
|
68189
68653
|
this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
|
|
68190
|
-
const workerEntry = this.options.workerEntry ?? (isBunBinary2 || this.options.coordinator === "in-process" ? defaultWorkerEntry() : undefined);
|
|
68191
|
-
this.usageTotal = await this.command({
|
|
68192
|
-
kind: "prepare",
|
|
68193
|
-
root,
|
|
68194
|
-
lease: this.lease,
|
|
68195
|
-
options: {
|
|
68196
|
-
journalPath: this.options.journalPath,
|
|
68197
|
-
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
68198
|
-
workers: this.options.workers,
|
|
68199
|
-
leaseMs: this.leaseMs,
|
|
68200
|
-
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
68201
|
-
...this.options.admission === undefined ? {} : { admission: this.options.admission },
|
|
68202
|
-
...workerEntry === undefined ? {} : { workerEntry }
|
|
68203
|
-
},
|
|
68204
|
-
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
68205
|
-
});
|
|
68206
68654
|
this.queue ??= await openSqlPoolQueue(poolJournal, this.options.durable === undefined ? undefined : new PoolRemoteJournal(this.backend.journal, sqlPoolStorage(poolJournal)));
|
|
68655
|
+
if (await this.queue.initialized(root))
|
|
68656
|
+
await this.connectPool();
|
|
68657
|
+
}
|
|
68658
|
+
connectPool() {
|
|
68659
|
+
this.connecting ??= (async () => {
|
|
68660
|
+
const root = this.root;
|
|
68661
|
+
const lease = this.lease;
|
|
68662
|
+
if (root === undefined || lease === undefined)
|
|
68663
|
+
throw new Error("Local worker pool requires root preparation");
|
|
68664
|
+
const workerEntry = this.options.workerEntry ?? (isBunBinary2 || this.options.coordinator === "in-process" ? defaultWorkerEntry() : undefined);
|
|
68665
|
+
this.usageTotal = await this.command({
|
|
68666
|
+
kind: "prepare",
|
|
68667
|
+
root,
|
|
68668
|
+
lease,
|
|
68669
|
+
options: {
|
|
68670
|
+
journalPath: this.options.journalPath,
|
|
68671
|
+
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
68672
|
+
workers: this.options.workers,
|
|
68673
|
+
leaseMs: this.leaseMs,
|
|
68674
|
+
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
68675
|
+
...this.options.admission === undefined ? {} : { admission: this.options.admission },
|
|
68676
|
+
...this.options.maxLoadPerCpu === undefined ? {} : { stageStartMaxLoadPerCpu: this.options.maxLoadPerCpu },
|
|
68677
|
+
...workerEntry === undefined ? {} : { workerEntry }
|
|
68678
|
+
},
|
|
68679
|
+
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
68680
|
+
});
|
|
68681
|
+
})();
|
|
68682
|
+
return this.connecting;
|
|
68207
68683
|
}
|
|
68208
68684
|
async poolJournal() {
|
|
68209
68685
|
const journal = this.backend.journal;
|
|
@@ -68252,6 +68728,7 @@ class LocalWorkerPool {
|
|
|
68252
68728
|
async start(root, promptNodes) {
|
|
68253
68729
|
if (this.closed)
|
|
68254
68730
|
throw new Error("Local worker pool is closed");
|
|
68731
|
+
await this.connectPool();
|
|
68255
68732
|
if (!this.queue || !this.lease || this.lease.runId !== root)
|
|
68256
68733
|
throw new Error("Local worker pool requires root preparation");
|
|
68257
68734
|
this.sources = await Promise.all(this.options.definitions.map(async (binding) => {
|
|
@@ -68534,6 +69011,11 @@ class LocalWorkerPool {
|
|
|
68534
69011
|
...message === undefined ? {} : { message }
|
|
68535
69012
|
});
|
|
68536
69013
|
}
|
|
69014
|
+
async sessionCommandOnPooledStage(watch, command) {
|
|
69015
|
+
if (this.closed || this.coordinatorLost !== undefined)
|
|
69016
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
69017
|
+
return await this.command({ kind: "stage-session", watch, command });
|
|
69018
|
+
}
|
|
68537
69019
|
stageTransport(onEnded) {
|
|
68538
69020
|
return {
|
|
68539
69021
|
watch: (ref, listener) => this.watchPooledStage(ref, (message) => {
|
|
@@ -68544,7 +69026,8 @@ class LocalWorkerPool {
|
|
|
68544
69026
|
unwatch: (watch) => this.unwatchPooledStage(watch),
|
|
68545
69027
|
deliver: (delivery) => this.deliverToPooledStage(delivery),
|
|
68546
69028
|
pause: (watch) => this.pausePooledStage(watch),
|
|
68547
|
-
resume: (watch, message) => this.resumePooledStage(watch, message)
|
|
69029
|
+
resume: (watch, message) => this.resumePooledStage(watch, message),
|
|
69030
|
+
session: (watch, command) => this.sessionCommandOnPooledStage(watch, command)
|
|
68548
69031
|
};
|
|
68549
69032
|
}
|
|
68550
69033
|
async acquirePooledStage(runId, stageId) {
|
|
@@ -69207,6 +69690,9 @@ var init_local_pool = __esm(() => {
|
|
|
69207
69690
|
completeInTurns = createTurnSlicer(2, COMPLETION_TURN_BUDGET_MS);
|
|
69208
69691
|
});
|
|
69209
69692
|
|
|
69693
|
+
// dist/builtin/workflows/src/workers/public-options.ts
|
|
69694
|
+
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
69695
|
+
|
|
69210
69696
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
69211
69697
|
import { resolve as resolve14 } from "node:path";
|
|
69212
69698
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
@@ -69257,6 +69743,7 @@ async function activatePublicPool(backend, options) {
|
|
|
69257
69743
|
...options.localWorkers,
|
|
69258
69744
|
startupTimeoutMs: undefined,
|
|
69259
69745
|
leaseMs: undefined,
|
|
69746
|
+
maxLoadPerCpu: undefined,
|
|
69260
69747
|
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve14(cwd, source.path) }))
|
|
69261
69748
|
};
|
|
69262
69749
|
const admission = options.admission && {
|
|
@@ -69300,6 +69787,7 @@ async function activatePublicPool(backend, options) {
|
|
|
69300
69787
|
admission: resources.admission ?? {},
|
|
69301
69788
|
startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
|
|
69302
69789
|
leaseMs: options.localWorkers?.leaseMs,
|
|
69790
|
+
maxLoadPerCpu: options.localWorkers?.maxLoadPerCpu ?? DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU,
|
|
69303
69791
|
...options.stageControlRegistry === undefined || options[hostWorkerBindings] ? {} : { stageControlRegistry: options.stageControlRegistry }
|
|
69304
69792
|
});
|
|
69305
69793
|
try {
|
|
@@ -75737,7 +76225,7 @@ class StageSessionController {
|
|
|
75737
76225
|
return this.modelRoute ? this.checkedSession(await ready) : ready;
|
|
75738
76226
|
}
|
|
75739
76227
|
async ensureSessionFromId(sessionId, consumer = "prompt") {
|
|
75740
|
-
const joinsLiveGeneration = !this.sessionShutdownPromise && (this.sessionPromise !== undefined || this.session !== undefined);
|
|
76228
|
+
const joinsLiveGeneration = !this.sessionShutdownPromise && (this.sessionPromise !== undefined || this.session !== undefined || this.activeCreation !== undefined || this.ownedCreationPromise !== undefined);
|
|
75741
76229
|
if (!this.sessionShutdownPromise && !joinsLiveGeneration)
|
|
75742
76230
|
this.reattachSessionId = sessionId;
|
|
75743
76231
|
const session = await this.ensureSession(consumer);
|
|
@@ -79722,10 +80210,12 @@ init_run();
|
|
|
79722
80210
|
init_run_tool_control_registry();
|
|
79723
80211
|
init_workflow_tool_abort();
|
|
79724
80212
|
init_wiring();
|
|
80213
|
+
init_pending_stage_delivery2();
|
|
79725
80214
|
init_stage_control_registry();
|
|
79726
80215
|
init_stage_queued_user_messages();
|
|
79727
80216
|
init_stage_ui_broker();
|
|
79728
80217
|
init_store();
|
|
80218
|
+
init_workflow_infrastructure_error();
|
|
79729
80219
|
init_admission_binding();
|
|
79730
80220
|
init_definitions();
|
|
79731
80221
|
import { randomUUID as randomUUID24 } from "node:crypto";
|
|
@@ -79808,6 +80298,9 @@ function workerSessionStore(input) {
|
|
|
79808
80298
|
// dist/builtin/workflows/src/workers/stage-watch.ts
|
|
79809
80299
|
init_stage_queued_user_messages();
|
|
79810
80300
|
init_pooled_watch_trace();
|
|
80301
|
+
import {
|
|
80302
|
+
getSessionCommandCatalog
|
|
80303
|
+
} from "@bastani/atomic";
|
|
79811
80304
|
|
|
79812
80305
|
// dist/builtin/workflows/src/workers/stage-delivery-receipts.ts
|
|
79813
80306
|
function queueLengths(event) {
|
|
@@ -79901,6 +80394,167 @@ class StageDeliveryReceipts {
|
|
|
79901
80394
|
|
|
79902
80395
|
// dist/builtin/workflows/src/workers/stage-watch.ts
|
|
79903
80396
|
init_stage_watch_coalesce();
|
|
80397
|
+
|
|
80398
|
+
// dist/builtin/workflows/src/workers/stage-watch-tasks.ts
|
|
80399
|
+
import {
|
|
80400
|
+
getOwnerTaskStore,
|
|
80401
|
+
ownerTaskViewSource,
|
|
80402
|
+
watchOwnerTaskStoreBinding
|
|
80403
|
+
} from "@bastani/atomic";
|
|
80404
|
+
var STAGE_TASKS_INTERVAL_MS = 200;
|
|
80405
|
+
function snapshotStageTasks(source) {
|
|
80406
|
+
const tasks = [...source.tasks];
|
|
80407
|
+
const background = source.backgroundTasks.map((task) => task.ref.taskId);
|
|
80408
|
+
return {
|
|
80409
|
+
tasks,
|
|
80410
|
+
background,
|
|
80411
|
+
settlement: [...source.settlementOrder].map(([id, sequence]) => [id, sequence.toString()]),
|
|
80412
|
+
activity: background.flatMap((id) => {
|
|
80413
|
+
const entries = source.recentActivity(id);
|
|
80414
|
+
const omitted = source.activityOmitted(id);
|
|
80415
|
+
return entries.length === 0 && !omitted ? [] : [{ id, entries, omitted }];
|
|
80416
|
+
}),
|
|
80417
|
+
stdin: tasks.flatMap((task) => task.execution.kind !== "settled" && source.stdinAvailable(task.ref.taskId) ? [task.ref.taskId] : []),
|
|
80418
|
+
statuses: tasks.flatMap((task) => {
|
|
80419
|
+
if (task.kind !== "agent")
|
|
80420
|
+
return [];
|
|
80421
|
+
const entries = [...source.extensionStatuses(task.ref.taskId)];
|
|
80422
|
+
return entries.length === 0 ? [] : [{ id: task.ref.taskId, entries }];
|
|
80423
|
+
})
|
|
80424
|
+
};
|
|
80425
|
+
}
|
|
80426
|
+
async function runStageTaskAction(source, taskId, action) {
|
|
80427
|
+
switch (action.kind) {
|
|
80428
|
+
case "foreground":
|
|
80429
|
+
return { kind: "foreground", result: await source.foregroundTask(taskId) };
|
|
80430
|
+
case "cancel":
|
|
80431
|
+
return { kind: "cancel", result: await source.cancelTask(taskId) };
|
|
80432
|
+
case "input":
|
|
80433
|
+
return { kind: "input", result: await source.writeTaskInput(taskId, action.text) };
|
|
80434
|
+
case "output":
|
|
80435
|
+
return {
|
|
80436
|
+
kind: "output",
|
|
80437
|
+
result: await source.readTaskOutput(taskId, { start: action.start, maximumBytes: action.maximumBytes })
|
|
80438
|
+
};
|
|
80439
|
+
case "detail":
|
|
80440
|
+
return { kind: "detail", detail: await source.taskDetailText(taskId) };
|
|
80441
|
+
case "transcript": {
|
|
80442
|
+
const result = await source.readTaskTranscript(taskId, action.cursor);
|
|
80443
|
+
const streaming = result.ok && action.cursor === undefined ? source.followTaskTranscript(taskId)?.session?.getStreamingMessage?.() : undefined;
|
|
80444
|
+
if (!result.ok || streaming === undefined || streaming.role !== "assistant")
|
|
80445
|
+
return { kind: "transcript", result };
|
|
80446
|
+
const partial = { ...streaming, content: streaming.content.filter((block) => block.type !== "thinking") };
|
|
80447
|
+
return {
|
|
80448
|
+
kind: "transcript",
|
|
80449
|
+
result: { ok: true, value: { ...result.value, messages: [...result.value.messages, partial] } }
|
|
80450
|
+
};
|
|
80451
|
+
}
|
|
80452
|
+
}
|
|
80453
|
+
}
|
|
80454
|
+
function stageTaskSource(handle) {
|
|
80455
|
+
const session = handle.agentSession;
|
|
80456
|
+
const store = session === undefined ? undefined : getOwnerTaskStore(session);
|
|
80457
|
+
return store === undefined ? undefined : ownerTaskViewSource(store);
|
|
80458
|
+
}
|
|
80459
|
+
|
|
80460
|
+
class WatchedStageTasks {
|
|
80461
|
+
handle;
|
|
80462
|
+
send;
|
|
80463
|
+
intervalMs;
|
|
80464
|
+
session;
|
|
80465
|
+
store;
|
|
80466
|
+
unbind;
|
|
80467
|
+
unsubscribe;
|
|
80468
|
+
statusWatches = new Map;
|
|
80469
|
+
transcriptWatches = new Map;
|
|
80470
|
+
timer;
|
|
80471
|
+
disposed = false;
|
|
80472
|
+
constructor(handle, send, intervalMs = STAGE_TASKS_INTERVAL_MS) {
|
|
80473
|
+
this.handle = handle;
|
|
80474
|
+
this.send = send;
|
|
80475
|
+
this.intervalMs = intervalMs;
|
|
80476
|
+
}
|
|
80477
|
+
sync() {
|
|
80478
|
+
if (this.disposed)
|
|
80479
|
+
return;
|
|
80480
|
+
const session = this.handle.agentSession;
|
|
80481
|
+
if (session === undefined || session === this.session)
|
|
80482
|
+
return;
|
|
80483
|
+
this.release();
|
|
80484
|
+
this.session = session;
|
|
80485
|
+
this.unbind = watchOwnerTaskStoreBinding(session, () => this.bindStore());
|
|
80486
|
+
this.bindStore();
|
|
80487
|
+
}
|
|
80488
|
+
flushPending() {
|
|
80489
|
+
if (this.timer === undefined)
|
|
80490
|
+
return;
|
|
80491
|
+
clearTimeout(this.timer);
|
|
80492
|
+
this.timer = undefined;
|
|
80493
|
+
this.flush();
|
|
80494
|
+
}
|
|
80495
|
+
dispose() {
|
|
80496
|
+
this.disposed = true;
|
|
80497
|
+
this.release();
|
|
80498
|
+
}
|
|
80499
|
+
bindStore() {
|
|
80500
|
+
const session = this.session;
|
|
80501
|
+
const store = session === undefined ? undefined : getOwnerTaskStore(session);
|
|
80502
|
+
if (this.disposed || store === undefined || store === this.store)
|
|
80503
|
+
return;
|
|
80504
|
+
this.unsubscribe?.();
|
|
80505
|
+
this.store = store;
|
|
80506
|
+
this.unsubscribe = store.subscribe(() => this.schedule());
|
|
80507
|
+
this.schedule();
|
|
80508
|
+
}
|
|
80509
|
+
schedule() {
|
|
80510
|
+
if (this.disposed || this.timer !== undefined)
|
|
80511
|
+
return;
|
|
80512
|
+
this.timer = setTimeout(() => {
|
|
80513
|
+
this.timer = undefined;
|
|
80514
|
+
this.flush();
|
|
80515
|
+
}, this.intervalMs);
|
|
80516
|
+
this.timer.unref?.();
|
|
80517
|
+
}
|
|
80518
|
+
flush() {
|
|
80519
|
+
const store = this.store;
|
|
80520
|
+
if (this.disposed || store === undefined)
|
|
80521
|
+
return;
|
|
80522
|
+
const source = ownerTaskViewSource(store);
|
|
80523
|
+
const agents = new Set(source.tasks.filter((task) => task.kind === "agent").map((task) => task.ref.taskId));
|
|
80524
|
+
for (const watches of [this.statusWatches, this.transcriptWatches])
|
|
80525
|
+
for (const [id, release] of watches)
|
|
80526
|
+
if (!agents.has(id)) {
|
|
80527
|
+
release();
|
|
80528
|
+
watches.delete(id);
|
|
80529
|
+
}
|
|
80530
|
+
for (const id of agents) {
|
|
80531
|
+
if (!this.statusWatches.has(id))
|
|
80532
|
+
this.statusWatches.set(id, source.watchExtensionStatuses(id, () => this.schedule()));
|
|
80533
|
+
if (!this.transcriptWatches.has(id)) {
|
|
80534
|
+
const session = source.followTaskTranscript(id)?.session;
|
|
80535
|
+
if (session?.subscribe !== undefined)
|
|
80536
|
+
this.transcriptWatches.set(id, session.subscribe(() => this.schedule()));
|
|
80537
|
+
}
|
|
80538
|
+
}
|
|
80539
|
+
this.send(snapshotStageTasks(source));
|
|
80540
|
+
}
|
|
80541
|
+
release() {
|
|
80542
|
+
clearTimeout(this.timer);
|
|
80543
|
+
this.timer = undefined;
|
|
80544
|
+
this.unbind?.();
|
|
80545
|
+
this.unbind = undefined;
|
|
80546
|
+
this.unsubscribe?.();
|
|
80547
|
+
this.unsubscribe = undefined;
|
|
80548
|
+
for (const release of [...this.statusWatches.values(), ...this.transcriptWatches.values()])
|
|
80549
|
+
release();
|
|
80550
|
+
this.statusWatches.clear();
|
|
80551
|
+
this.transcriptWatches.clear();
|
|
80552
|
+
this.store = undefined;
|
|
80553
|
+
this.session = undefined;
|
|
80554
|
+
}
|
|
80555
|
+
}
|
|
80556
|
+
|
|
80557
|
+
// dist/builtin/workflows/src/workers/stage-watch.ts
|
|
79904
80558
|
async function admitStageUserMessage(handle, text, intent, expandPromptTemplates) {
|
|
79905
80559
|
const options = {
|
|
79906
80560
|
...intent === "auto" ? {} : { deliverAs: intent },
|
|
@@ -79963,6 +80617,9 @@ async function admitStageUserMessage(handle, text, intent, expandPromptTemplates
|
|
|
79963
80617
|
}
|
|
79964
80618
|
var DELIVERY_OP_ENTRY = "atomic-pooled-delivery-op";
|
|
79965
80619
|
var DELIVERY_RECEIPT_EVENT2 = "atomic_pooled_delivery_receipt";
|
|
80620
|
+
var STAGE_SESSION_STARTED_EVENT2 = "atomic_pooled_stage_session_started";
|
|
80621
|
+
var STAGE_MESSAGES_EVENT2 = "atomic_pooled_stage_messages";
|
|
80622
|
+
var STAGE_TASKS_EVENT2 = "atomic_pooled_stage_tasks";
|
|
79966
80623
|
function turnUnderway(handle) {
|
|
79967
80624
|
return handle.isStreaming || handle.agentSession?.isStreaming === true || handle.isTurnLoopBusy === true;
|
|
79968
80625
|
}
|
|
@@ -80012,8 +80669,8 @@ class WorkerStageWatches {
|
|
|
80012
80669
|
this.send({ kind: "stage-command-result", commandId: command.commandId, ...this.answer(command) });
|
|
80013
80670
|
return;
|
|
80014
80671
|
}
|
|
80015
|
-
if (command.op === "deliver" || command.op === "pause" || command.op === "resume") {
|
|
80016
|
-
const result = command.op === "deliver" ? this.deliver(command) : command.op === "pause" ? this.pause(command) : this.resume(command);
|
|
80672
|
+
if (command.op === "deliver" || command.op === "pause" || command.op === "resume" || command.op === "session") {
|
|
80673
|
+
const result = command.op === "deliver" ? this.deliver(command) : command.op === "pause" ? this.pause(command) : command.op === "session" ? this.session(command) : this.resume(command);
|
|
80017
80674
|
result.then((outcome) => this.send({ kind: "stage-command-result", commandId: command.commandId, ...outcome }));
|
|
80018
80675
|
return;
|
|
80019
80676
|
}
|
|
@@ -80043,13 +80700,18 @@ class WorkerStageWatches {
|
|
|
80043
80700
|
}
|
|
80044
80701
|
this.close(command.watch);
|
|
80045
80702
|
const batch = [];
|
|
80703
|
+
const started = handle.agentSession !== undefined;
|
|
80704
|
+
const commands = commandCatalog(handle);
|
|
80046
80705
|
const watch = {
|
|
80047
80706
|
handle,
|
|
80048
80707
|
batch,
|
|
80049
80708
|
seq: 0,
|
|
80709
|
+
startedSent: started,
|
|
80050
80710
|
unsubscribe: handle.subscribe((event) => this.record(command.watch, event))
|
|
80051
80711
|
};
|
|
80052
80712
|
this.watches.set(command.watch, watch);
|
|
80713
|
+
watch.tasks = new WatchedStageTasks(handle, (tasks) => this.sendTasks(command.watch, tasks));
|
|
80714
|
+
watch.tasks.sync();
|
|
80053
80715
|
tracePooledWatch("worker.watch.opened", {
|
|
80054
80716
|
watch: command.watch,
|
|
80055
80717
|
status: handle.status,
|
|
@@ -80065,6 +80727,8 @@ class WorkerStageWatches {
|
|
|
80065
80727
|
commandId: command.commandId,
|
|
80066
80728
|
snapshot: {
|
|
80067
80729
|
...snapshot(handle, watch.seq),
|
|
80730
|
+
sessionStarted: started,
|
|
80731
|
+
...commands === undefined ? {} : { commands },
|
|
80068
80732
|
deliveredOps: [...delivered],
|
|
80069
80733
|
turnStarted: handle.isStreaming || this.options.turnStarted?.(handle) === true
|
|
80070
80734
|
}
|
|
@@ -80080,17 +80744,17 @@ class WorkerStageWatches {
|
|
|
80080
80744
|
}
|
|
80081
80745
|
sweep() {
|
|
80082
80746
|
for (const [id, watch] of this.watches) {
|
|
80747
|
+
this.sendStartedOnce(id, watch);
|
|
80748
|
+
watch.tasks?.sync();
|
|
80083
80749
|
const current = this.registry.get(watch.handle.runId, watch.handle.stageId);
|
|
80084
80750
|
if (current !== undefined && current !== watch.handle && !isTerminal(current)) {
|
|
80085
80751
|
tracePooledWatch("worker.watch.handle-replaced", { watch: id });
|
|
80086
|
-
this.
|
|
80087
|
-
this.close(id);
|
|
80752
|
+
this.finish(id);
|
|
80088
80753
|
this.send({ kind: "stage-watch-ended", watch: id, reason: "resync" });
|
|
80089
80754
|
continue;
|
|
80090
80755
|
}
|
|
80091
80756
|
if (isTerminal(watch.handle)) {
|
|
80092
|
-
this.
|
|
80093
|
-
this.close(id);
|
|
80757
|
+
this.finish(id);
|
|
80094
80758
|
this.send({ kind: "stage-watch-ended", watch: id, reason: "stage_finished" });
|
|
80095
80759
|
}
|
|
80096
80760
|
}
|
|
@@ -80100,10 +80764,13 @@ class WorkerStageWatches {
|
|
|
80100
80764
|
for (const receipts of this.receipts.values())
|
|
80101
80765
|
receipts.dispose();
|
|
80102
80766
|
this.receipts.clear();
|
|
80103
|
-
for (const id of [...this.watches.keys()])
|
|
80104
|
-
this.
|
|
80105
|
-
|
|
80106
|
-
|
|
80767
|
+
for (const id of [...this.watches.keys()])
|
|
80768
|
+
this.finish(id);
|
|
80769
|
+
}
|
|
80770
|
+
finish(id) {
|
|
80771
|
+
this.watches.get(id)?.tasks?.flushPending();
|
|
80772
|
+
this.flush(id);
|
|
80773
|
+
this.close(id);
|
|
80107
80774
|
}
|
|
80108
80775
|
question(command) {
|
|
80109
80776
|
const held = this.attempt();
|
|
@@ -80167,6 +80834,47 @@ class WorkerStageWatches {
|
|
|
80167
80834
|
return isTerminal(watch.handle) ? { refusal: "StageNotLive" } : { error: error.message };
|
|
80168
80835
|
}
|
|
80169
80836
|
}
|
|
80837
|
+
async session(command) {
|
|
80838
|
+
const watch = this.airlock(command);
|
|
80839
|
+
if (typeof watch === "string")
|
|
80840
|
+
return { refusal: watch };
|
|
80841
|
+
const request = command.command;
|
|
80842
|
+
if (this.control() !== "running" && !runsWhilePaused(request))
|
|
80843
|
+
return { refusal: "PoolPausedOrQuitting" };
|
|
80844
|
+
const session = watch.handle.agentSession;
|
|
80845
|
+
if (session === undefined)
|
|
80846
|
+
return {
|
|
80847
|
+
error: `Stage "${watch.handle.stageName}" is still starting on its local worker; try again shortly.`
|
|
80848
|
+
};
|
|
80849
|
+
try {
|
|
80850
|
+
switch (request.kind) {
|
|
80851
|
+
case "compact":
|
|
80852
|
+
await session.compact();
|
|
80853
|
+
return {};
|
|
80854
|
+
case "abort-compaction":
|
|
80855
|
+
session.abortCompaction();
|
|
80856
|
+
return {};
|
|
80857
|
+
case "bash":
|
|
80858
|
+
return {
|
|
80859
|
+
bash: await session.executeBash(request.command, undefined, {
|
|
80860
|
+
id: request.id,
|
|
80861
|
+
...request.excludeFromContext === undefined ? {} : { excludeFromContext: request.excludeFromContext }
|
|
80862
|
+
})
|
|
80863
|
+
};
|
|
80864
|
+
case "abort-bash":
|
|
80865
|
+
session.abortBash(request.id);
|
|
80866
|
+
return {};
|
|
80867
|
+
case "task": {
|
|
80868
|
+
const source = stageTaskSource(watch.handle);
|
|
80869
|
+
if (source === undefined)
|
|
80870
|
+
return { error: `Stage "${watch.handle.stageName}" has no background tasks.` };
|
|
80871
|
+
return { task: await runStageTaskAction(source, request.taskId, request.action) };
|
|
80872
|
+
}
|
|
80873
|
+
}
|
|
80874
|
+
} catch (error) {
|
|
80875
|
+
return isTerminal(watch.handle) ? { refusal: "StageNotLive" } : { error: error.message };
|
|
80876
|
+
}
|
|
80877
|
+
}
|
|
80170
80878
|
async resume(command) {
|
|
80171
80879
|
const watch = this.airlock(command);
|
|
80172
80880
|
if (typeof watch === "string")
|
|
@@ -80248,9 +80956,38 @@ class WorkerStageWatches {
|
|
|
80248
80956
|
const watch = this.watches.get(id);
|
|
80249
80957
|
if (watch === undefined)
|
|
80250
80958
|
return;
|
|
80959
|
+
this.sendStartedOnce(id, watch);
|
|
80960
|
+
watch.tasks?.sync();
|
|
80961
|
+
if (event.type === "compaction_end" && event.aborted !== true && event.result !== undefined)
|
|
80962
|
+
this.append(id, watch, {
|
|
80963
|
+
type: STAGE_MESSAGES_EVENT2,
|
|
80964
|
+
messages: [...watch.handle.messages]
|
|
80965
|
+
});
|
|
80966
|
+
this.append(id, watch, event);
|
|
80967
|
+
}
|
|
80968
|
+
append(id, watch, event) {
|
|
80251
80969
|
appendCoalesced(watch.batch, { seq: ++watch.seq, event });
|
|
80252
80970
|
watch.timer ??= setTimeout(() => this.flush(id), STAGE_EVENT_BATCH_INTERVAL_MS);
|
|
80253
80971
|
}
|
|
80972
|
+
sendTasks(id, tasks) {
|
|
80973
|
+
const watch = this.watches.get(id);
|
|
80974
|
+
if (watch === undefined)
|
|
80975
|
+
return;
|
|
80976
|
+
const waiting = watch.batch.findIndex(({ event }) => event.type === STAGE_TASKS_EVENT2);
|
|
80977
|
+
if (waiting >= 0)
|
|
80978
|
+
watch.batch.splice(waiting, 1);
|
|
80979
|
+
this.append(id, watch, { type: STAGE_TASKS_EVENT2, tasks });
|
|
80980
|
+
}
|
|
80981
|
+
sendStartedOnce(id, watch) {
|
|
80982
|
+
if (watch.startedSent || watch.handle.agentSession === undefined)
|
|
80983
|
+
return;
|
|
80984
|
+
watch.startedSent = true;
|
|
80985
|
+
const commands = commandCatalog(watch.handle);
|
|
80986
|
+
this.append(id, watch, {
|
|
80987
|
+
type: STAGE_SESSION_STARTED_EVENT2,
|
|
80988
|
+
...commands === undefined ? {} : { commands }
|
|
80989
|
+
});
|
|
80990
|
+
}
|
|
80254
80991
|
flush(id) {
|
|
80255
80992
|
const watch = this.watches.get(id);
|
|
80256
80993
|
if (watch === undefined)
|
|
@@ -80269,6 +81006,7 @@ class WorkerStageWatches {
|
|
|
80269
81006
|
this.watches.delete(id);
|
|
80270
81007
|
clearTimeout(watch.timer);
|
|
80271
81008
|
watch.unsubscribe();
|
|
81009
|
+
watch.tasks?.dispose();
|
|
80272
81010
|
}
|
|
80273
81011
|
}
|
|
80274
81012
|
function deliveredOps(entries) {
|
|
@@ -80279,6 +81017,16 @@ function deliveredOps(entries) {
|
|
|
80279
81017
|
return typeof op === "string" ? [op] : [];
|
|
80280
81018
|
});
|
|
80281
81019
|
}
|
|
81020
|
+
function commandCatalog(handle) {
|
|
81021
|
+
const session = handle.agentSession;
|
|
81022
|
+
if (session?.resourceLoader === undefined || session.settingsManager === undefined)
|
|
81023
|
+
return;
|
|
81024
|
+
try {
|
|
81025
|
+
return getSessionCommandCatalog(session);
|
|
81026
|
+
} catch {
|
|
81027
|
+
return;
|
|
81028
|
+
}
|
|
81029
|
+
}
|
|
80282
81030
|
function snapshot(handle, seq) {
|
|
80283
81031
|
const streamingMessage = handle.agentSession?.agent?.state.streamingMessage;
|
|
80284
81032
|
return {
|
|
@@ -80416,7 +81164,7 @@ async function runWorker(start) {
|
|
|
80416
81164
|
rootLeaseLost = true;
|
|
80417
81165
|
attemptFenced = true;
|
|
80418
81166
|
receiver?.reject(new WorkAttemptFencedError(reply.error));
|
|
80419
|
-
} else if (reply.error && reply.fenced) {
|
|
81167
|
+
} else if (reply.error && (reply.fenced || workflowInfrastructureFault(reply.error) !== undefined)) {
|
|
80420
81168
|
attemptFenced = true;
|
|
80421
81169
|
receiver?.reject(new WorkAttemptFencedError(reply.error));
|
|
80422
81170
|
} else if (reply.error)
|
|
@@ -80602,7 +81350,8 @@ async function runWorker(start) {
|
|
|
80602
81350
|
...start.admission,
|
|
80603
81351
|
root: start.root,
|
|
80604
81352
|
holder: work.worker,
|
|
80605
|
-
attempt: work
|
|
81353
|
+
attempt: work,
|
|
81354
|
+
...start.stageStartMaxLoadPerCpu === undefined ? {} : { stageStartMaxLoadPerCpu: start.stageStartMaxLoadPerCpu }
|
|
80606
81355
|
}) : undefined;
|
|
80607
81356
|
const baseAdapter = createAgentSessionAdapter({ cwd: String(work.execution.cwd) }, stageUiBroker);
|
|
80608
81357
|
const adapter = {
|
|
@@ -80624,7 +81373,14 @@ async function runWorker(start) {
|
|
|
80624
81373
|
routeCapability: capability,
|
|
80625
81374
|
async deliverPending(deliver, recipient) {
|
|
80626
81375
|
await publication;
|
|
80627
|
-
await request({ kind: "delivery", ...identity, recipient },
|
|
81376
|
+
await untilDrainedOrStalled((progress) => request({ kind: "delivery", ...identity, recipient }, async (from, message) => {
|
|
81377
|
+
progress();
|
|
81378
|
+
try {
|
|
81379
|
+
await deliver(from, message);
|
|
81380
|
+
} finally {
|
|
81381
|
+
progress();
|
|
81382
|
+
}
|
|
81383
|
+
}).then(() => {}));
|
|
80628
81384
|
},
|
|
80629
81385
|
async ready(sessionId) {
|
|
80630
81386
|
await publication;
|
|
@@ -80719,6 +81475,8 @@ async function runWorker(start) {
|
|
|
80719
81475
|
await request({ kind: "controlled", revision: finalControl.revision });
|
|
80720
81476
|
return;
|
|
80721
81477
|
}
|
|
81478
|
+
if (attemptFenced)
|
|
81479
|
+
throw new WorkAttemptFencedError("Work attempt fenced before completion");
|
|
80722
81480
|
await request({ kind: "complete", result });
|
|
80723
81481
|
} catch (error) {
|
|
80724
81482
|
if (!attemptFenced)
|