@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
|
@@ -2413,6 +2413,75 @@ function redactSensitiveText(value2) {
|
|
|
2413
2413
|
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]");
|
|
2414
2414
|
}
|
|
2415
2415
|
|
|
2416
|
+
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
2417
|
+
function isInfrastructureError(value2) {
|
|
2418
|
+
if (value2 instanceof WorkflowInfrastructureError)
|
|
2419
|
+
return true;
|
|
2420
|
+
if (typeof value2 !== "object" || value2 === null)
|
|
2421
|
+
return false;
|
|
2422
|
+
const candidate = value2;
|
|
2423
|
+
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
2424
|
+
}
|
|
2425
|
+
function isRetryableWorkflowError(error) {
|
|
2426
|
+
let current = error;
|
|
2427
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
|
|
2428
|
+
if (isInfrastructureError(current))
|
|
2429
|
+
return true;
|
|
2430
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
2431
|
+
}
|
|
2432
|
+
return false;
|
|
2433
|
+
}
|
|
2434
|
+
function workflowInfrastructureFault(message) {
|
|
2435
|
+
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
2436
|
+
}
|
|
2437
|
+
function asWorkflowInfrastructureError(error) {
|
|
2438
|
+
if (isInfrastructureError(error))
|
|
2439
|
+
return error;
|
|
2440
|
+
if (!(error instanceof Error))
|
|
2441
|
+
return;
|
|
2442
|
+
const code = workflowInfrastructureFault(error.message);
|
|
2443
|
+
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
2444
|
+
}
|
|
2445
|
+
function failedOnInfrastructureFault(result) {
|
|
2446
|
+
if (result.status !== "failed")
|
|
2447
|
+
return false;
|
|
2448
|
+
const names = (value2) => typeof value2 === "string" && (WORKFLOW_INFRASTRUCTURE_FAULTS.has(value2) || workflowInfrastructureFault(value2) !== undefined);
|
|
2449
|
+
const failure = result.failure;
|
|
2450
|
+
if (names(failure?.code) || names(result.error))
|
|
2451
|
+
return true;
|
|
2452
|
+
return Array.isArray(result.stages) && result.stages.some((stage) => stage?.status === "failed" && (names(stage.failureCode) || names(stage.error)));
|
|
2453
|
+
}
|
|
2454
|
+
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", WORKFLOW_INFRASTRUCTURE_FAULTS, MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
2455
|
+
var init_workflow_infrastructure_error = __esm(() => {
|
|
2456
|
+
WORKFLOW_INFRASTRUCTURE_FAULTS = new Set([
|
|
2457
|
+
"worker_lost",
|
|
2458
|
+
"worker_cleanup_unconfirmed",
|
|
2459
|
+
"worker_retry_limit",
|
|
2460
|
+
"worker_startup_failed",
|
|
2461
|
+
"stale_work_lease",
|
|
2462
|
+
"intercom_unavailable",
|
|
2463
|
+
"storage_unavailable"
|
|
2464
|
+
]);
|
|
2465
|
+
FAULT_PATTERNS = [
|
|
2466
|
+
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
2467
|
+
[/Local worker retry limit/, "worker_retry_limit"],
|
|
2468
|
+
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
2469
|
+
[/Worker exited before delivery acknowledgement|Local worker pool coordinator exited/, "worker_lost"],
|
|
2470
|
+
[/Stale work lease|Stale resource admission attempt/, "stale_work_lease"],
|
|
2471
|
+
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
2472
|
+
[/Storage unavailable/, "storage_unavailable"]
|
|
2473
|
+
];
|
|
2474
|
+
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
2475
|
+
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
2476
|
+
retryable = true;
|
|
2477
|
+
code;
|
|
2478
|
+
constructor(code, message, options) {
|
|
2479
|
+
super(message, options);
|
|
2480
|
+
this.code = code;
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2483
|
+
});
|
|
2484
|
+
|
|
2416
2485
|
// dist/builtin/workflows/src/shared/workflow-failures-decisions.ts
|
|
2417
2486
|
function authDecision(code) {
|
|
2418
2487
|
if (code === "invalid_api_key") {
|
|
@@ -2501,6 +2570,16 @@ function cancelledDecision() {
|
|
|
2501
2570
|
disposition: "terminal_killed"
|
|
2502
2571
|
};
|
|
2503
2572
|
}
|
|
2573
|
+
function infrastructureFaultDecision(code) {
|
|
2574
|
+
return {
|
|
2575
|
+
kind: "unknown",
|
|
2576
|
+
code,
|
|
2577
|
+
retryable: true,
|
|
2578
|
+
resumable: true,
|
|
2579
|
+
recoverability: "recoverable",
|
|
2580
|
+
disposition: "terminal_failed"
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2504
2583
|
function unknownDecision() {
|
|
2505
2584
|
return {
|
|
2506
2585
|
kind: "unknown",
|
|
@@ -2528,6 +2607,8 @@ function strongDecisionFromNormalizedCode(normalized, retryAfterMs) {
|
|
|
2528
2607
|
disposition: "active_blocked"
|
|
2529
2608
|
};
|
|
2530
2609
|
}
|
|
2610
|
+
if (WORKFLOW_INFRASTRUCTURE_FAULTS.has(normalized))
|
|
2611
|
+
return infrastructureFaultDecision(normalized);
|
|
2531
2612
|
if (CANCELLED_CODES.has(normalized))
|
|
2532
2613
|
return cancelledDecision();
|
|
2533
2614
|
if (INVALID_API_KEY_CODES.has(normalized))
|
|
@@ -2640,6 +2721,9 @@ function classificationFromNormalizedCode(normalized, retryAfterMs, source, mess
|
|
|
2640
2721
|
return weak !== undefined ? { weak: classificationForDecision(weak, source, message, "weak_signal") } : {};
|
|
2641
2722
|
}
|
|
2642
2723
|
function fallbackDecisionFromMessage(message, name) {
|
|
2724
|
+
const fault = workflowInfrastructureFault(message);
|
|
2725
|
+
if (fault !== undefined)
|
|
2726
|
+
return infrastructureFaultDecision(fault);
|
|
2643
2727
|
const tokens = tokenize(message);
|
|
2644
2728
|
const decision = decisionFromMessageTokens(tokens, name);
|
|
2645
2729
|
const providerAuthDecision = classifyFallbackProviderAuthMessage(message, tokens);
|
|
@@ -2654,6 +2738,7 @@ function fallbackDecisionFromMessage(message, name) {
|
|
|
2654
2738
|
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;
|
|
2655
2739
|
var init_workflow_failures_decisions = __esm(() => {
|
|
2656
2740
|
init_workflow_failures_contract();
|
|
2741
|
+
init_workflow_infrastructure_error();
|
|
2657
2742
|
INVALID_API_KEY_CODES = new Set([
|
|
2658
2743
|
"401",
|
|
2659
2744
|
"invalid_api_key",
|
|
@@ -2841,6 +2926,13 @@ function decisionOfRecordedCode(code, retryAfterMs) {
|
|
|
2841
2926
|
case "cancelled":
|
|
2842
2927
|
return cancelledDecision();
|
|
2843
2928
|
case "pending_stage_delivery_failed":
|
|
2929
|
+
case "worker_lost":
|
|
2930
|
+
case "worker_cleanup_unconfirmed":
|
|
2931
|
+
case "worker_retry_limit":
|
|
2932
|
+
case "worker_startup_failed":
|
|
2933
|
+
case "stale_work_lease":
|
|
2934
|
+
case "intercom_unavailable":
|
|
2935
|
+
case "storage_unavailable":
|
|
2844
2936
|
return strongDecisionFromNormalizedCode(code, retryAfterMs);
|
|
2845
2937
|
case "unknown":
|
|
2846
2938
|
return;
|
|
@@ -11809,7 +11901,7 @@ class JournalDurableBackend {
|
|
|
11809
11901
|
timer;
|
|
11810
11902
|
state = "open";
|
|
11811
11903
|
closing;
|
|
11812
|
-
renewing;
|
|
11904
|
+
renewing = new Map;
|
|
11813
11905
|
mutationContext = new AsyncLocalStorage3;
|
|
11814
11906
|
processExitCleanup;
|
|
11815
11907
|
unregisterExecutionStorages = registerExecutionStorages(this.executionContext, this.mutationContext);
|
|
@@ -12530,27 +12622,21 @@ class JournalDurableBackend {
|
|
|
12530
12622
|
yield this.enqueue(runId, () => this.deleteOwned(runId));
|
|
12531
12623
|
}
|
|
12532
12624
|
renewLeases() {
|
|
12533
|
-
if (this.renewing !== undefined)
|
|
12534
|
-
return this.renewing;
|
|
12535
12625
|
if (this.state !== "open")
|
|
12536
12626
|
return Promise.resolve();
|
|
12537
|
-
this.renewing = this.renewOwnedLeases().finally(() => {
|
|
12538
|
-
this.renewing = undefined;
|
|
12539
|
-
});
|
|
12540
|
-
return this.renewing;
|
|
12541
|
-
}
|
|
12542
|
-
async renewOwnedLeases() {
|
|
12543
12627
|
for (const [runId, lease] of this.leases) {
|
|
12544
|
-
if (this.
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
} catch (error) {
|
|
12549
|
-
if (error instanceof Error)
|
|
12550
|
-
this.lost.set(runId, error);
|
|
12628
|
+
if (this.renewing.has(runId))
|
|
12629
|
+
continue;
|
|
12630
|
+
const renewal = this.serialize(runId, () => this.renewLease(runId, lease), false).catch((error) => {
|
|
12631
|
+
this.lost.set(runId, error);
|
|
12551
12632
|
this.dropLease(runId);
|
|
12552
|
-
}
|
|
12633
|
+
}).finally(() => {
|
|
12634
|
+
if (this.renewing.get(runId) === renewal)
|
|
12635
|
+
this.renewing.delete(runId);
|
|
12636
|
+
});
|
|
12637
|
+
this.renewing.set(runId, renewal);
|
|
12553
12638
|
}
|
|
12639
|
+
return Promise.all(this.renewing.values()).then(() => {});
|
|
12554
12640
|
}
|
|
12555
12641
|
*renewLease(runId, lease) {
|
|
12556
12642
|
if (this.leases.get(runId) !== lease || this.lost.has(runId))
|
|
@@ -12558,9 +12644,10 @@ class JournalDurableBackend {
|
|
|
12558
12644
|
try {
|
|
12559
12645
|
yield* invoke(() => this.journal.renew(lease));
|
|
12560
12646
|
} catch (error) {
|
|
12647
|
+
if (!(error instanceof StaleLeaseError))
|
|
12648
|
+
return;
|
|
12561
12649
|
if (this.leases.get(runId) === lease) {
|
|
12562
|
-
|
|
12563
|
-
this.lost.set(runId, yield* this.mapOwnership(error, runId));
|
|
12650
|
+
this.lost.set(runId, yield* this.mapOwnership(error, runId));
|
|
12564
12651
|
this.dropLease(runId);
|
|
12565
12652
|
}
|
|
12566
12653
|
}
|
|
@@ -12654,7 +12741,7 @@ class JournalDurableBackend {
|
|
|
12654
12741
|
}
|
|
12655
12742
|
async drainAndClose() {
|
|
12656
12743
|
try {
|
|
12657
|
-
await this.renewing;
|
|
12744
|
+
await Promise.all(this.renewing.values());
|
|
12658
12745
|
while (this.pending.size > 0)
|
|
12659
12746
|
await Promise.all(this.pending.values());
|
|
12660
12747
|
for (const runId of this.leases.keys())
|
|
@@ -17029,7 +17116,7 @@ class SqlResourceAdmission {
|
|
|
17029
17116
|
for (const value2 of Object.values(limits ?? {}))
|
|
17030
17117
|
if (!Number.isSafeInteger(value2) || value2 < 1)
|
|
17031
17118
|
throw new Error("Invalid resource limit");
|
|
17032
|
-
for (const value2 of Object.values(options.host ?? {}))
|
|
17119
|
+
for (const value2 of [...Object.values(options.host ?? {}), options.stageStartMaxLoadPerCpu ?? 0])
|
|
17033
17120
|
if (!Number.isFinite(value2) || value2 < 0)
|
|
17034
17121
|
throw new Error("Invalid host admission threshold");
|
|
17035
17122
|
const admission = new SqlResourceAdmission(storage, {
|
|
@@ -17047,6 +17134,8 @@ class SqlResourceAdmission {
|
|
|
17047
17134
|
for (const column of ["owner", "attempt", "process_identity"])
|
|
17048
17135
|
if (!columns.some((entry) => entry.name === column))
|
|
17049
17136
|
await tx.exec(`ALTER TABLE ${admission.permits} ADD COLUMN ${column} TEXT`);
|
|
17137
|
+
if (!columns.some((entry) => entry.name === "granted_at"))
|
|
17138
|
+
await tx.exec(`ALTER TABLE ${admission.permits} ADD COLUMN granted_at INTEGER`);
|
|
17050
17139
|
await tx.exec(`CREATE INDEX IF NOT EXISTS ${admission.permits}_owner ON ${admission.permits}(owner, state);
|
|
17051
17140
|
CREATE INDEX IF NOT EXISTS ${admission.permits}_state ON ${admission.permits}(state)`);
|
|
17052
17141
|
if (!(await tx.all(`PRAGMA table_info(${admission.owners})`)).some((entry) => entry.name === "boot"))
|
|
@@ -17076,14 +17165,24 @@ class SqlResourceAdmission {
|
|
|
17076
17165
|
await admission.reconcile();
|
|
17077
17166
|
return admission;
|
|
17078
17167
|
}
|
|
17168
|
+
sampleHost() {
|
|
17169
|
+
return this.options.sampleHost?.() ?? {
|
|
17170
|
+
freeMemoryBytes: freemem(),
|
|
17171
|
+
load: process.platform === "win32" ? undefined : loadavg()[0] / cpus().length
|
|
17172
|
+
};
|
|
17173
|
+
}
|
|
17174
|
+
stageStartPressure(kind, delegated) {
|
|
17175
|
+
const threshold = this.options.stageStartMaxLoadPerCpu;
|
|
17176
|
+
if (kind !== "session" || delegated === true || threshold === undefined || threshold === 0)
|
|
17177
|
+
return false;
|
|
17178
|
+
const load = this.sampleHost().load;
|
|
17179
|
+
return load !== undefined && load > threshold;
|
|
17180
|
+
}
|
|
17079
17181
|
hostReason() {
|
|
17080
17182
|
const host = this.options.host;
|
|
17081
17183
|
if (!host)
|
|
17082
17184
|
return;
|
|
17083
|
-
const sample = this.
|
|
17084
|
-
freeMemoryBytes: freemem(),
|
|
17085
|
-
load: process.platform === "win32" ? undefined : loadavg()[0] / cpus().length
|
|
17086
|
-
};
|
|
17185
|
+
const sample = this.sampleHost();
|
|
17087
17186
|
if (host.minFreeMemoryBytes !== undefined) {
|
|
17088
17187
|
if (sample.freeMemoryBytes === undefined)
|
|
17089
17188
|
return "host memory unsupported";
|
|
@@ -17097,21 +17196,32 @@ class SqlResourceAdmission {
|
|
|
17097
17196
|
return "host load";
|
|
17098
17197
|
}
|
|
17099
17198
|
}
|
|
17100
|
-
async
|
|
17199
|
+
async attemptStanding(tx) {
|
|
17101
17200
|
const { root, attempt } = this.options;
|
|
17102
17201
|
if (!attempt)
|
|
17103
|
-
return;
|
|
17104
|
-
const work = await tx.get(`SELECT
|
|
17202
|
+
return "current";
|
|
17203
|
+
const work = await tx.get(`SELECT (w.expires_at < ${NOW_MS} OR l.renewed_at + p.timeout < ${NOW_MS}) AS late
|
|
17204
|
+
FROM ${this.storage.tables.runs}_work w JOIN ${this.storage.tables.leases} l ON l.run_id = w.root
|
|
17105
17205
|
JOIN ${this.storage.tables.runs}_pool p ON p.root = w.root JOIN ${this.storage.tables.runs} r ON r.run_id = w.root
|
|
17106
17206
|
WHERE w.id = ? AND w.root = ? AND w.generation = ? AND w.epoch = ? AND w.state = 'leased' AND r.status IN ('running', 'paused')
|
|
17107
|
-
AND
|
|
17108
|
-
AND l.epoch = w.epoch AND l.renewed_at + p.timeout >= CAST(unixepoch('subsec') * 1000 AS INTEGER)`, attempt.id, root, attempt.generation, attempt.epoch);
|
|
17207
|
+
AND l.epoch = w.epoch`, attempt.id, root, attempt.generation, attempt.epoch);
|
|
17109
17208
|
if (!work)
|
|
17209
|
+
return "stale";
|
|
17210
|
+
return Number(work.late) === 1 ? "late" : "current";
|
|
17211
|
+
}
|
|
17212
|
+
async assertCurrentAttempt(tx) {
|
|
17213
|
+
const standing = await this.attemptStanding(tx);
|
|
17214
|
+
if (standing === "stale")
|
|
17110
17215
|
throw new Error("Stale resource admission attempt");
|
|
17216
|
+
return standing === "current";
|
|
17111
17217
|
}
|
|
17112
17218
|
async validate(signal) {
|
|
17113
|
-
|
|
17114
|
-
|
|
17219
|
+
for (;; ) {
|
|
17220
|
+
signal?.throwIfAborted();
|
|
17221
|
+
if (await this.storage.transaction((tx) => this.assertCurrentAttempt(tx)))
|
|
17222
|
+
return;
|
|
17223
|
+
await delay(LATE_ATTEMPT_POLL_MS, undefined, { signal });
|
|
17224
|
+
}
|
|
17115
17225
|
}
|
|
17116
17226
|
async acquire(kind, signal, request) {
|
|
17117
17227
|
signal?.throwIfAborted();
|
|
@@ -17145,11 +17255,19 @@ class SqlResourceAdmission {
|
|
|
17145
17255
|
this.nextReconciliation = performance.now() + 1000;
|
|
17146
17256
|
}
|
|
17147
17257
|
const hostReason = this.hostReason();
|
|
17258
|
+
const pressure = this.stageStartPressure(kind, request?.delegated);
|
|
17148
17259
|
const granted = await this.storage.transaction(async (tx) => {
|
|
17149
17260
|
await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
|
|
17150
17261
|
const { root } = this.options;
|
|
17151
|
-
await this.assertCurrentAttempt(tx)
|
|
17262
|
+
if (!await this.assertCurrentAttempt(tx)) {
|
|
17263
|
+
const waiting = await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE operation = ? AND state = 'waiting'`, LATE_ATTEMPT_REASON, operation);
|
|
17264
|
+
if (waiting.changes !== 1)
|
|
17265
|
+
throw new Error("Resource admission holder was stopped");
|
|
17266
|
+
return false;
|
|
17267
|
+
}
|
|
17152
17268
|
let reason = hostReason;
|
|
17269
|
+
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)))
|
|
17270
|
+
reason ??= STAGE_START_PRESSURE_REASON;
|
|
17153
17271
|
const controls = `${this.storage.tables.runs}_pool_control`;
|
|
17154
17272
|
if (await tx.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?", controls)) {
|
|
17155
17273
|
const control = await tx.get(`SELECT state FROM ${controls} WHERE root = ?`, root);
|
|
@@ -17164,13 +17282,14 @@ class SqlResourceAdmission {
|
|
|
17164
17282
|
const rootClause = scope === "user" ? "" : "AND root = ?";
|
|
17165
17283
|
const args = scope === "user" ? [kind] : [kind, root];
|
|
17166
17284
|
const count = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted'`, ...args);
|
|
17167
|
-
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);
|
|
17285
|
+
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);
|
|
17168
17286
|
if (Number(count?.count) >= limit || older)
|
|
17169
17287
|
reason ??= `${scope} ${kind}`;
|
|
17170
17288
|
}
|
|
17171
17289
|
if (reason && request?.delegated)
|
|
17172
17290
|
throw new Error(`Delegated session cannot be admitted without capacity headroom: ${reason}`);
|
|
17173
|
-
const
|
|
17291
|
+
const stageStart = kind === "session" && request?.delegated !== true;
|
|
17292
|
+
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);
|
|
17174
17293
|
if (updated.changes !== 1)
|
|
17175
17294
|
throw new Error("Resource admission holder was stopped");
|
|
17176
17295
|
return !reason;
|
|
@@ -17330,7 +17449,7 @@ async function reapProcessGroups(journal, root, scope) {
|
|
|
17330
17449
|
return { survivors: [], unprobeable: [] };
|
|
17331
17450
|
return settleProcessGroups(storage, root, scope, true);
|
|
17332
17451
|
}
|
|
17333
|
-
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)";
|
|
17452
|
+
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";
|
|
17334
17453
|
var init_resource_admission = __esm(() => {
|
|
17335
17454
|
init_internal();
|
|
17336
17455
|
init_sql_run_journal();
|
|
@@ -59903,14 +60022,23 @@ class SqlPoolQueue {
|
|
|
59903
60022
|
}
|
|
59904
60023
|
await tx.run(`UPDATE ${this.meta} SET version = ?`, POOL_SCHEMA_VERSION);
|
|
59905
60024
|
}
|
|
60025
|
+
leaseRow(tx, lease) {
|
|
60026
|
+
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);
|
|
60027
|
+
}
|
|
59906
60028
|
async authority(tx, lease, timeout) {
|
|
59907
|
-
const row = await
|
|
60029
|
+
const row = await this.leaseRow(tx, lease);
|
|
59908
60030
|
if (row?.timeout === null && timeout === undefined)
|
|
59909
60031
|
throw new Error("Pool not initialized");
|
|
59910
60032
|
if (!row || row.epoch !== lease.epoch || row.holder_id !== lease.holderId || isWorkflowLeaseExpired(row.renewed_at, row.timeout ?? timeout ?? 0, row.now))
|
|
59911
60033
|
throw new StaleLeaseError(lease.runId, lease.epoch, Number(row?.epoch ?? 0));
|
|
59912
60034
|
return row;
|
|
59913
60035
|
}
|
|
60036
|
+
async rootLease(lease, timeout) {
|
|
60037
|
+
const row = await this.storage.read((executor) => this.leaseRow(executor, lease));
|
|
60038
|
+
if (!row || row.epoch !== lease.epoch || row.holder_id !== lease.holderId)
|
|
60039
|
+
return "lost";
|
|
60040
|
+
return isWorkflowLeaseExpired(row.renewed_at, row.timeout ?? timeout, row.now) ? "late" : "current";
|
|
60041
|
+
}
|
|
59914
60042
|
async initialize(lease, coordinatorTimeoutMs) {
|
|
59915
60043
|
positive(coordinatorTimeoutMs);
|
|
59916
60044
|
lease = snapshotLease(lease);
|
|
@@ -59922,6 +60050,9 @@ class SqlPoolQueue {
|
|
|
59922
60050
|
throw new Error("Pool configuration is immutable");
|
|
59923
60051
|
});
|
|
59924
60052
|
}
|
|
60053
|
+
async initialized(root) {
|
|
60054
|
+
return await this.storage.read((executor) => executor.get(`SELECT 1 AS held FROM ${this.roots} WHERE root = ?`, root)) !== undefined;
|
|
60055
|
+
}
|
|
59925
60056
|
async control(lease) {
|
|
59926
60057
|
return this.transaction(async (tx) => {
|
|
59927
60058
|
await this.authority(tx, lease);
|
|
@@ -60316,6 +60447,21 @@ class SqlPoolQueue {
|
|
|
60316
60447
|
return row ? JSON.parse(String(row.result)) : undefined;
|
|
60317
60448
|
});
|
|
60318
60449
|
}
|
|
60450
|
+
async reopenCompleted(lease, id, rerun) {
|
|
60451
|
+
lease = snapshotLease(lease);
|
|
60452
|
+
return this.transaction(async (tx) => {
|
|
60453
|
+
await this.authority(tx, lease);
|
|
60454
|
+
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, id, lease.runId);
|
|
60455
|
+
if (row?.state !== "completed" || row.epoch >= lease.epoch)
|
|
60456
|
+
return;
|
|
60457
|
+
const stored = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, id);
|
|
60458
|
+
if (!stored || !rerun(JSON.parse(String(stored.result))))
|
|
60459
|
+
return;
|
|
60460
|
+
await tx.run(`DELETE FROM ${this.work}_results WHERE work = ?`, id);
|
|
60461
|
+
await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0, epoch = ? WHERE id = ?`, lease.epoch, id);
|
|
60462
|
+
return fromRow({ ...row, state: "ready", worker: null, expires_at: 0, epoch: lease.epoch });
|
|
60463
|
+
});
|
|
60464
|
+
}
|
|
60319
60465
|
async expire(lease, token) {
|
|
60320
60466
|
lease = snapshotLease(lease);
|
|
60321
60467
|
token = { ...token };
|
|
@@ -60437,7 +60583,7 @@ function reportsClosedSession(error) {
|
|
|
60437
60583
|
}
|
|
60438
60584
|
function isSessionClosedError(error) {
|
|
60439
60585
|
let current = error;
|
|
60440
|
-
for (let depth = 0;depth <
|
|
60586
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined; depth++) {
|
|
60441
60587
|
try {
|
|
60442
60588
|
if (reportsClosedSession(current))
|
|
60443
60589
|
return true;
|
|
@@ -60448,7 +60594,7 @@ function isSessionClosedError(error) {
|
|
|
60448
60594
|
}
|
|
60449
60595
|
return false;
|
|
60450
60596
|
}
|
|
60451
|
-
var
|
|
60597
|
+
var MAX_CAUSE_DEPTH2 = 8;
|
|
60452
60598
|
var init_session_closed_error = () => {};
|
|
60453
60599
|
|
|
60454
60600
|
// dist/builtin/workflows/src/shared/external-run-routes.ts
|
|
@@ -64772,57 +64918,6 @@ var init_sdk_intercom = __esm(() => {
|
|
|
64772
64918
|
owners2 = new WeakMap;
|
|
64773
64919
|
});
|
|
64774
64920
|
|
|
64775
|
-
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
64776
|
-
function isInfrastructureError(value2) {
|
|
64777
|
-
if (value2 instanceof WorkflowInfrastructureError)
|
|
64778
|
-
return true;
|
|
64779
|
-
if (typeof value2 !== "object" || value2 === null)
|
|
64780
|
-
return false;
|
|
64781
|
-
const candidate = value2;
|
|
64782
|
-
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
64783
|
-
}
|
|
64784
|
-
function isRetryableWorkflowError(error) {
|
|
64785
|
-
let current = error;
|
|
64786
|
-
for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined && current !== null; depth++) {
|
|
64787
|
-
if (isInfrastructureError(current))
|
|
64788
|
-
return true;
|
|
64789
|
-
current = current instanceof Error ? current.cause : undefined;
|
|
64790
|
-
}
|
|
64791
|
-
return false;
|
|
64792
|
-
}
|
|
64793
|
-
function workflowInfrastructureFault(message) {
|
|
64794
|
-
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
64795
|
-
}
|
|
64796
|
-
function asWorkflowInfrastructureError(error) {
|
|
64797
|
-
if (isInfrastructureError(error))
|
|
64798
|
-
return error;
|
|
64799
|
-
if (!(error instanceof Error))
|
|
64800
|
-
return;
|
|
64801
|
-
const code = workflowInfrastructureFault(error.message);
|
|
64802
|
-
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
64803
|
-
}
|
|
64804
|
-
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH2 = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
64805
|
-
var init_workflow_infrastructure_error = __esm(() => {
|
|
64806
|
-
FAULT_PATTERNS = [
|
|
64807
|
-
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
64808
|
-
[/Local worker retry limit/, "worker_retry_limit"],
|
|
64809
|
-
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
64810
|
-
[/Worker exited before delivery acknowledgement|Local worker pool coordinator exited/, "worker_lost"],
|
|
64811
|
-
[/Stale work lease/, "stale_work_lease"],
|
|
64812
|
-
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
64813
|
-
[/Storage unavailable/, "storage_unavailable"]
|
|
64814
|
-
];
|
|
64815
|
-
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
64816
|
-
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
64817
|
-
retryable = true;
|
|
64818
|
-
code;
|
|
64819
|
-
constructor(code, message, options) {
|
|
64820
|
-
super(message, options);
|
|
64821
|
-
this.code = code;
|
|
64822
|
-
}
|
|
64823
|
-
};
|
|
64824
|
-
});
|
|
64825
|
-
|
|
64826
64921
|
// dist/builtin/workflows/src/workers/coordinator-protocol.ts
|
|
64827
64922
|
var POOL_COORDINATOR_ROLE = "pool-coordinator", POOL_SUMMARY_INTERVAL_MS = 250;
|
|
64828
64923
|
|
|
@@ -65106,6 +65201,16 @@ class RateLimitObservationOutbox {
|
|
|
65106
65201
|
}
|
|
65107
65202
|
var RATE_LIMIT_SHARE_INTERVAL_MS = 250;
|
|
65108
65203
|
|
|
65204
|
+
// dist/builtin/workflows/src/workers/stage-session-commands.ts
|
|
65205
|
+
function runsWhilePaused(command) {
|
|
65206
|
+
if (command.kind === "abort-bash" || command.kind === "abort-compaction")
|
|
65207
|
+
return true;
|
|
65208
|
+
if (command.kind !== "task")
|
|
65209
|
+
return false;
|
|
65210
|
+
const action = command.action.kind;
|
|
65211
|
+
return action === "cancel" || action === "output" || action === "detail" || action === "transcript";
|
|
65212
|
+
}
|
|
65213
|
+
|
|
65109
65214
|
// dist/builtin/workflows/src/workers/stage-watch-coalesce.ts
|
|
65110
65215
|
function streamedDelta(event) {
|
|
65111
65216
|
if (event.type !== "message_update")
|
|
@@ -65432,6 +65537,7 @@ class PoolCoordinator {
|
|
|
65432
65537
|
closing;
|
|
65433
65538
|
replacements = 0;
|
|
65434
65539
|
rootLeaseLost = false;
|
|
65540
|
+
lateRoot;
|
|
65435
65541
|
attemptBase = new Map;
|
|
65436
65542
|
constructor(port) {
|
|
65437
65543
|
this.port = port;
|
|
@@ -65445,6 +65551,47 @@ class PoolCoordinator {
|
|
|
65445
65551
|
await this.journal?.close().catch(() => {});
|
|
65446
65552
|
await this.durable?.close().catch(() => {});
|
|
65447
65553
|
}
|
|
65554
|
+
async whileRootLate(queue, action, resume) {
|
|
65555
|
+
for (let waited = false;; ) {
|
|
65556
|
+
try {
|
|
65557
|
+
if (waited)
|
|
65558
|
+
await resume?.();
|
|
65559
|
+
return await action();
|
|
65560
|
+
} catch (error) {
|
|
65561
|
+
if (!(error instanceof Error) || !isRootLeaseLost(error) || !await this.rootRenewal(queue))
|
|
65562
|
+
throw error;
|
|
65563
|
+
waited = true;
|
|
65564
|
+
}
|
|
65565
|
+
}
|
|
65566
|
+
}
|
|
65567
|
+
rootRenewal(queue) {
|
|
65568
|
+
this.lateRoot ??= this.awaitRootRenewal(queue).finally(() => {
|
|
65569
|
+
this.lateRoot = undefined;
|
|
65570
|
+
});
|
|
65571
|
+
return this.lateRoot;
|
|
65572
|
+
}
|
|
65573
|
+
async awaitRootRenewal(queue) {
|
|
65574
|
+
const lease = this.lease;
|
|
65575
|
+
const since = performance.now();
|
|
65576
|
+
let late = false;
|
|
65577
|
+
try {
|
|
65578
|
+
for (;; ) {
|
|
65579
|
+
if (this.closed)
|
|
65580
|
+
return false;
|
|
65581
|
+
const lost = await this.remote?.fresh(lease).then(() => false, () => true);
|
|
65582
|
+
if (lost)
|
|
65583
|
+
return false;
|
|
65584
|
+
const standing = await queue.rootLease(lease, COORDINATOR_LEASE_MS);
|
|
65585
|
+
if (standing !== "late")
|
|
65586
|
+
return standing === "current";
|
|
65587
|
+
late = true;
|
|
65588
|
+
await delay2(LATE_ROOT_POLL_MS);
|
|
65589
|
+
}
|
|
65590
|
+
} finally {
|
|
65591
|
+
if (late)
|
|
65592
|
+
this.stalledMs += performance.now() - since;
|
|
65593
|
+
}
|
|
65594
|
+
}
|
|
65448
65595
|
receive(message) {
|
|
65449
65596
|
if (message.kind === "request-reply") {
|
|
65450
65597
|
const pending = this.requests.get(message.id);
|
|
@@ -65513,6 +65660,8 @@ class PoolCoordinator {
|
|
|
65513
65660
|
return this.stageAnswer(command.runId, command.stageId, command.answer);
|
|
65514
65661
|
case "stage-pause":
|
|
65515
65662
|
return this.stageControl(command.watch, { op: "pause" });
|
|
65663
|
+
case "stage-session":
|
|
65664
|
+
return this.stageSession(command.watch, command.command);
|
|
65516
65665
|
case "stage-resume":
|
|
65517
65666
|
return this.stageControl(command.watch, {
|
|
65518
65667
|
op: "resume",
|
|
@@ -65542,8 +65691,8 @@ class PoolCoordinator {
|
|
|
65542
65691
|
this.usageTotal = await this.usageLedger.total(root);
|
|
65543
65692
|
this.lease = lease;
|
|
65544
65693
|
const queue = await openSqlPoolQueue(this.journal, this.remote);
|
|
65545
|
-
await queue.initialize(lease, COORDINATOR_LEASE_MS);
|
|
65546
|
-
await queue.drainOutbox(lease);
|
|
65694
|
+
await this.whileRootLate(queue, () => queue.initialize(lease, COORDINATOR_LEASE_MS));
|
|
65695
|
+
await this.whileRootLate(queue, () => queue.drainOutbox(lease));
|
|
65547
65696
|
if (this.remote !== undefined) {
|
|
65548
65697
|
const remote = this.remote;
|
|
65549
65698
|
this.mirrorTimer = setInterval(() => void remote.fresh(lease, 0).catch(() => {}), MIRROR_INTERVAL_MS).unref();
|
|
@@ -65552,10 +65701,10 @@ class PoolCoordinator {
|
|
|
65552
65701
|
for (const work of await queue.inspect(root))
|
|
65553
65702
|
if (work.state === "leased" && work.epoch < lease.epoch && (await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
|
|
65554
65703
|
retained.push(work);
|
|
65555
|
-
await queue.releasePreviousIncarnations(lease, retained.map((work) => work.id));
|
|
65704
|
+
await this.whileRootLate(queue, () => queue.releasePreviousIncarnations(lease, retained.map((work) => work.id)));
|
|
65556
65705
|
for (;; ) {
|
|
65557
65706
|
const intended = this.desiredControl ?? "running";
|
|
65558
|
-
await queue.setControl(lease, intended);
|
|
65707
|
+
await this.whileRootLate(queue, () => queue.setControl(lease, intended));
|
|
65559
65708
|
if (intended === (this.desiredControl ?? "running"))
|
|
65560
65709
|
break;
|
|
65561
65710
|
}
|
|
@@ -65591,7 +65740,7 @@ class PoolCoordinator {
|
|
|
65591
65740
|
return this.retainedTransition(async () => {
|
|
65592
65741
|
const record = this.retained.get(work.id);
|
|
65593
65742
|
this.retained.delete(work.id);
|
|
65594
|
-
await this.queue.releaseRetained(this.lease, work, record?.enqueued === true).catch((error) => {
|
|
65743
|
+
await this.whileRootLate(this.queue, () => this.queue.releaseRetained(this.lease, work, record?.enqueued === true)).catch((error) => {
|
|
65595
65744
|
if (error.message !== STALE_WORK_LEASE)
|
|
65596
65745
|
throw error;
|
|
65597
65746
|
});
|
|
@@ -65605,20 +65754,29 @@ class PoolCoordinator {
|
|
|
65605
65754
|
async control(state) {
|
|
65606
65755
|
this.desiredControl = state;
|
|
65607
65756
|
if (!this.queue || !this.lease)
|
|
65608
|
-
return;
|
|
65609
|
-
const
|
|
65610
|
-
const
|
|
65611
|
-
|
|
65757
|
+
return 0;
|
|
65758
|
+
const queue = this.queue;
|
|
65759
|
+
const lease = this.lease;
|
|
65760
|
+
const control = await this.whileRootLate(queue, () => queue.setControl(lease, state));
|
|
65761
|
+
const unacknowledged = () => [...this.readyWorkers].filter((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision).length;
|
|
65762
|
+
let pending = unacknowledged();
|
|
65763
|
+
let progressAt = performance.now();
|
|
65764
|
+
let stalledAt = this.stalledMs;
|
|
65765
|
+
while (pending > 0) {
|
|
65612
65766
|
if (this.desiredControl !== state)
|
|
65613
|
-
return;
|
|
65614
|
-
if (Date.now() >= deadline) {
|
|
65615
|
-
if (state === "quit")
|
|
65616
|
-
break;
|
|
65617
|
-
throw new Error("Worker control acknowledgement unresolved");
|
|
65618
|
-
}
|
|
65767
|
+
return pending;
|
|
65619
65768
|
await delay2(25);
|
|
65769
|
+
this.observeResponsiveness();
|
|
65770
|
+
const now = unacknowledged();
|
|
65771
|
+
if (now < pending) {
|
|
65772
|
+
pending = now;
|
|
65773
|
+
progressAt = performance.now();
|
|
65774
|
+
stalledAt = this.stalledMs;
|
|
65775
|
+
} else if (performance.now() - progressAt - (this.stalledMs - stalledAt) >= CONTROL_ACKNOWLEDGEMENT_STALL_MS)
|
|
65776
|
+
break;
|
|
65620
65777
|
}
|
|
65621
65778
|
this.flush();
|
|
65779
|
+
return pending;
|
|
65622
65780
|
}
|
|
65623
65781
|
async start(sources, cwd, publish, rootRun) {
|
|
65624
65782
|
if (this.closed)
|
|
@@ -65646,7 +65804,11 @@ class PoolCoordinator {
|
|
|
65646
65804
|
return;
|
|
65647
65805
|
});
|
|
65648
65806
|
this.recoveryTimer = setInterval(() => {
|
|
65649
|
-
this.recoverExpired().catch((error) =>
|
|
65807
|
+
this.recoverExpired().catch(async (error) => {
|
|
65808
|
+
if (this.queue && isRootLeaseLost(error) && await this.rootRenewal(this.queue).catch(() => false))
|
|
65809
|
+
return;
|
|
65810
|
+
this.fail(error);
|
|
65811
|
+
});
|
|
65650
65812
|
}, RECOVERY_INTERVAL_MS).unref();
|
|
65651
65813
|
const workers = Array.from({ length: this.options.workers }, () => this.spawn());
|
|
65652
65814
|
try {
|
|
@@ -65663,7 +65825,9 @@ class PoolCoordinator {
|
|
|
65663
65825
|
const queue = this.queue;
|
|
65664
65826
|
const lease = this.lease;
|
|
65665
65827
|
const work = await this.retainedTransition(async () => {
|
|
65666
|
-
|
|
65828
|
+
let enqueued = await this.whileRootLate(queue, () => queue.enqueue(lease, command.descriptor, command.boundary));
|
|
65829
|
+
if (enqueued.state === "completed" && enqueued.epoch < lease.epoch)
|
|
65830
|
+
enqueued = await this.whileRootLate(queue, () => queue.reopenCompleted(lease, enqueued.id, failedOnInfrastructureFault)) ?? enqueued;
|
|
65667
65831
|
const retained = this.retained.get(enqueued.id);
|
|
65668
65832
|
if (retained)
|
|
65669
65833
|
retained.enqueued = true;
|
|
@@ -65676,7 +65840,9 @@ class PoolCoordinator {
|
|
|
65676
65840
|
}
|
|
65677
65841
|
async transport(request, payload) {
|
|
65678
65842
|
const target = this.deliveryRequests.get(request);
|
|
65679
|
-
if (target === undefined
|
|
65843
|
+
if (target === undefined)
|
|
65844
|
+
throw new Error("Pooled stage delivery request already answered");
|
|
65845
|
+
if (!this.incarnations.has(target.slot.worker))
|
|
65680
65846
|
throw new Error("Worker exited before delivery acknowledgement");
|
|
65681
65847
|
const { slot, workerRequest } = target;
|
|
65682
65848
|
await new Promise((resolve, reject) => {
|
|
@@ -65904,6 +66070,34 @@ class PoolCoordinator {
|
|
|
65904
66070
|
return { ok: false, refusal: "StaleAttempt" };
|
|
65905
66071
|
return { ok: true, ...result.action === undefined ? {} : { action: result.action } };
|
|
65906
66072
|
}
|
|
66073
|
+
async stageSession(id, command) {
|
|
66074
|
+
const watch = this.watches.get(id);
|
|
66075
|
+
if (watch === undefined || !watch.open)
|
|
66076
|
+
return {
|
|
66077
|
+
ok: false,
|
|
66078
|
+
refusal: this.endedWatches.get(id) === "stage_finished" ? "StageNotLive" : "StaleAttempt"
|
|
66079
|
+
};
|
|
66080
|
+
const { slot, attempt } = watch;
|
|
66081
|
+
if (slot.work?.id !== attempt.workId || slot.work.generation !== attempt.generation)
|
|
66082
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
66083
|
+
if (this.desiredControl !== undefined && this.desiredControl !== "running" && !runsWhilePaused(command))
|
|
66084
|
+
return { ok: false, refusal: "PoolPausedOrQuitting" };
|
|
66085
|
+
const result = await this.stageCommand(slot, { attempt, op: "session", watch: id, command });
|
|
66086
|
+
if (result === undefined)
|
|
66087
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
66088
|
+
if (result.error !== undefined)
|
|
66089
|
+
throw new Error(result.error);
|
|
66090
|
+
const refusal = result.refusal;
|
|
66091
|
+
if (refusal === "StageNotLive" || refusal === "PoolPausedOrQuitting")
|
|
66092
|
+
return { ok: false, refusal };
|
|
66093
|
+
if (refusal !== undefined)
|
|
66094
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
66095
|
+
return {
|
|
66096
|
+
ok: true,
|
|
66097
|
+
...result.bash === undefined ? {} : { bash: result.bash },
|
|
66098
|
+
...result.task === undefined ? {} : { task: result.task }
|
|
66099
|
+
};
|
|
66100
|
+
}
|
|
65907
66101
|
stageCommand(slot, command) {
|
|
65908
66102
|
if (!this.incarnations.has(slot.worker)) {
|
|
65909
66103
|
tracePooledWatch("coordinator.command.no-worker", { op: command.op, worker: slot.worker });
|
|
@@ -66019,7 +66213,8 @@ class PoolCoordinator {
|
|
|
66019
66213
|
root,
|
|
66020
66214
|
definitions: this.sources,
|
|
66021
66215
|
admission: options.admission,
|
|
66022
|
-
...this.promptNodes ? { promptNodes: true } : {}
|
|
66216
|
+
...this.promptNodes ? { promptNodes: true } : {},
|
|
66217
|
+
...options.stageStartMaxLoadPerCpu === undefined ? {} : { stageStartMaxLoadPerCpu: options.stageStartMaxLoadPerCpu }
|
|
66023
66218
|
})
|
|
66024
66219
|
], {
|
|
66025
66220
|
stdio: ["ignore", "ignore", "pipe", "ipc"],
|
|
@@ -66140,7 +66335,10 @@ class PoolCoordinator {
|
|
|
66140
66335
|
if (this.closed)
|
|
66141
66336
|
return;
|
|
66142
66337
|
const exhausted = work !== undefined && this.attempts(work) >= MAX_CHILD_ATTEMPTS;
|
|
66143
|
-
const
|
|
66338
|
+
const queue = this.queue;
|
|
66339
|
+
const lease = this.lease;
|
|
66340
|
+
const attempt = work;
|
|
66341
|
+
const settled = attempt !== undefined && await this.whileRootLate(queue, () => exhausted ? queue.failExited(lease, attempt) : queue.releaseExited(lease, attempt));
|
|
66144
66342
|
const superseded = work !== undefined && !settled && await this.superseded(work);
|
|
66145
66343
|
if (work !== undefined && exhausted && !superseded)
|
|
66146
66344
|
this.failWork(work, diagnosed(childRetryLimit(work, "lost its worker")));
|
|
@@ -66202,21 +66400,40 @@ class PoolCoordinator {
|
|
|
66202
66400
|
await this.starting;
|
|
66203
66401
|
const queue = this.queue;
|
|
66204
66402
|
const lease = this.lease;
|
|
66403
|
+
const renewAttempt = async () => {
|
|
66404
|
+
const attempt = slot.work;
|
|
66405
|
+
if (attempt === undefined)
|
|
66406
|
+
return;
|
|
66407
|
+
const renewed = await queue.extend(lease, attempt, options.leaseMs);
|
|
66408
|
+
if (slot.work === attempt)
|
|
66409
|
+
slot.work = renewed;
|
|
66410
|
+
};
|
|
66411
|
+
const current = async (action) => {
|
|
66412
|
+
try {
|
|
66413
|
+
return await action();
|
|
66414
|
+
} catch (error) {
|
|
66415
|
+
if (!(error instanceof Error) || error.message !== STALE_WORK_LEASE || slot.work === undefined)
|
|
66416
|
+
throw error;
|
|
66417
|
+
await renewAttempt();
|
|
66418
|
+
return action();
|
|
66419
|
+
}
|
|
66420
|
+
};
|
|
66421
|
+
const leased = (action) => this.whileRootLate(queue, () => current(action), renewAttempt);
|
|
66205
66422
|
if (message.kind === "control")
|
|
66206
|
-
return queue.control(lease);
|
|
66423
|
+
return leased(() => queue.control(lease));
|
|
66207
66424
|
if (message.kind === "fenced") {
|
|
66208
66425
|
const fenced = slot.work;
|
|
66209
66426
|
slot.work = undefined;
|
|
66210
66427
|
if (fenced && !await this.superseded(fenced)) {
|
|
66211
66428
|
if (this.attempts(fenced) < MAX_CHILD_ATTEMPTS)
|
|
66212
|
-
await queue.releaseExited(lease, fenced);
|
|
66213
|
-
else if (await queue.failExited(lease, fenced))
|
|
66429
|
+
await leased(() => queue.releaseExited(lease, fenced));
|
|
66430
|
+
else if (await leased(() => queue.failExited(lease, fenced)))
|
|
66214
66431
|
this.failWork(fenced, new Error(childRetryLimit(fenced, "was refused by the root as stale on every attempt")));
|
|
66215
66432
|
}
|
|
66216
66433
|
return;
|
|
66217
66434
|
}
|
|
66218
66435
|
if (message.kind === "controlled") {
|
|
66219
|
-
const control = await queue.control(lease);
|
|
66436
|
+
const control = await leased(() => queue.control(lease));
|
|
66220
66437
|
if (message.revision > control.revision)
|
|
66221
66438
|
throw new Error("Unknown control revision");
|
|
66222
66439
|
this.controlAcks.set(worker, Math.max(this.controlAcks.get(worker) ?? -1, message.revision));
|
|
@@ -66227,21 +66444,21 @@ class PoolCoordinator {
|
|
|
66227
66444
|
throw new Error("Worker already holds an attempt");
|
|
66228
66445
|
if (this.budgetBlocked)
|
|
66229
66446
|
return;
|
|
66230
|
-
await
|
|
66231
|
-
|
|
66232
|
-
|
|
66233
|
-
|
|
66234
|
-
|
|
66235
|
-
|
|
66447
|
+
slot.work = await leased(async () => {
|
|
66448
|
+
await this.recoverExpired();
|
|
66449
|
+
slot.runs.clear();
|
|
66450
|
+
return queue.claim(lease, worker, this.sources.map((source) => ({
|
|
66451
|
+
definition: `${source.path}#${source.exportName}`,
|
|
66452
|
+
digest: source.digest
|
|
66453
|
+
})), options.leaseMs);
|
|
66454
|
+
});
|
|
66236
66455
|
return slot.work;
|
|
66237
66456
|
}
|
|
66238
|
-
|
|
66239
|
-
if (!
|
|
66457
|
+
const held = slot.work;
|
|
66458
|
+
if (!held)
|
|
66240
66459
|
throw new Error("Worker has no active attempt");
|
|
66241
|
-
|
|
66242
|
-
|
|
66243
|
-
slot.work = work;
|
|
66244
|
-
}
|
|
66460
|
+
const work = message.kind === "renew" || held.expiresAt - Date.now() < options.leaseMs / 2 ? await leased(() => queue.extend(lease, held, options.leaseMs)) : held;
|
|
66461
|
+
slot.work = work;
|
|
66245
66462
|
if (message.kind === "activity") {
|
|
66246
66463
|
for (const run of message.runs)
|
|
66247
66464
|
slot.runs.add(run.id);
|
|
@@ -66301,24 +66518,24 @@ class PoolCoordinator {
|
|
|
66301
66518
|
if (message.kind === "renew")
|
|
66302
66519
|
return;
|
|
66303
66520
|
if (message.kind === "commit") {
|
|
66304
|
-
const receipt = await queue.commit(lease, work, message.operation, message.mutation);
|
|
66521
|
+
const receipt = await leased(() => queue.commit(lease, work, message.operation, message.mutation));
|
|
66305
66522
|
if (message.mutation.kind !== "session-append")
|
|
66306
66523
|
this.noteUsage(await this.usageLedger.total(root));
|
|
66307
66524
|
return receipt;
|
|
66308
66525
|
}
|
|
66309
66526
|
if (message.kind === "usage") {
|
|
66310
|
-
this.noteUsage(await this.usageLedger.report(lease, work, message.reports));
|
|
66527
|
+
this.noteUsage(await leased(() => this.usageLedger.report(lease, work, message.reports)));
|
|
66311
66528
|
return;
|
|
66312
66529
|
}
|
|
66313
66530
|
if (message.kind === "budget") {
|
|
66314
|
-
await queue.assertCurrent(lease, work);
|
|
66531
|
+
await leased(() => queue.assertCurrent(lease, work));
|
|
66315
66532
|
if (this.budgetBlocked)
|
|
66316
66533
|
throw new Error("Root workflow budget exhausted");
|
|
66317
|
-
return queue.control(lease);
|
|
66534
|
+
return leased(() => queue.control(lease));
|
|
66318
66535
|
}
|
|
66319
66536
|
if (message.kind !== "complete")
|
|
66320
66537
|
throw new Error("Invalid worker operation");
|
|
66321
|
-
await queue.complete(lease, work, message.result);
|
|
66538
|
+
await leased(() => queue.complete(lease, work, message.result));
|
|
66322
66539
|
this.endStageWatches((watch) => watch.slot === slot, "stage_finished");
|
|
66323
66540
|
this.replacements = 0;
|
|
66324
66541
|
slot.work = undefined;
|
|
@@ -66357,7 +66574,7 @@ class PoolCoordinator {
|
|
|
66357
66574
|
if (this.recovering)
|
|
66358
66575
|
return this.recovering;
|
|
66359
66576
|
const root = this.root;
|
|
66360
|
-
if (this.closed || root === undefined || !this.queue || performance.now() < this.nextRecoveryAt)
|
|
66577
|
+
if (this.closed || root === undefined || !this.queue || this.lateRoot !== undefined || performance.now() < this.nextRecoveryAt)
|
|
66361
66578
|
return Promise.resolve();
|
|
66362
66579
|
const queue = this.queue;
|
|
66363
66580
|
const lease = this.lease;
|
|
@@ -66366,9 +66583,12 @@ class PoolCoordinator {
|
|
|
66366
66583
|
await new Promise((resolve) => setImmediate(resolve));
|
|
66367
66584
|
await this.admission?.reconcile();
|
|
66368
66585
|
const expiredBefore = Date.now();
|
|
66369
|
-
|
|
66370
|
-
|
|
66371
|
-
|
|
66586
|
+
const expired = (await queue.inspect(root)).filter((work) => work.state === "leased" && work.expiresAt < expiredBefore);
|
|
66587
|
+
if (expired.length > 0 && await queue.rootLease(lease, COORDINATOR_LEASE_MS) === "late") {
|
|
66588
|
+
this.rootRenewal(queue).catch(() => {});
|
|
66589
|
+
return;
|
|
66590
|
+
}
|
|
66591
|
+
for (const work of expired) {
|
|
66372
66592
|
if (this.quarantined.has(work.id))
|
|
66373
66593
|
continue;
|
|
66374
66594
|
if (this.held.has(work.id)) {
|
|
@@ -66484,7 +66704,7 @@ function childRetryLimit(work, reason) {
|
|
|
66484
66704
|
const exportName = work.definition.slice(work.definition.lastIndexOf("#") + 1);
|
|
66485
66705
|
return `Local worker retry limit: child ${work.childRunId} (${exportName}) ${reason} ${MAX_CHILD_ATTEMPTS} times`;
|
|
66486
66706
|
}
|
|
66487
|
-
var
|
|
66707
|
+
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;
|
|
66488
66708
|
var init_pool_coordinator = __esm(() => {
|
|
66489
66709
|
init_internal();
|
|
66490
66710
|
init_pool_remote_journal();
|
|
@@ -66498,12 +66718,14 @@ var init_pool_coordinator = __esm(() => {
|
|
|
66498
66718
|
init_pending_stage_route_capability();
|
|
66499
66719
|
init_pending_stage_route_readiness();
|
|
66500
66720
|
init_store();
|
|
66721
|
+
init_workflow_infrastructure_error();
|
|
66501
66722
|
init_pool_journal();
|
|
66502
66723
|
init_pooled_watch_trace();
|
|
66503
66724
|
init_resource_admission();
|
|
66504
66725
|
init_stage_watch_coalesce();
|
|
66505
66726
|
init_startup_timeout();
|
|
66506
66727
|
COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
|
|
66728
|
+
LATE_ROOT_POLL_MS = RECOVERY_INTERVAL_MS;
|
|
66507
66729
|
STAGE_WATCH_BACKLOG_BYTES = 8 * 1024 * 1024;
|
|
66508
66730
|
});
|
|
66509
66731
|
|
|
@@ -66594,7 +66816,8 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
66594
66816
|
const boundedDrain = (drain, sessionId) => {
|
|
66595
66817
|
const waiting = new Promise((resolve, reject) => {
|
|
66596
66818
|
drain.then(resolve, reject);
|
|
66597
|
-
|
|
66819
|
+
if (options.holdUntilDrained !== true)
|
|
66820
|
+
watchStall(drain, sessionId, resolve);
|
|
66598
66821
|
});
|
|
66599
66822
|
waiting.catch(() => {});
|
|
66600
66823
|
return waiting;
|
|
@@ -66976,10 +67199,14 @@ class PoolStageHandoff {
|
|
|
66976
67199
|
if (run.endedAt !== undefined || this.owners.get(run.id) !== work.id)
|
|
66977
67200
|
continue;
|
|
66978
67201
|
if (run.id === work.childRunId) {
|
|
66979
|
-
const
|
|
67202
|
+
const executions = new Map(run.stages.map((stage) => [stage.id, stage.workerExecution]));
|
|
67203
|
+
const attempt = run.stages.flatMap((stage) => stage.workerExecution === undefined ? [] : [stage.workerExecution]).reduce((latest, execution) => latest === undefined || execution.renewedAt > latest.renewedAt ? execution : latest, undefined);
|
|
66980
67204
|
this.store.recordRunStart({
|
|
66981
67205
|
...run,
|
|
66982
|
-
stages: result.stages.map((stage) =>
|
|
67206
|
+
stages: result.stages.map((stage) => {
|
|
67207
|
+
const execution = executions.get(stage.id) ?? attempt;
|
|
67208
|
+
return execution === undefined ? stage : { ...stage, workerExecution: execution };
|
|
67209
|
+
}),
|
|
66983
67210
|
toolNodes: result.toolNodes
|
|
66984
67211
|
});
|
|
66985
67212
|
this.store.recordRunEnd(run.id, result.status, result.result, result.error);
|
|
@@ -67033,7 +67260,7 @@ class PoolStageHandoff {
|
|
|
67033
67260
|
pendingStageMessages: [
|
|
67034
67261
|
...known.get(run.id)?.pendingStageMessages ?? pendingStageMessagesForDurableRun(this.backend, run.id, root)
|
|
67035
67262
|
],
|
|
67036
|
-
stages: withReconnectingStages(known.get(run.id), run, run.stages.map((stage) => ({ ...stage, workerExecution: execution })), work.generation)
|
|
67263
|
+
stages: withReconnectingStages(known.get(run.id), run, run.stages.map((stage) => ({ ...stage, workerExecution: endedUnder(known.get(run.id), stage, execution) })), work.generation)
|
|
67037
67264
|
}));
|
|
67038
67265
|
const changed = published.some((run) => activity(known.get(run.id)) !== activity(run));
|
|
67039
67266
|
for (const run of published)
|
|
@@ -67164,7 +67391,7 @@ class PoolStageHandoff {
|
|
|
67164
67391
|
throw new Error(STALE);
|
|
67165
67392
|
if (attempt.sessions.get(key) !== sessionId)
|
|
67166
67393
|
throw new Error(`Stage session ${sessionId} was replaced before it acknowledged delivery`);
|
|
67167
|
-
}, action));
|
|
67394
|
+
}, action), { holdUntilDrained: true });
|
|
67168
67395
|
attempt.deliveries.set(key, delivery);
|
|
67169
67396
|
}
|
|
67170
67397
|
return delivery;
|
|
@@ -67176,6 +67403,12 @@ function outside2(runId) {
|
|
|
67176
67403
|
function isLive(stage) {
|
|
67177
67404
|
return (stage.sessionId !== undefined || stage.sessionFile !== undefined) && stage.status !== "completed" && stage.status !== "failed" && stage.status !== "skipped";
|
|
67178
67405
|
}
|
|
67406
|
+
function endedUnder(known, stage, execution) {
|
|
67407
|
+
if (!isTerminalStageStatus(stage.status))
|
|
67408
|
+
return execution;
|
|
67409
|
+
const previous = known?.stages.find((candidate) => candidate.id === stage.id);
|
|
67410
|
+
return previous !== undefined && isTerminalStageStatus(previous.status) && previous.workerExecution?.generation === execution.generation && previous.workerExecution.worker === execution.worker ? previous.workerExecution : execution;
|
|
67411
|
+
}
|
|
67179
67412
|
function withReconnectingStages(previous, run, stages, generation) {
|
|
67180
67413
|
if (previous === undefined || run.endedAt !== undefined || isTerminalRunStatus(run.status))
|
|
67181
67414
|
return stages;
|
|
@@ -67312,6 +67545,116 @@ class StageToolExecutionBuffer {
|
|
|
67312
67545
|
}
|
|
67313
67546
|
}
|
|
67314
67547
|
|
|
67548
|
+
// dist/builtin/workflows/src/workers/pooled-stage-task-source.ts
|
|
67549
|
+
function failure2(error) {
|
|
67550
|
+
return { ok: false, error: { message: typeof error === "string" ? error : error.message } };
|
|
67551
|
+
}
|
|
67552
|
+
|
|
67553
|
+
class PooledStageTaskSource {
|
|
67554
|
+
run;
|
|
67555
|
+
state = EMPTY;
|
|
67556
|
+
records = [];
|
|
67557
|
+
backgroundRecords = [];
|
|
67558
|
+
settlements = new Map;
|
|
67559
|
+
activity = new Map;
|
|
67560
|
+
statuses = new Map;
|
|
67561
|
+
stdin = new Set;
|
|
67562
|
+
listeners = new Set;
|
|
67563
|
+
constructor(run) {
|
|
67564
|
+
this.run = run;
|
|
67565
|
+
}
|
|
67566
|
+
apply(state) {
|
|
67567
|
+
this.state = state;
|
|
67568
|
+
this.records = [...state.tasks];
|
|
67569
|
+
const background = new Set(state.background);
|
|
67570
|
+
this.backgroundRecords = this.records.filter((task) => background.has(task.ref.taskId));
|
|
67571
|
+
this.settlements = new Map(state.settlement.map(([id, sequence]) => [id, BigInt(sequence)]));
|
|
67572
|
+
this.activity = new Map(state.activity.map((entry) => [entry.id, entry]));
|
|
67573
|
+
this.statuses = new Map(state.statuses.map((entry) => [entry.id, new Map(entry.entries)]));
|
|
67574
|
+
this.stdin = new Set(state.stdin);
|
|
67575
|
+
for (const listener of [...this.listeners])
|
|
67576
|
+
listener();
|
|
67577
|
+
}
|
|
67578
|
+
get empty() {
|
|
67579
|
+
return this.state.tasks.length === 0;
|
|
67580
|
+
}
|
|
67581
|
+
get tasks() {
|
|
67582
|
+
return this.records;
|
|
67583
|
+
}
|
|
67584
|
+
get backgroundTasks() {
|
|
67585
|
+
return this.backgroundRecords;
|
|
67586
|
+
}
|
|
67587
|
+
get settlementOrder() {
|
|
67588
|
+
return this.settlements;
|
|
67589
|
+
}
|
|
67590
|
+
recentActivity(id) {
|
|
67591
|
+
return [...this.activity.get(id)?.entries ?? []];
|
|
67592
|
+
}
|
|
67593
|
+
activityOmitted(id) {
|
|
67594
|
+
return this.activity.get(id)?.omitted === true;
|
|
67595
|
+
}
|
|
67596
|
+
subscribe(listener) {
|
|
67597
|
+
this.listeners.add(listener);
|
|
67598
|
+
return () => {
|
|
67599
|
+
this.listeners.delete(listener);
|
|
67600
|
+
};
|
|
67601
|
+
}
|
|
67602
|
+
async foregroundTask(id) {
|
|
67603
|
+
const reply = await this.request(id, { kind: "foreground" });
|
|
67604
|
+
return reply.ok ? reply.value.kind === "foreground" ? reply.value.result : unexpected() : reply;
|
|
67605
|
+
}
|
|
67606
|
+
async cancelTask(id) {
|
|
67607
|
+
const reply = await this.request(id, { kind: "cancel" });
|
|
67608
|
+
if (!reply.ok)
|
|
67609
|
+
return reply;
|
|
67610
|
+
return reply.value.kind === "cancel" ? reply.value.result ?? { ok: true, value: undefined } : unexpected();
|
|
67611
|
+
}
|
|
67612
|
+
stdinAvailable(id) {
|
|
67613
|
+
return this.stdin.has(id);
|
|
67614
|
+
}
|
|
67615
|
+
async writeTaskInput(id, text) {
|
|
67616
|
+
const reply = await this.request(id, { kind: "input", text });
|
|
67617
|
+
return reply.ok ? reply.value.kind === "input" ? reply.value.result : unexpected() : reply;
|
|
67618
|
+
}
|
|
67619
|
+
async readTaskOutput(id, range) {
|
|
67620
|
+
const reply = await this.request(id, { kind: "output", start: range.start, maximumBytes: range.maximumBytes });
|
|
67621
|
+
return reply.ok ? reply.value.kind === "output" ? reply.value.result : unexpected() : reply;
|
|
67622
|
+
}
|
|
67623
|
+
async taskDetailText(id) {
|
|
67624
|
+
const reply = await this.request(id, { kind: "detail" });
|
|
67625
|
+
return reply.ok && reply.value.kind === "detail" ? reply.value.detail : {};
|
|
67626
|
+
}
|
|
67627
|
+
async readTaskTranscript(id, cursor) {
|
|
67628
|
+
const reply = await this.request(id, { kind: "transcript", ...cursor === undefined ? {} : { cursor } });
|
|
67629
|
+
return reply.ok ? reply.value.kind === "transcript" ? reply.value.result : unexpected() : reply;
|
|
67630
|
+
}
|
|
67631
|
+
followTaskTranscript(id) {
|
|
67632
|
+
return this.records.some((task) => task.ref.taskId === id && task.kind === "agent") ? { historyOnly: true } : undefined;
|
|
67633
|
+
}
|
|
67634
|
+
extensionStatuses(id) {
|
|
67635
|
+
return this.statuses.get(id) ?? NO_STATUSES;
|
|
67636
|
+
}
|
|
67637
|
+
watchExtensionStatuses(_id, listener) {
|
|
67638
|
+
return this.subscribe(listener);
|
|
67639
|
+
}
|
|
67640
|
+
async request(id, action) {
|
|
67641
|
+
try {
|
|
67642
|
+
const reply = await this.run(id, action);
|
|
67643
|
+
return reply === undefined ? failure2("Task unavailable") : { ok: true, value: reply };
|
|
67644
|
+
} catch (error) {
|
|
67645
|
+
return failure2(error instanceof Error ? error : String(error));
|
|
67646
|
+
}
|
|
67647
|
+
}
|
|
67648
|
+
}
|
|
67649
|
+
function unexpected() {
|
|
67650
|
+
return failure2("Unexpected reply from the local worker");
|
|
67651
|
+
}
|
|
67652
|
+
var EMPTY, NO_STATUSES;
|
|
67653
|
+
var init_pooled_stage_task_source = __esm(() => {
|
|
67654
|
+
EMPTY = { tasks: [], background: [], settlement: [], activity: [], stdin: [], statuses: [] };
|
|
67655
|
+
NO_STATUSES = new Map;
|
|
67656
|
+
});
|
|
67657
|
+
|
|
67315
67658
|
// dist/builtin/workflows/src/workers/pooled-stage-handle.ts
|
|
67316
67659
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
67317
67660
|
|
|
@@ -67342,6 +67685,11 @@ class PooledStageHandle {
|
|
|
67342
67685
|
undelivered;
|
|
67343
67686
|
disposed = false;
|
|
67344
67687
|
session;
|
|
67688
|
+
commands;
|
|
67689
|
+
sessionStarted = true;
|
|
67690
|
+
started = Promise.withResolvers();
|
|
67691
|
+
bashRuns = new Map;
|
|
67692
|
+
taskView = new PooledStageTaskSource(async (taskId, action) => (await this.sessionCommand({ kind: "task", taskId, action })).task);
|
|
67345
67693
|
pumping;
|
|
67346
67694
|
pumpAgain = false;
|
|
67347
67695
|
watchGone = Promise.withResolvers();
|
|
@@ -67404,6 +67752,43 @@ class PooledStageHandle {
|
|
|
67404
67752
|
streamingMessage() {
|
|
67405
67753
|
return this.streaming;
|
|
67406
67754
|
}
|
|
67755
|
+
commandCatalog() {
|
|
67756
|
+
return this.commands;
|
|
67757
|
+
}
|
|
67758
|
+
taskSource() {
|
|
67759
|
+
return this.taskView;
|
|
67760
|
+
}
|
|
67761
|
+
get isSessionStarting() {
|
|
67762
|
+
return !this.sessionStarted && this.ended === undefined;
|
|
67763
|
+
}
|
|
67764
|
+
get isBashRunning() {
|
|
67765
|
+
return this.bashRuns.size > 0;
|
|
67766
|
+
}
|
|
67767
|
+
async executeBash(command, onChunk, options) {
|
|
67768
|
+
const id = randomUUID18();
|
|
67769
|
+
this.bashRuns.set(id, onChunk);
|
|
67770
|
+
try {
|
|
67771
|
+
const result = await this.sessionCommand({
|
|
67772
|
+
kind: "bash",
|
|
67773
|
+
id,
|
|
67774
|
+
command,
|
|
67775
|
+
...options?.excludeFromContext === undefined ? {} : { excludeFromContext: options.excludeFromContext }
|
|
67776
|
+
});
|
|
67777
|
+
return result.bash ?? { output: "", exitCode: undefined, cancelled: true, truncated: false };
|
|
67778
|
+
} finally {
|
|
67779
|
+
this.bashRuns.delete(id);
|
|
67780
|
+
}
|
|
67781
|
+
}
|
|
67782
|
+
abortBash() {
|
|
67783
|
+
for (const id of this.bashRuns.keys())
|
|
67784
|
+
this.sessionCommand({ kind: "abort-bash", id }).catch(() => {});
|
|
67785
|
+
}
|
|
67786
|
+
async compact() {
|
|
67787
|
+
await this.sessionCommand({ kind: "compact" });
|
|
67788
|
+
}
|
|
67789
|
+
abortCompaction() {
|
|
67790
|
+
this.sessionCommand({ kind: "abort-compaction" }).catch(() => {});
|
|
67791
|
+
}
|
|
67407
67792
|
pendingToolExecutionEvents() {
|
|
67408
67793
|
return this.toolExecutions.replayEvents();
|
|
67409
67794
|
}
|
|
@@ -67551,6 +67936,17 @@ class PooledStageHandle {
|
|
|
67551
67936
|
if (this.disposed)
|
|
67552
67937
|
throw new Error(`Stage chat "${this.stageName}" is closed.`);
|
|
67553
67938
|
}
|
|
67939
|
+
async sessionCommand(command) {
|
|
67940
|
+
this.throwIfClosed();
|
|
67941
|
+
if (this.ended !== undefined)
|
|
67942
|
+
throw new PooledStageDeliveryError("StageNotLive", this.stageName);
|
|
67943
|
+
if (this.transport.session === undefined)
|
|
67944
|
+
throw new Error(`Stage "${this.stageName}" runs on a local worker that cannot run this command.`);
|
|
67945
|
+
const result = await this.transport.session(this.watchId, command);
|
|
67946
|
+
if (!result.ok)
|
|
67947
|
+
throw new PooledStageDeliveryError(result.refusal, this.stageName);
|
|
67948
|
+
return result;
|
|
67949
|
+
}
|
|
67554
67950
|
undeliveredCount() {
|
|
67555
67951
|
if (this.undelivered !== undefined)
|
|
67556
67952
|
return this.undelivered;
|
|
@@ -67616,6 +68012,16 @@ class PooledStageHandle {
|
|
|
67616
68012
|
entry.waiter = undefined;
|
|
67617
68013
|
}
|
|
67618
68014
|
}
|
|
68015
|
+
markSessionStarted(started) {
|
|
68016
|
+
if (started) {
|
|
68017
|
+
this.sessionStarted = true;
|
|
68018
|
+
this.started.resolve();
|
|
68019
|
+
return;
|
|
68020
|
+
}
|
|
68021
|
+
if (this.sessionStarted)
|
|
68022
|
+
this.started = Promise.withResolvers();
|
|
68023
|
+
this.sessionStarted = false;
|
|
68024
|
+
}
|
|
67619
68025
|
forget(op) {
|
|
67620
68026
|
const index = this.outbound.findIndex((entry) => entry.op === op);
|
|
67621
68027
|
if (index >= 0)
|
|
@@ -67672,10 +68078,17 @@ class PooledStageHandle {
|
|
|
67672
68078
|
const gone = this.watchGone.promise.then(() => ({ ok: false, refusal: "StaleAttempt" }));
|
|
67673
68079
|
const sending = this.sendEntry(entry, watch);
|
|
67674
68080
|
let bound;
|
|
68081
|
+
let stopped = false;
|
|
67675
68082
|
const unconfirmed = new Promise((resolve) => {
|
|
67676
|
-
|
|
68083
|
+
this.started.promise.then(() => {
|
|
68084
|
+
if (!stopped)
|
|
68085
|
+
bound = setTimeout(() => resolve("unconfirmed"), this.admissionWaitMs);
|
|
68086
|
+
});
|
|
68087
|
+
});
|
|
68088
|
+
const outcome = await Promise.race([sending, gone, unconfirmed]).finally(() => {
|
|
68089
|
+
stopped = true;
|
|
68090
|
+
clearTimeout(bound);
|
|
67677
68091
|
});
|
|
67678
|
-
const outcome = await Promise.race([sending, gone, unconfirmed]).finally(() => clearTimeout(bound));
|
|
67679
68092
|
if (outcome === "unconfirmed") {
|
|
67680
68093
|
tracePooledWatch("root.outbox.unconfirmed", { op: entry.op, watch, generation });
|
|
67681
68094
|
entry.unconfirmedOn = generation;
|
|
@@ -67765,6 +68178,10 @@ class PooledStageHandle {
|
|
|
67765
68178
|
}
|
|
67766
68179
|
adopt(snapshot) {
|
|
67767
68180
|
this.session = snapshot.sessionId;
|
|
68181
|
+
this.commands = snapshot.commands;
|
|
68182
|
+
if (!this.taskView.empty)
|
|
68183
|
+
this.taskView.apply(NO_TASKS);
|
|
68184
|
+
this.markSessionStarted(snapshot.sessionStarted !== false);
|
|
67768
68185
|
this.settled = [...snapshot.messages];
|
|
67769
68186
|
this.streaming = snapshot.streamingMessage;
|
|
67770
68187
|
this.currentStatus = snapshot.status;
|
|
@@ -67785,6 +68202,25 @@ class PooledStageHandle {
|
|
|
67785
68202
|
this.forget(event.op);
|
|
67786
68203
|
return false;
|
|
67787
68204
|
}
|
|
68205
|
+
if (event.type === STAGE_SESSION_STARTED_EVENT) {
|
|
68206
|
+
this.commands = event.commands;
|
|
68207
|
+
this.markSessionStarted(true);
|
|
68208
|
+
const queued = this.queuedUserMessages();
|
|
68209
|
+
const redraw = { type: "queue_update", steering: [...queued.steering], followUp: [...queued.followUp] };
|
|
68210
|
+
for (const listener of [...this.listeners])
|
|
68211
|
+
listener(redraw);
|
|
68212
|
+
return false;
|
|
68213
|
+
}
|
|
68214
|
+
if (event.type === STAGE_TASKS_EVENT) {
|
|
68215
|
+
this.taskView.apply(event.tasks);
|
|
68216
|
+
return false;
|
|
68217
|
+
}
|
|
68218
|
+
if (event.type === STAGE_MESSAGES_EVENT) {
|
|
68219
|
+
this.settled = [...event.messages];
|
|
68220
|
+
return false;
|
|
68221
|
+
}
|
|
68222
|
+
if (event.type === "bash_execution_update" && event.id !== undefined)
|
|
68223
|
+
this.bashRuns.get(event.id)?.(event.delta);
|
|
67788
68224
|
this.applyEvent(event);
|
|
67789
68225
|
const turnUnderway = TURN_EVENTS.has(event.type) || (event.type === "message_start" || event.type === "message_update") && event.message.role === "assistant";
|
|
67790
68226
|
if (turnUnderway && this.awaitingTurn) {
|
|
@@ -67867,10 +68303,12 @@ async function reconnectPooledStageHandle(handle, transport, wanted = () => true
|
|
|
67867
68303
|
await rebinding;
|
|
67868
68304
|
return !handle.isReconnecting;
|
|
67869
68305
|
}
|
|
67870
|
-
var DELIVERY_RECEIPT_EVENT = "atomic_pooled_delivery_receipt", POOLED_ADMISSION_WAIT_MS = 15000, RECONNECTABLE, TURN_EVENTS, PooledStageDeliveryError;
|
|
68306
|
+
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;
|
|
67871
68307
|
var init_pooled_stage_handle = __esm(() => {
|
|
67872
68308
|
init_stage_queued_user_messages();
|
|
68309
|
+
init_pooled_stage_task_source();
|
|
67873
68310
|
init_pooled_watch_trace();
|
|
68311
|
+
NO_TASKS = { tasks: [], background: [], settlement: [], activity: [], stdin: [], statuses: [] };
|
|
67874
68312
|
RECONNECTABLE = new Set(["attempt_fenced", "worker_exited", "resync"]);
|
|
67875
68313
|
TURN_EVENTS = new Set(["agent_start", "turn_start", "tool_execution_start", "tool_execution_update"]);
|
|
67876
68314
|
PooledStageDeliveryError = class PooledStageDeliveryError extends Error {
|
|
@@ -67930,6 +68368,9 @@ class RegisteredPooledStageHandle {
|
|
|
67930
68368
|
pendingToolExecutionEvents() {
|
|
67931
68369
|
return this.current()?.pendingToolExecutionEvents?.() ?? [];
|
|
67932
68370
|
}
|
|
68371
|
+
commandCatalog() {
|
|
68372
|
+
return this.current()?.commandCatalog?.();
|
|
68373
|
+
}
|
|
67933
68374
|
update(stage) {
|
|
67934
68375
|
this.stage = stage;
|
|
67935
68376
|
}
|
|
@@ -68228,6 +68669,7 @@ class LocalWorkerPool {
|
|
|
68228
68669
|
rootSignature;
|
|
68229
68670
|
completing = 0;
|
|
68230
68671
|
rootFlush;
|
|
68672
|
+
connecting;
|
|
68231
68673
|
starting;
|
|
68232
68674
|
failure;
|
|
68233
68675
|
closed = false;
|
|
@@ -68257,6 +68699,8 @@ class LocalWorkerPool {
|
|
|
68257
68699
|
throw new Error("Invalid local worker startup timeout");
|
|
68258
68700
|
if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
|
|
68259
68701
|
throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
|
|
68702
|
+
if (options.maxLoadPerCpu !== undefined && (!Number.isFinite(options.maxLoadPerCpu) || options.maxLoadPerCpu < 0))
|
|
68703
|
+
throw new Error("Invalid local worker load threshold: maxLoadPerCpu must be a number of at least 0");
|
|
68260
68704
|
this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
|
|
68261
68705
|
this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
|
|
68262
68706
|
if (options.admission && options.rootId === undefined)
|
|
@@ -68284,23 +68728,35 @@ class LocalWorkerPool {
|
|
|
68284
68728
|
if (!state || state.holderId !== this.backend.holderId)
|
|
68285
68729
|
throw new Error("Local worker pool requires the root owner");
|
|
68286
68730
|
this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
|
|
68287
|
-
const workerEntry = this.options.workerEntry ?? (isBunBinary2 || this.options.coordinator === "in-process" ? defaultWorkerEntry() : undefined);
|
|
68288
|
-
this.usageTotal = await this.command({
|
|
68289
|
-
kind: "prepare",
|
|
68290
|
-
root,
|
|
68291
|
-
lease: this.lease,
|
|
68292
|
-
options: {
|
|
68293
|
-
journalPath: this.options.journalPath,
|
|
68294
|
-
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
68295
|
-
workers: this.options.workers,
|
|
68296
|
-
leaseMs: this.leaseMs,
|
|
68297
|
-
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
68298
|
-
...this.options.admission === undefined ? {} : { admission: this.options.admission },
|
|
68299
|
-
...workerEntry === undefined ? {} : { workerEntry }
|
|
68300
|
-
},
|
|
68301
|
-
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
68302
|
-
});
|
|
68303
68731
|
this.queue ??= await openSqlPoolQueue(poolJournal, this.options.durable === undefined ? undefined : new PoolRemoteJournal(this.backend.journal, sqlPoolStorage(poolJournal)));
|
|
68732
|
+
if (await this.queue.initialized(root))
|
|
68733
|
+
await this.connectPool();
|
|
68734
|
+
}
|
|
68735
|
+
connectPool() {
|
|
68736
|
+
this.connecting ??= (async () => {
|
|
68737
|
+
const root = this.root;
|
|
68738
|
+
const lease = this.lease;
|
|
68739
|
+
if (root === undefined || lease === undefined)
|
|
68740
|
+
throw new Error("Local worker pool requires root preparation");
|
|
68741
|
+
const workerEntry = this.options.workerEntry ?? (isBunBinary2 || this.options.coordinator === "in-process" ? defaultWorkerEntry() : undefined);
|
|
68742
|
+
this.usageTotal = await this.command({
|
|
68743
|
+
kind: "prepare",
|
|
68744
|
+
root,
|
|
68745
|
+
lease,
|
|
68746
|
+
options: {
|
|
68747
|
+
journalPath: this.options.journalPath,
|
|
68748
|
+
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
68749
|
+
workers: this.options.workers,
|
|
68750
|
+
leaseMs: this.leaseMs,
|
|
68751
|
+
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
68752
|
+
...this.options.admission === undefined ? {} : { admission: this.options.admission },
|
|
68753
|
+
...this.options.maxLoadPerCpu === undefined ? {} : { stageStartMaxLoadPerCpu: this.options.maxLoadPerCpu },
|
|
68754
|
+
...workerEntry === undefined ? {} : { workerEntry }
|
|
68755
|
+
},
|
|
68756
|
+
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
68757
|
+
});
|
|
68758
|
+
})();
|
|
68759
|
+
return this.connecting;
|
|
68304
68760
|
}
|
|
68305
68761
|
async poolJournal() {
|
|
68306
68762
|
const journal = this.backend.journal;
|
|
@@ -68349,6 +68805,7 @@ class LocalWorkerPool {
|
|
|
68349
68805
|
async start(root, promptNodes) {
|
|
68350
68806
|
if (this.closed)
|
|
68351
68807
|
throw new Error("Local worker pool is closed");
|
|
68808
|
+
await this.connectPool();
|
|
68352
68809
|
if (!this.queue || !this.lease || this.lease.runId !== root)
|
|
68353
68810
|
throw new Error("Local worker pool requires root preparation");
|
|
68354
68811
|
this.sources = await Promise.all(this.options.definitions.map(async (binding) => {
|
|
@@ -68631,6 +69088,11 @@ class LocalWorkerPool {
|
|
|
68631
69088
|
...message === undefined ? {} : { message }
|
|
68632
69089
|
});
|
|
68633
69090
|
}
|
|
69091
|
+
async sessionCommandOnPooledStage(watch, command) {
|
|
69092
|
+
if (this.closed || this.coordinatorLost !== undefined)
|
|
69093
|
+
return { ok: false, refusal: "StaleAttempt" };
|
|
69094
|
+
return await this.command({ kind: "stage-session", watch, command });
|
|
69095
|
+
}
|
|
68634
69096
|
stageTransport(onEnded) {
|
|
68635
69097
|
return {
|
|
68636
69098
|
watch: (ref, listener) => this.watchPooledStage(ref, (message) => {
|
|
@@ -68641,7 +69103,8 @@ class LocalWorkerPool {
|
|
|
68641
69103
|
unwatch: (watch) => this.unwatchPooledStage(watch),
|
|
68642
69104
|
deliver: (delivery) => this.deliverToPooledStage(delivery),
|
|
68643
69105
|
pause: (watch) => this.pausePooledStage(watch),
|
|
68644
|
-
resume: (watch, message) => this.resumePooledStage(watch, message)
|
|
69106
|
+
resume: (watch, message) => this.resumePooledStage(watch, message),
|
|
69107
|
+
session: (watch, command) => this.sessionCommandOnPooledStage(watch, command)
|
|
68645
69108
|
};
|
|
68646
69109
|
}
|
|
68647
69110
|
async acquirePooledStage(runId, stageId) {
|
|
@@ -69304,6 +69767,9 @@ var init_local_pool = __esm(() => {
|
|
|
69304
69767
|
completeInTurns = createTurnSlicer(2, COMPLETION_TURN_BUDGET_MS);
|
|
69305
69768
|
});
|
|
69306
69769
|
|
|
69770
|
+
// dist/builtin/workflows/src/workers/public-options.ts
|
|
69771
|
+
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
69772
|
+
|
|
69307
69773
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
69308
69774
|
import { resolve as resolve15 } from "node:path";
|
|
69309
69775
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
@@ -69354,6 +69820,7 @@ async function activatePublicPool(backend, options) {
|
|
|
69354
69820
|
...options.localWorkers,
|
|
69355
69821
|
startupTimeoutMs: undefined,
|
|
69356
69822
|
leaseMs: undefined,
|
|
69823
|
+
maxLoadPerCpu: undefined,
|
|
69357
69824
|
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
|
|
69358
69825
|
};
|
|
69359
69826
|
const admission = options.admission && {
|
|
@@ -69397,6 +69864,7 @@ async function activatePublicPool(backend, options) {
|
|
|
69397
69864
|
admission: resources.admission ?? {},
|
|
69398
69865
|
startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
|
|
69399
69866
|
leaseMs: options.localWorkers?.leaseMs,
|
|
69867
|
+
maxLoadPerCpu: options.localWorkers?.maxLoadPerCpu ?? DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU,
|
|
69400
69868
|
...options.stageControlRegistry === undefined || options[hostWorkerBindings] ? {} : { stageControlRegistry: options.stageControlRegistry }
|
|
69401
69869
|
});
|
|
69402
69870
|
try {
|
|
@@ -75834,7 +76302,7 @@ class StageSessionController {
|
|
|
75834
76302
|
return this.modelRoute ? this.checkedSession(await ready) : ready;
|
|
75835
76303
|
}
|
|
75836
76304
|
async ensureSessionFromId(sessionId, consumer = "prompt") {
|
|
75837
|
-
const joinsLiveGeneration = !this.sessionShutdownPromise && (this.sessionPromise !== undefined || this.session !== undefined);
|
|
76305
|
+
const joinsLiveGeneration = !this.sessionShutdownPromise && (this.sessionPromise !== undefined || this.session !== undefined || this.activeCreation !== undefined || this.ownedCreationPromise !== undefined);
|
|
75838
76306
|
if (!this.sessionShutdownPromise && !joinsLiveGeneration)
|
|
75839
76307
|
this.reattachSessionId = sessionId;
|
|
75840
76308
|
const session = await this.ensureSession(consumer);
|