@caupulican/pi-adaptative 0.90.2 → 0.90.5
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 +41 -0
- package/dist/core/agent-session-contracts.d.ts +2 -0
- package/dist/core/agent-session-contracts.d.ts.map +1 -1
- package/dist/core/agent-session-contracts.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts +10 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +24 -2
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +6 -1
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +17 -1
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +1 -3
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/compaction-controller.d.ts.map +1 -1
- package/dist/core/compaction-controller.js +0 -1
- package/dist/core/compaction-controller.js.map +1 -1
- package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -1
- package/dist/core/delegation/managed-lane-controller.js +5 -1
- package/dist/core/delegation/managed-lane-controller.js.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.d.ts +8 -1
- package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.js +94 -36
- package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-agent-control.d.ts +1 -0
- package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
- package/dist/core/delegation/worker-agent-control.js.map +1 -1
- package/dist/core/delegation/worker-attempt-executor.d.ts.map +1 -1
- package/dist/core/delegation/worker-attempt-executor.js +7 -2
- package/dist/core/delegation/worker-attempt-executor.js.map +1 -1
- package/dist/core/delegation/worker-authority-resolver.d.ts +2 -0
- package/dist/core/delegation/worker-authority-resolver.d.ts.map +1 -1
- package/dist/core/delegation/worker-authority-resolver.js +49 -6
- package/dist/core/delegation/worker-authority-resolver.js.map +1 -1
- package/dist/core/delegation/worker-delegation-controller.d.ts +8 -5
- package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
- package/dist/core/delegation/worker-delegation-controller.js +158 -40
- package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
- package/dist/core/delegation/worker-fleet-limits.d.ts +9 -2
- package/dist/core/delegation/worker-fleet-limits.d.ts.map +1 -1
- package/dist/core/delegation/worker-fleet-limits.js +39 -3
- package/dist/core/delegation/worker-fleet-limits.js.map +1 -1
- package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -1
- package/dist/core/delegation/worker-lane-projection.js +10 -0
- package/dist/core/delegation/worker-lane-projection.js.map +1 -1
- package/dist/core/delegation/worker-lease-heartbeat.d.ts +16 -0
- package/dist/core/delegation/worker-lease-heartbeat.d.ts.map +1 -0
- package/dist/core/delegation/worker-lease-heartbeat.js +37 -0
- package/dist/core/delegation/worker-lease-heartbeat.js.map +1 -0
- package/dist/core/delegation/worker-lifecycle.d.ts +1 -0
- package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -1
- package/dist/core/delegation/worker-lifecycle.js +6 -0
- package/dist/core/delegation/worker-lifecycle.js.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.js +2 -1
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-profile-resolver.d.ts +28 -1
- package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -1
- package/dist/core/delegation/worker-profile-resolver.js +38 -9
- package/dist/core/delegation/worker-profile-resolver.js.map +1 -1
- package/dist/core/delegation/worker-runner.js +2 -2
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/delegation/worker-terminal-handoff-coordinator.d.ts +1 -0
- package/dist/core/delegation/worker-terminal-handoff-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-terminal-handoff-coordinator.js +1 -0
- package/dist/core/delegation/worker-terminal-handoff-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-tree-budget-coordinator.d.ts +4 -2
- package/dist/core/delegation/worker-tree-budget-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-tree-budget-coordinator.js +10 -2
- package/dist/core/delegation/worker-tree-budget-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-write-reservation-coordinator.d.ts +14 -0
- package/dist/core/delegation/worker-write-reservation-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-write-reservation-coordinator.js +121 -33
- package/dist/core/delegation/worker-write-reservation-coordinator.js.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.d.ts +5 -0
- package/dist/core/foreground-terminal-handoff-controller.d.ts.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.js +28 -12
- package/dist/core/foreground-terminal-handoff-controller.js.map +1 -1
- package/dist/core/orchestration/capability-gateway.d.ts +2 -1
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
- package/dist/core/orchestration/capability-gateway.js +9 -2
- package/dist/core/orchestration/capability-gateway.js.map +1 -1
- package/dist/core/orchestration/contracts.d.ts +16 -1
- package/dist/core/orchestration/contracts.d.ts.map +1 -1
- package/dist/core/orchestration/contracts.js +5 -0
- package/dist/core/orchestration/contracts.js.map +1 -1
- package/dist/core/orchestration/profile-registry.d.ts.map +1 -1
- package/dist/core/orchestration/profile-registry.js +38 -1
- package/dist/core/orchestration/profile-registry.js.map +1 -1
- package/dist/core/orchestration/risk-budget.d.ts +10 -0
- package/dist/core/orchestration/risk-budget.d.ts.map +1 -1
- package/dist/core/orchestration/risk-budget.js +14 -0
- package/dist/core/orchestration/risk-budget.js.map +1 -1
- package/dist/core/orchestration/task-runtime-reducer.d.ts +1 -0
- package/dist/core/orchestration/task-runtime-reducer.d.ts.map +1 -1
- package/dist/core/orchestration/task-runtime-reducer.js +34 -0
- package/dist/core/orchestration/task-runtime-reducer.js.map +1 -1
- package/dist/core/orchestration/task-runtime.d.ts +1 -0
- package/dist/core/orchestration/task-runtime.d.ts.map +1 -1
- package/dist/core/orchestration/task-runtime.js +24 -1
- package/dist/core/orchestration/task-runtime.js.map +1 -1
- package/dist/core/orchestration/worker-model-pins.d.ts +28 -0
- package/dist/core/orchestration/worker-model-pins.d.ts.map +1 -0
- package/dist/core/orchestration/worker-model-pins.js +141 -0
- package/dist/core/orchestration/worker-model-pins.js.map +1 -0
- package/dist/core/provider-prompt-contracts.d.ts.map +1 -1
- package/dist/core/provider-prompt-contracts.js +2 -1
- package/dist/core/provider-prompt-contracts.js.map +1 -1
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +8 -1
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +1 -0
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +26 -2
- package/dist/core/settings-manager.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 +13 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +3 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +26 -1
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +15 -1
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +234 -68
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +14 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-failure-recovery.d.ts +3 -0
- package/dist/core/tools/file-failure-recovery.d.ts.map +1 -1
- package/dist/core/tools/file-failure-recovery.js +11 -0
- package/dist/core/tools/file-failure-recovery.js.map +1 -1
- package/dist/core/tools/orchestration-panel.d.ts +1 -1
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
- package/dist/core/tools/orchestration-panel.js +1 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -1
- package/dist/core/tools/profile-writer.d.ts.map +1 -1
- package/dist/core/tools/profile-writer.js +2 -8
- package/dist/core/tools/profile-writer.js.map +1 -1
- package/dist/core/tools/search-command-guard.d.ts.map +1 -1
- package/dist/core/tools/search-command-guard.js +10 -3
- package/dist/core/tools/search-command-guard.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +10 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
- package/dist/modes/interactive/components/activity-lane.js +11 -2
- package/dist/modes/interactive/components/activity-lane.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/utils/shell.d.ts +2 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +3 -1
- package/dist/utils/shell.js.map +1 -1
- package/docs/harness-architecture.md +6 -3
- package/docs/settings.md +39 -6
- package/docs/tool-repair.md +1 -1
- package/docs/worker-profiles.md +2 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-terminal-handoff-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-terminal-handoff-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { isLaneRecord, isLaneTerminalStatus, type LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport { MAX_ORCHESTRATION_ATTEMPTS, MAX_ORCHESTRATION_IDENTIFIER_LENGTH } from \"../orchestration/contracts.ts\";\n\nexport interface WorkerTerminalHandoff {\n\tterminalAttemptId: string;\n\tparentAgentId: string;\n\tchildAgentId: string;\n\trecord: LaneRecord;\n}\n\n/** Per-entry ceiling; combined with the durable attempt cap this bounds retained memory to 4 MiB. */\nexport const MAX_WORKER_TERMINAL_HANDOFF_BYTES = 16 * 1024;\n\nexport type WorkerTerminalHandoffDelivery = \"delivered\" | \"retained\";\nexport type WorkerTerminalHandoffRetention = \"retained\" | \"replay\";\n\nexport interface WorkerTerminalHandoffDrainResult {\n\tattempted: number;\n\tdelivered: number;\n\terrors: number;\n\tretained: number;\n}\n\nexport interface WorkerTerminalHandoffRehydrationResult {\n\tadded: number;\n\treplayed: number;\n\tdrain: WorkerTerminalHandoffDrainResult;\n}\n\nexport interface WorkerTerminalHandoffCoordinatorOptions {\n\tdeliver(handoff: Readonly<WorkerTerminalHandoff>): WorkerTerminalHandoffDelivery;\n\tonDeliveryError?(handoff: Readonly<WorkerTerminalHandoff>, error: unknown): void;\n}\n\nfunction assertIdentifier(value: unknown, label: string): asserts value is string {\n\tif (\n\t\ttypeof value !== \"string\" ||\n\t\t!value ||\n\t\tvalue.trim() !== value ||\n\t\tvalue.length > MAX_ORCHESTRATION_IDENTIFIER_LENGTH\n\t) {\n\t\tthrow new TypeError(`${label} must be a bounded non-empty canonical string.`);\n\t}\n}\n\nfunction snapshotHandoff(handoff: WorkerTerminalHandoff): WorkerTerminalHandoff {\n\tassertIdentifier(handoff.terminalAttemptId, \"Worker terminal attempt ID\");\n\tassertIdentifier(handoff.parentAgentId, \"Worker terminal parent agent ID\");\n\tassertIdentifier(handoff.childAgentId, \"Worker terminal child agent ID\");\n\tif (!isLaneRecord(handoff.record)) {\n\t\tthrow new TypeError(\"Worker terminal handoff requires a valid lane record.\");\n\t}\n\tif (!isLaneTerminalStatus(handoff.record.status)) {\n\t\tthrow new TypeError(\"Worker terminal handoff requires a terminal lane record.\");\n\t}\n\tconst snapshot = { ...handoff, record: { ...handoff.record } };\n\tif (Buffer.byteLength(JSON.stringify(snapshot), \"utf-8\") > MAX_WORKER_TERMINAL_HANDOFF_BYTES) {\n\t\tthrow new TypeError(`Worker terminal handoff exceeds its ${MAX_WORKER_TERMINAL_HANDOFF_BYTES} byte limit.`);\n\t}\n\treturn snapshot;\n}\n\nfunction cloneHandoff(handoff: WorkerTerminalHandoff): WorkerTerminalHandoff {\n\treturn { ...handoff, record: { ...handoff.record } };\n}\n\n/**\n * Bounded process-local outbox for parent terminal handoffs. Delivery is driven only by explicit\n * terminal, capacity, state-change, and recovery calls; this owner never creates a timer or poll.\n */\nexport class WorkerTerminalHandoffCoordinator {\n\tprivate readonly options: WorkerTerminalHandoffCoordinatorOptions;\n\tprivate readonly pending = new Map<string, WorkerTerminalHandoff>();\n\tprivate draining = false;\n\tprivate redrainRequested = false;\n\tprivate disposed = false;\n\n\tconstructor(options: WorkerTerminalHandoffCoordinatorOptions) {\n\t\tthis.options = options;\n\t}\n\n\tget retainedCount(): number {\n\t\treturn this.pending.size;\n\t}\n\n\tretained(): WorkerTerminalHandoff[] {\n\t\treturn [...this.pending.values()].map(cloneHandoff);\n\t}\n\n\t/** Retain one terminal handoff snapshot. Structurally identical pending replays are inert; conflicts fail closed. */\n\tretain(handoff: WorkerTerminalHandoff): WorkerTerminalHandoffRetention {\n\t\tthis.assertActive();\n\t\tconst snapshot = snapshotHandoff(handoff);\n\t\tconst existing = this.pending.get(snapshot.terminalAttemptId);\n\t\tif (existing) {\n\t\t\tif (isDeepStrictEqual(existing, snapshot)) return \"replay\";\n\t\t\tthrow new Error(\n\t\t\t\t`Worker terminal handoff attempt ${snapshot.terminalAttemptId} conflicts with its retained payload.`,\n\t\t\t);\n\t\t}\n\t\tthis.assertCapacity(this.pending.size + 1);\n\t\tthis.pending.set(snapshot.terminalAttemptId, snapshot);\n\t\tif (this.draining) this.redrainRequested = true;\n\t\treturn \"retained\";\n\t}\n\n\t/**\n\t * Atomically adopt a durable recovery snapshot, then make one explicit delivery pass. Repeated\n\t * attempt IDs in the recovery snapshot must carry structurally equivalent data.\n\t */\n\trehydrate(handoffs: readonly WorkerTerminalHandoff[]): WorkerTerminalHandoffRehydrationResult {\n\t\tthis.assertActive();\n\t\tconst staged = new Map(this.pending);\n\t\tconst additions: WorkerTerminalHandoff[] = [];\n\t\tlet replayed = 0;\n\t\tfor (const handoff of handoffs) {\n\t\t\tconst snapshot = snapshotHandoff(handoff);\n\t\t\tconst existing = staged.get(snapshot.terminalAttemptId);\n\t\t\tif (existing) {\n\t\t\t\tif (!isDeepStrictEqual(existing, snapshot)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Worker terminal handoff attempt ${snapshot.terminalAttemptId} conflicts with its retained payload.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treplayed += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.assertCapacity(staged.size + 1);\n\t\t\tstaged.set(snapshot.terminalAttemptId, snapshot);\n\t\t\tadditions.push(snapshot);\n\t\t}\n\t\tfor (const handoff of additions) this.pending.set(handoff.terminalAttemptId, handoff);\n\t\treturn { added: additions.length, replayed, drain: this.signal() };\n\t}\n\n\t/** Explicit terminal/capacity/state-change event. Reentrant signals coalesce into a redrain. */\n\tsignal(): WorkerTerminalHandoffDrainResult {\n\t\tif (this.disposed) return { attempted: 0, delivered: 0, errors: 0, retained: 0 };\n\t\tif (this.draining) {\n\t\t\tthis.redrainRequested = true;\n\t\t\treturn { attempted: 0, delivered: 0, errors: 0, retained: this.pending.size };\n\t\t}\n\n\t\tlet attempted = 0;\n\t\tlet delivered = 0;\n\t\tlet errors = 0;\n\t\tlet stagnantPasses = 0;\n\t\tthis.draining = true;\n\t\tthis.redrainRequested = true;\n\t\ttry {\n\t\t\twhile (this.redrainRequested && !this.disposed) {\n\t\t\t\tthis.redrainRequested = false;\n\t\t\t\tconst batch = [...this.pending.values()];\n\t\t\t\tlet passChanged = false;\n\t\t\t\tfor (const retained of batch) {\n\t\t\t\t\tif (this.disposed || this.pending.get(retained.terminalAttemptId) !== retained) continue;\n\t\t\t\t\tattempted += 1;\n\t\t\t\t\tlet result: WorkerTerminalHandoffDelivery;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = this.options.deliver(cloneHandoff(retained));\n\t\t\t\t\t\tif (result !== \"delivered\" && result !== \"retained\") {\n\t\t\t\t\t\t\tthrow new TypeError(\"Worker terminal handoff delivery returned an invalid result.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\terrors += 1;\n\t\t\t\t\t\tthis.reportDeliveryError(retained, error);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (result !== \"delivered\" || this.pending.get(retained.terminalAttemptId) !== retained) continue;\n\t\t\t\t\tthis.pending.delete(retained.terminalAttemptId);\n\t\t\t\t\tdelivered += 1;\n\t\t\t\t\tpassChanged = true;\n\t\t\t\t}\n\n\t\t\t\tif (passChanged || batch.some((entry) => this.pending.get(entry.terminalAttemptId) !== entry)) {\n\t\t\t\t\tstagnantPasses = 0;\n\t\t\t\t} else {\n\t\t\t\t\tstagnantPasses += 1;\n\t\t\t\t}\n\t\t\t\t// A self-signalling retained callback cannot spin forever. One unchanged redrain is enough\n\t\t\t\t// to observe every synchronous state mutation that preceded the nested signal.\n\t\t\t\tif (this.redrainRequested && stagnantPasses >= 2) this.redrainRequested = false;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.draining = false;\n\t\t\tthis.redrainRequested = false;\n\t\t}\n\t\treturn { attempted, delivered, errors, retained: this.pending.size };\n\t}\n\n\tclear(): void {\n\t\tthis.pending.clear();\n\t\tthis.redrainRequested = false;\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tthis.clear();\n\t}\n\n\tprivate assertActive(): void {\n\t\tif (this.disposed) throw new Error(\"Worker terminal handoff coordinator is disposed.\");\n\t}\n\n\tprivate assertCapacity(size: number): void {\n\t\tif (size <= MAX_ORCHESTRATION_ATTEMPTS) return;\n\t\tthrow new Error(`Worker terminal handoff retention reached its ${MAX_ORCHESTRATION_ATTEMPTS} attempt limit.`);\n\t}\n\n\tprivate reportDeliveryError(handoff: WorkerTerminalHandoff, error: unknown): void {\n\t\ttry {\n\t\t\tthis.options.onDeliveryError?.(cloneHandoff(handoff), error);\n\t\t} catch {\n\t\t\t// Diagnostics cannot consume or unblock a retained terminal handoff.\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"worker-terminal-handoff-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-terminal-handoff-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { isLaneRecord, isLaneTerminalStatus, type LaneRecord } from \"../autonomy/lane-tracker.ts\";\nimport { MAX_ORCHESTRATION_ATTEMPTS, MAX_ORCHESTRATION_IDENTIFIER_LENGTH } from \"../orchestration/contracts.ts\";\n\nexport interface WorkerTerminalHandoff {\n\tterminalAttemptId: string;\n\tparentAgentId: string;\n\tchildAgentId: string;\n\trecord: LaneRecord;\n}\n\nexport const WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE =\n\t\"CAVEMAN MODE - MANDATORY: completion_error means a worker execution failed, not harness failure. Tool timeout, provider/model/API/network/WebSocket/fetch/overload, and exhausted retry are worker failures. NEVER call any of them harness failure. NEVER stop, cancel, or interrupt healthy siblings for them. A delivered terminal handoff proves persistence and delivery worked. Harness failure requires direct evidence that orchestration state, terminal delivery, or control broke. Otherwise read evidence and continue or replan.\";\n\n/** Per-entry ceiling; combined with the durable attempt cap this bounds retained memory to 4 MiB. */\nexport const MAX_WORKER_TERMINAL_HANDOFF_BYTES = 16 * 1024;\n\nexport type WorkerTerminalHandoffDelivery = \"delivered\" | \"retained\";\nexport type WorkerTerminalHandoffRetention = \"retained\" | \"replay\";\n\nexport interface WorkerTerminalHandoffDrainResult {\n\tattempted: number;\n\tdelivered: number;\n\terrors: number;\n\tretained: number;\n}\n\nexport interface WorkerTerminalHandoffRehydrationResult {\n\tadded: number;\n\treplayed: number;\n\tdrain: WorkerTerminalHandoffDrainResult;\n}\n\nexport interface WorkerTerminalHandoffCoordinatorOptions {\n\tdeliver(handoff: Readonly<WorkerTerminalHandoff>): WorkerTerminalHandoffDelivery;\n\tonDeliveryError?(handoff: Readonly<WorkerTerminalHandoff>, error: unknown): void;\n}\n\nfunction assertIdentifier(value: unknown, label: string): asserts value is string {\n\tif (\n\t\ttypeof value !== \"string\" ||\n\t\t!value ||\n\t\tvalue.trim() !== value ||\n\t\tvalue.length > MAX_ORCHESTRATION_IDENTIFIER_LENGTH\n\t) {\n\t\tthrow new TypeError(`${label} must be a bounded non-empty canonical string.`);\n\t}\n}\n\nfunction snapshotHandoff(handoff: WorkerTerminalHandoff): WorkerTerminalHandoff {\n\tassertIdentifier(handoff.terminalAttemptId, \"Worker terminal attempt ID\");\n\tassertIdentifier(handoff.parentAgentId, \"Worker terminal parent agent ID\");\n\tassertIdentifier(handoff.childAgentId, \"Worker terminal child agent ID\");\n\tif (!isLaneRecord(handoff.record)) {\n\t\tthrow new TypeError(\"Worker terminal handoff requires a valid lane record.\");\n\t}\n\tif (!isLaneTerminalStatus(handoff.record.status)) {\n\t\tthrow new TypeError(\"Worker terminal handoff requires a terminal lane record.\");\n\t}\n\tconst snapshot = { ...handoff, record: { ...handoff.record } };\n\tif (Buffer.byteLength(JSON.stringify(snapshot), \"utf-8\") > MAX_WORKER_TERMINAL_HANDOFF_BYTES) {\n\t\tthrow new TypeError(`Worker terminal handoff exceeds its ${MAX_WORKER_TERMINAL_HANDOFF_BYTES} byte limit.`);\n\t}\n\treturn snapshot;\n}\n\nfunction cloneHandoff(handoff: WorkerTerminalHandoff): WorkerTerminalHandoff {\n\treturn { ...handoff, record: { ...handoff.record } };\n}\n\n/**\n * Bounded process-local outbox for parent terminal handoffs. Delivery is driven only by explicit\n * terminal, capacity, state-change, and recovery calls; this owner never creates a timer or poll.\n */\nexport class WorkerTerminalHandoffCoordinator {\n\tprivate readonly options: WorkerTerminalHandoffCoordinatorOptions;\n\tprivate readonly pending = new Map<string, WorkerTerminalHandoff>();\n\tprivate draining = false;\n\tprivate redrainRequested = false;\n\tprivate disposed = false;\n\n\tconstructor(options: WorkerTerminalHandoffCoordinatorOptions) {\n\t\tthis.options = options;\n\t}\n\n\tget retainedCount(): number {\n\t\treturn this.pending.size;\n\t}\n\n\tretained(): WorkerTerminalHandoff[] {\n\t\treturn [...this.pending.values()].map(cloneHandoff);\n\t}\n\n\t/** Retain one terminal handoff snapshot. Structurally identical pending replays are inert; conflicts fail closed. */\n\tretain(handoff: WorkerTerminalHandoff): WorkerTerminalHandoffRetention {\n\t\tthis.assertActive();\n\t\tconst snapshot = snapshotHandoff(handoff);\n\t\tconst existing = this.pending.get(snapshot.terminalAttemptId);\n\t\tif (existing) {\n\t\t\tif (isDeepStrictEqual(existing, snapshot)) return \"replay\";\n\t\t\tthrow new Error(\n\t\t\t\t`Worker terminal handoff attempt ${snapshot.terminalAttemptId} conflicts with its retained payload.`,\n\t\t\t);\n\t\t}\n\t\tthis.assertCapacity(this.pending.size + 1);\n\t\tthis.pending.set(snapshot.terminalAttemptId, snapshot);\n\t\tif (this.draining) this.redrainRequested = true;\n\t\treturn \"retained\";\n\t}\n\n\t/**\n\t * Atomically adopt a durable recovery snapshot, then make one explicit delivery pass. Repeated\n\t * attempt IDs in the recovery snapshot must carry structurally equivalent data.\n\t */\n\trehydrate(handoffs: readonly WorkerTerminalHandoff[]): WorkerTerminalHandoffRehydrationResult {\n\t\tthis.assertActive();\n\t\tconst staged = new Map(this.pending);\n\t\tconst additions: WorkerTerminalHandoff[] = [];\n\t\tlet replayed = 0;\n\t\tfor (const handoff of handoffs) {\n\t\t\tconst snapshot = snapshotHandoff(handoff);\n\t\t\tconst existing = staged.get(snapshot.terminalAttemptId);\n\t\t\tif (existing) {\n\t\t\t\tif (!isDeepStrictEqual(existing, snapshot)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Worker terminal handoff attempt ${snapshot.terminalAttemptId} conflicts with its retained payload.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treplayed += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.assertCapacity(staged.size + 1);\n\t\t\tstaged.set(snapshot.terminalAttemptId, snapshot);\n\t\t\tadditions.push(snapshot);\n\t\t}\n\t\tfor (const handoff of additions) this.pending.set(handoff.terminalAttemptId, handoff);\n\t\treturn { added: additions.length, replayed, drain: this.signal() };\n\t}\n\n\t/** Explicit terminal/capacity/state-change event. Reentrant signals coalesce into a redrain. */\n\tsignal(): WorkerTerminalHandoffDrainResult {\n\t\tif (this.disposed) return { attempted: 0, delivered: 0, errors: 0, retained: 0 };\n\t\tif (this.draining) {\n\t\t\tthis.redrainRequested = true;\n\t\t\treturn { attempted: 0, delivered: 0, errors: 0, retained: this.pending.size };\n\t\t}\n\n\t\tlet attempted = 0;\n\t\tlet delivered = 0;\n\t\tlet errors = 0;\n\t\tlet stagnantPasses = 0;\n\t\tthis.draining = true;\n\t\tthis.redrainRequested = true;\n\t\ttry {\n\t\t\twhile (this.redrainRequested && !this.disposed) {\n\t\t\t\tthis.redrainRequested = false;\n\t\t\t\tconst batch = [...this.pending.values()];\n\t\t\t\tlet passChanged = false;\n\t\t\t\tfor (const retained of batch) {\n\t\t\t\t\tif (this.disposed || this.pending.get(retained.terminalAttemptId) !== retained) continue;\n\t\t\t\t\tattempted += 1;\n\t\t\t\t\tlet result: WorkerTerminalHandoffDelivery;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = this.options.deliver(cloneHandoff(retained));\n\t\t\t\t\t\tif (result !== \"delivered\" && result !== \"retained\") {\n\t\t\t\t\t\t\tthrow new TypeError(\"Worker terminal handoff delivery returned an invalid result.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\terrors += 1;\n\t\t\t\t\t\tthis.reportDeliveryError(retained, error);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (result !== \"delivered\" || this.pending.get(retained.terminalAttemptId) !== retained) continue;\n\t\t\t\t\tthis.pending.delete(retained.terminalAttemptId);\n\t\t\t\t\tdelivered += 1;\n\t\t\t\t\tpassChanged = true;\n\t\t\t\t}\n\n\t\t\t\tif (passChanged || batch.some((entry) => this.pending.get(entry.terminalAttemptId) !== entry)) {\n\t\t\t\t\tstagnantPasses = 0;\n\t\t\t\t} else {\n\t\t\t\t\tstagnantPasses += 1;\n\t\t\t\t}\n\t\t\t\t// A self-signalling retained callback cannot spin forever. One unchanged redrain is enough\n\t\t\t\t// to observe every synchronous state mutation that preceded the nested signal.\n\t\t\t\tif (this.redrainRequested && stagnantPasses >= 2) this.redrainRequested = false;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.draining = false;\n\t\t\tthis.redrainRequested = false;\n\t\t}\n\t\treturn { attempted, delivered, errors, retained: this.pending.size };\n\t}\n\n\tclear(): void {\n\t\tthis.pending.clear();\n\t\tthis.redrainRequested = false;\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tthis.clear();\n\t}\n\n\tprivate assertActive(): void {\n\t\tif (this.disposed) throw new Error(\"Worker terminal handoff coordinator is disposed.\");\n\t}\n\n\tprivate assertCapacity(size: number): void {\n\t\tif (size <= MAX_ORCHESTRATION_ATTEMPTS) return;\n\t\tthrow new Error(`Worker terminal handoff retention reached its ${MAX_ORCHESTRATION_ATTEMPTS} attempt limit.`);\n\t}\n\n\tprivate reportDeliveryError(handoff: WorkerTerminalHandoff, error: unknown): void {\n\t\ttry {\n\t\t\tthis.options.onDeliveryError?.(cloneHandoff(handoff), error);\n\t\t} catch {\n\t\t\t// Diagnostics cannot consume or unblock a retained terminal handoff.\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { BoundedCompletionFailureError } from "../autonomy/bounded-completion.ts";
|
|
1
2
|
import { type SharedCapabilityBudget } from "../orchestration/capability-gateway.ts";
|
|
2
3
|
import type { AttemptUsageSnapshot, RiskBudget } from "../orchestration/contracts.ts";
|
|
3
|
-
export
|
|
4
|
-
|
|
4
|
+
export type WorkerTreeBudgetField = "maxTokens" | "maxCostUsd" | "maxToolCalls" | "maxWallClockMs" | "maxAttempts";
|
|
5
|
+
export declare class WorkerTreeBudgetExceededError extends BoundedCompletionFailureError {
|
|
6
|
+
readonly field: WorkerTreeBudgetField;
|
|
5
7
|
constructor(field: WorkerTreeBudgetExceededError["field"], subject: string);
|
|
6
8
|
}
|
|
7
9
|
export interface WorkerTreeBudgetSeed {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-tree-budget-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-tree-budget-coordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker-tree-budget-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-tree-budget-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mCAAmC,CAAC;AAMlF,OAAO,EAIN,KAAK,sBAAsB,EAC3B,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAGtF,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAUnH,qBAAa,6BAA8B,SAAQ,6BAA6B;IAC/E,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IAEtC,YAAY,KAAK,EAAE,6BAA6B,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAQzE;CACD;AAmBD,MAAM,WAAW,oBAAoB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,oBAAoB,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IAC1C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC1D,QAAQ,EAAE,QAAQ,CACjB,MAAM,CACL,MAAM,EACN;QACC,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE;YAAE,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACrC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;KACjC,CACD,CACD,CAAC;IACF,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,oBAAoB,CAAA;KAAE,CAAC,CAAC,CAAC;CACxE;AAED,2FAA2F;AAC3F,wBAAgB,4BAA4B,CAC3C,QAAQ,EAAE,0BAA0B,EACpC,WAAW,EAAE,MAAM,GACjB,oBAAoB,EAAE,CAYxB;AAMD,oGAAoG;AACpG,qBAAa,2BAA2B;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsC;IAE5D,UAAU,CAAC,IAAI,EAAE;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC;QACnB,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;QACvC,YAAY,EAAE,oBAAoB,CAAC;KACnC,GAAG,sBAAsB,CA+BzB;IAED,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,qBAAqB;IAmC7B,OAAO,CAAC,YAAY;IA4CpB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;CA2BvB"}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import { BoundedCompletionFailureError } from "../autonomy/bounded-completion.js";
|
|
1
2
|
import { attemptUsageFromGatewayUsage, EMPTY_ATTEMPT_USAGE, reconcileAttemptUsage, } from "../orchestration/attempt-usage.js";
|
|
2
3
|
import { budgetedTokens, } from "../orchestration/capability-gateway.js";
|
|
3
4
|
import { intersectRiskBudgets } from "../orchestration/risk-budget.js";
|
|
4
|
-
|
|
5
|
+
const WORKER_TREE_BUDGET_REASON_CODES = {
|
|
6
|
+
maxTokens: "worker_tree_token_budget_exhausted",
|
|
7
|
+
maxCostUsd: "worker_tree_cost_budget_exhausted",
|
|
8
|
+
maxToolCalls: "worker_tree_tool_call_budget_exhausted",
|
|
9
|
+
maxWallClockMs: "worker_tree_wall_clock_budget_exhausted",
|
|
10
|
+
maxAttempts: "worker_tree_attempt_budget_exhausted",
|
|
11
|
+
};
|
|
12
|
+
export class WorkerTreeBudgetExceededError extends BoundedCompletionFailureError {
|
|
5
13
|
constructor(field, subject) {
|
|
6
|
-
super(`Worker orchestration tree budget '${field}' is exhausted before ${subject}.`);
|
|
14
|
+
super("budget_exhausted", WORKER_TREE_BUDGET_REASON_CODES[field], `Worker orchestration tree budget '${field}' is exhausted before ${subject}.`);
|
|
7
15
|
this.name = "WorkerTreeBudgetExceededError";
|
|
8
16
|
this.field = field;
|
|
9
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-tree-budget-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-tree-budget-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tattemptUsageFromGatewayUsage,\n\tEMPTY_ATTEMPT_USAGE,\n\treconcileAttemptUsage,\n} from \"../orchestration/attempt-usage.ts\";\nimport {\n\tbudgetedTokens,\n\ttype GatewayUsageSnapshot,\n\ttype ProviderBudgetReservation,\n\ttype SharedCapabilityBudget,\n} from \"../orchestration/capability-gateway.ts\";\nimport type { AttemptUsageSnapshot, RiskBudget } from \"../orchestration/contracts.ts\";\nimport { intersectRiskBudgets } from \"../orchestration/risk-budget.ts\";\n\nexport class WorkerTreeBudgetExceededError extends Error {\n\treadonly field: \"maxTokens\" | \"maxCostUsd\" | \"maxToolCalls\" | \"maxWallClockMs\" | \"maxAttempts\";\n\n\tconstructor(field: WorkerTreeBudgetExceededError[\"field\"], subject: string) {\n\t\tsuper(`Worker orchestration tree budget '${field}' is exhausted before ${subject}.`);\n\t\tthis.name = \"WorkerTreeBudgetExceededError\";\n\t\tthis.field = field;\n\t}\n}\n\ninterface TreeBudgetState {\n\tbudget: RiskBudget;\n\tattempts: Map<string, AttemptUsageSnapshot>;\n\treservations: Map<string, { maxTokens: number }>;\n\twaiters: ProviderBudgetWaiter[];\n}\n\ninterface ProviderBudgetWaiter {\n\tattemptId: string;\n\trequestedMaxTokens: number;\n\tsubject: string;\n\tsignal?: AbortSignal;\n\tresolve(reservation: ProviderBudgetReservation): void;\n\treject(error: unknown): void;\n\tonAbort?: () => void;\n}\n\nexport interface WorkerTreeBudgetSeed {\n\tattemptId: string;\n\tusage: AttemptUsageSnapshot;\n}\n\nexport interface WorkerTreeBudgetProjection {\n\tagents: Readonly<Record<string, { rootAgentId: string }>>;\n\tattempts: Readonly<\n\t\tRecord<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tattemptId: string;\n\t\t\t\tagentId?: string;\n\t\t\t\tdispatch: { logicalLaneId?: string };\n\t\t\t\tcheckpointIds: readonly string[];\n\t\t\t}\n\t\t>\n\t>;\n\tcheckpoints: Readonly<Record<string, { usage?: AttemptUsageSnapshot }>>;\n}\n\n/** Rebuild every durable tree attempt, including attempts with no usage checkpoint yet. */\nexport function collectWorkerTreeBudgetSeeds(\n\tsnapshot: WorkerTreeBudgetProjection,\n\trootAgentId: string,\n): WorkerTreeBudgetSeed[] {\n\tconst seeds: WorkerTreeBudgetSeed[] = [];\n\tfor (const attempt of Object.values(snapshot.attempts)) {\n\t\tconst attemptAgentId = attempt.agentId ?? attempt.dispatch.logicalLaneId;\n\t\tif (!attemptAgentId || snapshot.agents[attemptAgentId]?.rootAgentId !== rootAgentId) continue;\n\t\tconst usage = [...attempt.checkpointIds]\n\t\t\t.reverse()\n\t\t\t.map((checkpointId) => snapshot.checkpoints[checkpointId]?.usage)\n\t\t\t.find((candidate): candidate is AttemptUsageSnapshot => candidate !== undefined);\n\t\tseeds.push({ attemptId: attempt.attemptId, usage: usage ?? EMPTY_ATTEMPT_USAGE });\n\t}\n\treturn seeds;\n}\n\nfunction abortReason(signal: AbortSignal): unknown {\n\treturn signal.reason ?? new Error(\"Worker provider budget reservation was aborted.\");\n}\n\n/** One in-memory aggregate reconstructed from durable checkpoints whenever a root is first used. */\nexport class WorkerTreeBudgetCoordinator {\n\tprivate readonly trees = new Map<string, TreeBudgetState>();\n\n\tcreatePort(args: {\n\t\trootAgentId: string;\n\t\tattemptId: string;\n\t\tbudget: RiskBudget;\n\t\tseeds: readonly WorkerTreeBudgetSeed[];\n\t\tinitialUsage: AttemptUsageSnapshot;\n\t}): SharedCapabilityBudget {\n\t\tlet state = this.trees.get(args.rootAgentId);\n\t\tif (!state) {\n\t\t\tstate = { budget: structuredClone(args.budget), attempts: new Map(), reservations: new Map(), waiters: [] };\n\t\t\tthis.trees.set(args.rootAgentId, state);\n\t\t} else {\n\t\t\tstate.budget = intersectRiskBudgets(state.budget, args.budget);\n\t\t}\n\t\tfor (const seed of args.seeds) {\n\t\t\tstate.attempts.set(\n\t\t\t\tseed.attemptId,\n\t\t\t\treconcileAttemptUsage(state.attempts.get(seed.attemptId) ?? EMPTY_ATTEMPT_USAGE, seed.usage),\n\t\t\t);\n\t\t}\n\t\tstate.attempts.set(\n\t\t\targs.attemptId,\n\t\t\treconcileAttemptUsage(state.attempts.get(args.attemptId) ?? EMPTY_ATTEMPT_USAGE, args.initialUsage),\n\t\t);\n\t\tconst tree = state;\n\t\treturn {\n\t\t\tassertBudgetAvailable: (subject) => this.assertAvailable(tree, subject),\n\t\t\trecordAttemptUsage: (usage) => this.recordAttemptUsage(tree, args.attemptId, usage),\n\t\t\tremainingTokens: () => {\n\t\t\t\tconst maximum = tree.budget.maxTokens;\n\t\t\t\treturn maximum === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: Math.max(0, maximum - this.budgetedTokens(tree) - this.reservedTokens(tree));\n\t\t\t},\n\t\t\treserveProviderBudget: (requestedMaxTokens, subject, signal) =>\n\t\t\t\tthis.reserveProviderBudget(tree, args.attemptId, requestedMaxTokens, subject, signal),\n\t\t};\n\t}\n\n\tprivate recordAttemptUsage(state: TreeBudgetState, attemptId: string, usage: GatewayUsageSnapshot): void {\n\t\tconst previous = state.attempts.get(attemptId);\n\t\tconst merged = reconcileAttemptUsage(previous ?? EMPTY_ATTEMPT_USAGE, attemptUsageFromGatewayUsage(usage));\n\t\tstate.attempts.set(attemptId, merged);\n\t\tconst reservation = state.reservations.get(attemptId);\n\t\tif (reservation && previous) {\n\t\t\treservation.maxTokens = Math.max(\n\t\t\t\t0,\n\t\t\t\treservation.maxTokens - Math.max(0, budgetedTokens(merged) - budgetedTokens(previous)),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate reserveProviderBudget(\n\t\tstate: TreeBudgetState,\n\t\tattemptId: string,\n\t\trequestedMaxTokens: number,\n\t\tsubject: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<ProviderBudgetReservation> {\n\t\tif (!Number.isSafeInteger(requestedMaxTokens) || requestedMaxTokens <= 0) {\n\t\t\treturn Promise.reject(new Error(\"Worker provider token reservation must be a positive safe integer.\"));\n\t\t}\n\t\tif (signal?.aborted) return Promise.reject(abortReason(signal));\n\t\treturn new Promise<ProviderBudgetReservation>((resolve, reject) => {\n\t\t\tconst waiter: ProviderBudgetWaiter = {\n\t\t\t\tattemptId,\n\t\t\t\trequestedMaxTokens,\n\t\t\t\tsubject,\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t};\n\t\t\tif (signal) {\n\t\t\t\twaiter.onAbort = () => {\n\t\t\t\t\tconst index = state.waiters.indexOf(waiter);\n\t\t\t\t\tif (index < 0) return;\n\t\t\t\t\tstate.waiters.splice(index, 1);\n\t\t\t\t\treject(abortReason(signal));\n\t\t\t\t\tthis.drainWaiters(state);\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", waiter.onAbort, { once: true });\n\t\t\t}\n\t\t\tstate.waiters.push(waiter);\n\t\t\tthis.drainWaiters(state);\n\t\t});\n\t}\n\n\tprivate drainWaiters(state: TreeBudgetState): void {\n\t\twhile (state.waiters.length > 0) {\n\t\t\tconst waiter = state.waiters[0];\n\t\t\tif (!waiter) return;\n\t\t\ttry {\n\t\t\t\tthis.assertAvailable(state, waiter.subject);\n\t\t\t} catch (error) {\n\t\t\t\tstate.waiters.shift();\n\t\t\t\tthis.detachAbort(waiter);\n\t\t\t\twaiter.reject(error);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (state.reservations.has(waiter.attemptId)) return;\n\t\t\tif (\n\t\t\t\t(state.budget.maxCostUsd !== undefined || state.budget.maxWallClockMs !== undefined) &&\n\t\t\t\tstate.reservations.size > 0\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst availableTokens =\n\t\t\t\tstate.budget.maxTokens === undefined\n\t\t\t\t\t? waiter.requestedMaxTokens\n\t\t\t\t\t: Math.max(0, state.budget.maxTokens - this.budgetedTokens(state) - this.reservedTokens(state));\n\t\t\tif (availableTokens <= 0) return;\n\t\t\tconst maxTokens = Math.min(waiter.requestedMaxTokens, availableTokens);\n\t\t\tstate.waiters.shift();\n\t\t\tthis.detachAbort(waiter);\n\t\t\tconst reservationState = { maxTokens };\n\t\t\tstate.reservations.set(waiter.attemptId, reservationState);\n\t\t\tlet released = false;\n\t\t\twaiter.resolve({\n\t\t\t\tmaxTokens,\n\t\t\t\trelease: () => {\n\t\t\t\t\tif (released) return;\n\t\t\t\t\treleased = true;\n\t\t\t\t\tif (state.reservations.get(waiter.attemptId) === reservationState) {\n\t\t\t\t\t\tstate.reservations.delete(waiter.attemptId);\n\t\t\t\t\t}\n\t\t\t\t\tthis.drainWaiters(state);\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate detachAbort(waiter: ProviderBudgetWaiter): void {\n\t\tif (waiter.signal && waiter.onAbort) waiter.signal.removeEventListener(\"abort\", waiter.onAbort);\n\t}\n\n\tprivate budgetedTokens(state: TreeBudgetState): number {\n\t\treturn [...state.attempts.values()].reduce((total, usage) => total + budgetedTokens(usage), 0);\n\t}\n\n\tprivate reservedTokens(state: TreeBudgetState): number {\n\t\treturn [...state.reservations.values()].reduce((total, reservation) => total + reservation.maxTokens, 0);\n\t}\n\n\tprivate assertAvailable(state: TreeBudgetState, subject: string): void {\n\t\tconst usages = [...state.attempts.values()];\n\t\tif (state.budget.maxAttempts !== undefined && usages.length > state.budget.maxAttempts) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxAttempts\", subject);\n\t\t}\n\t\tif (state.budget.maxTokens !== undefined && this.budgetedTokens(state) >= state.budget.maxTokens) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxTokens\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxCostUsd !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.costUsd, 0) >= state.budget.maxCostUsd\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxCostUsd\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxToolCalls !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.toolCalls, 0) >= state.budget.maxToolCalls\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxToolCalls\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxWallClockMs !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.activeWallClockMs, 0) >= state.budget.maxWallClockMs\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxWallClockMs\", subject);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"worker-tree-budget-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-tree-budget-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import { BoundedCompletionFailureError } from \"../autonomy/bounded-completion.ts\";\nimport {\n\tattemptUsageFromGatewayUsage,\n\tEMPTY_ATTEMPT_USAGE,\n\treconcileAttemptUsage,\n} from \"../orchestration/attempt-usage.ts\";\nimport {\n\tbudgetedTokens,\n\ttype GatewayUsageSnapshot,\n\ttype ProviderBudgetReservation,\n\ttype SharedCapabilityBudget,\n} from \"../orchestration/capability-gateway.ts\";\nimport type { AttemptUsageSnapshot, RiskBudget } from \"../orchestration/contracts.ts\";\nimport { intersectRiskBudgets } from \"../orchestration/risk-budget.ts\";\n\nexport type WorkerTreeBudgetField = \"maxTokens\" | \"maxCostUsd\" | \"maxToolCalls\" | \"maxWallClockMs\" | \"maxAttempts\";\n\nconst WORKER_TREE_BUDGET_REASON_CODES: Readonly<Record<WorkerTreeBudgetField, string>> = {\n\tmaxTokens: \"worker_tree_token_budget_exhausted\",\n\tmaxCostUsd: \"worker_tree_cost_budget_exhausted\",\n\tmaxToolCalls: \"worker_tree_tool_call_budget_exhausted\",\n\tmaxWallClockMs: \"worker_tree_wall_clock_budget_exhausted\",\n\tmaxAttempts: \"worker_tree_attempt_budget_exhausted\",\n};\n\nexport class WorkerTreeBudgetExceededError extends BoundedCompletionFailureError {\n\treadonly field: WorkerTreeBudgetField;\n\n\tconstructor(field: WorkerTreeBudgetExceededError[\"field\"], subject: string) {\n\t\tsuper(\n\t\t\t\"budget_exhausted\",\n\t\t\tWORKER_TREE_BUDGET_REASON_CODES[field],\n\t\t\t`Worker orchestration tree budget '${field}' is exhausted before ${subject}.`,\n\t\t);\n\t\tthis.name = \"WorkerTreeBudgetExceededError\";\n\t\tthis.field = field;\n\t}\n}\n\ninterface TreeBudgetState {\n\tbudget: RiskBudget;\n\tattempts: Map<string, AttemptUsageSnapshot>;\n\treservations: Map<string, { maxTokens: number }>;\n\twaiters: ProviderBudgetWaiter[];\n}\n\ninterface ProviderBudgetWaiter {\n\tattemptId: string;\n\trequestedMaxTokens: number;\n\tsubject: string;\n\tsignal?: AbortSignal;\n\tresolve(reservation: ProviderBudgetReservation): void;\n\treject(error: unknown): void;\n\tonAbort?: () => void;\n}\n\nexport interface WorkerTreeBudgetSeed {\n\tattemptId: string;\n\tusage: AttemptUsageSnapshot;\n}\n\nexport interface WorkerTreeBudgetProjection {\n\tagents: Readonly<Record<string, { rootAgentId: string }>>;\n\tattempts: Readonly<\n\t\tRecord<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tattemptId: string;\n\t\t\t\tagentId?: string;\n\t\t\t\tdispatch: { logicalLaneId?: string };\n\t\t\t\tcheckpointIds: readonly string[];\n\t\t\t}\n\t\t>\n\t>;\n\tcheckpoints: Readonly<Record<string, { usage?: AttemptUsageSnapshot }>>;\n}\n\n/** Rebuild every durable tree attempt, including attempts with no usage checkpoint yet. */\nexport function collectWorkerTreeBudgetSeeds(\n\tsnapshot: WorkerTreeBudgetProjection,\n\trootAgentId: string,\n): WorkerTreeBudgetSeed[] {\n\tconst seeds: WorkerTreeBudgetSeed[] = [];\n\tfor (const attempt of Object.values(snapshot.attempts)) {\n\t\tconst attemptAgentId = attempt.agentId ?? attempt.dispatch.logicalLaneId;\n\t\tif (!attemptAgentId || snapshot.agents[attemptAgentId]?.rootAgentId !== rootAgentId) continue;\n\t\tconst usage = [...attempt.checkpointIds]\n\t\t\t.reverse()\n\t\t\t.map((checkpointId) => snapshot.checkpoints[checkpointId]?.usage)\n\t\t\t.find((candidate): candidate is AttemptUsageSnapshot => candidate !== undefined);\n\t\tseeds.push({ attemptId: attempt.attemptId, usage: usage ?? EMPTY_ATTEMPT_USAGE });\n\t}\n\treturn seeds;\n}\n\nfunction abortReason(signal: AbortSignal): unknown {\n\treturn signal.reason ?? new Error(\"Worker provider budget reservation was aborted.\");\n}\n\n/** One in-memory aggregate reconstructed from durable checkpoints whenever a root is first used. */\nexport class WorkerTreeBudgetCoordinator {\n\tprivate readonly trees = new Map<string, TreeBudgetState>();\n\n\tcreatePort(args: {\n\t\trootAgentId: string;\n\t\tattemptId: string;\n\t\tbudget: RiskBudget;\n\t\tseeds: readonly WorkerTreeBudgetSeed[];\n\t\tinitialUsage: AttemptUsageSnapshot;\n\t}): SharedCapabilityBudget {\n\t\tlet state = this.trees.get(args.rootAgentId);\n\t\tif (!state) {\n\t\t\tstate = { budget: structuredClone(args.budget), attempts: new Map(), reservations: new Map(), waiters: [] };\n\t\t\tthis.trees.set(args.rootAgentId, state);\n\t\t} else {\n\t\t\tstate.budget = intersectRiskBudgets(state.budget, args.budget);\n\t\t}\n\t\tfor (const seed of args.seeds) {\n\t\t\tstate.attempts.set(\n\t\t\t\tseed.attemptId,\n\t\t\t\treconcileAttemptUsage(state.attempts.get(seed.attemptId) ?? EMPTY_ATTEMPT_USAGE, seed.usage),\n\t\t\t);\n\t\t}\n\t\tstate.attempts.set(\n\t\t\targs.attemptId,\n\t\t\treconcileAttemptUsage(state.attempts.get(args.attemptId) ?? EMPTY_ATTEMPT_USAGE, args.initialUsage),\n\t\t);\n\t\tconst tree = state;\n\t\treturn {\n\t\t\tassertBudgetAvailable: (subject) => this.assertAvailable(tree, subject),\n\t\t\trecordAttemptUsage: (usage) => this.recordAttemptUsage(tree, args.attemptId, usage),\n\t\t\tremainingTokens: () => {\n\t\t\t\tconst maximum = tree.budget.maxTokens;\n\t\t\t\treturn maximum === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: Math.max(0, maximum - this.budgetedTokens(tree) - this.reservedTokens(tree));\n\t\t\t},\n\t\t\treserveProviderBudget: (requestedMaxTokens, subject, signal) =>\n\t\t\t\tthis.reserveProviderBudget(tree, args.attemptId, requestedMaxTokens, subject, signal),\n\t\t};\n\t}\n\n\tprivate recordAttemptUsage(state: TreeBudgetState, attemptId: string, usage: GatewayUsageSnapshot): void {\n\t\tconst previous = state.attempts.get(attemptId);\n\t\tconst merged = reconcileAttemptUsage(previous ?? EMPTY_ATTEMPT_USAGE, attemptUsageFromGatewayUsage(usage));\n\t\tstate.attempts.set(attemptId, merged);\n\t\tconst reservation = state.reservations.get(attemptId);\n\t\tif (reservation && previous) {\n\t\t\treservation.maxTokens = Math.max(\n\t\t\t\t0,\n\t\t\t\treservation.maxTokens - Math.max(0, budgetedTokens(merged) - budgetedTokens(previous)),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate reserveProviderBudget(\n\t\tstate: TreeBudgetState,\n\t\tattemptId: string,\n\t\trequestedMaxTokens: number,\n\t\tsubject: string,\n\t\tsignal?: AbortSignal,\n\t): Promise<ProviderBudgetReservation> {\n\t\tif (!Number.isSafeInteger(requestedMaxTokens) || requestedMaxTokens <= 0) {\n\t\t\treturn Promise.reject(new Error(\"Worker provider token reservation must be a positive safe integer.\"));\n\t\t}\n\t\tif (signal?.aborted) return Promise.reject(abortReason(signal));\n\t\treturn new Promise<ProviderBudgetReservation>((resolve, reject) => {\n\t\t\tconst waiter: ProviderBudgetWaiter = {\n\t\t\t\tattemptId,\n\t\t\t\trequestedMaxTokens,\n\t\t\t\tsubject,\n\t\t\t\t...(signal ? { signal } : {}),\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t};\n\t\t\tif (signal) {\n\t\t\t\twaiter.onAbort = () => {\n\t\t\t\t\tconst index = state.waiters.indexOf(waiter);\n\t\t\t\t\tif (index < 0) return;\n\t\t\t\t\tstate.waiters.splice(index, 1);\n\t\t\t\t\treject(abortReason(signal));\n\t\t\t\t\tthis.drainWaiters(state);\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", waiter.onAbort, { once: true });\n\t\t\t}\n\t\t\tstate.waiters.push(waiter);\n\t\t\tthis.drainWaiters(state);\n\t\t});\n\t}\n\n\tprivate drainWaiters(state: TreeBudgetState): void {\n\t\twhile (state.waiters.length > 0) {\n\t\t\tconst waiter = state.waiters[0];\n\t\t\tif (!waiter) return;\n\t\t\ttry {\n\t\t\t\tthis.assertAvailable(state, waiter.subject);\n\t\t\t} catch (error) {\n\t\t\t\tstate.waiters.shift();\n\t\t\t\tthis.detachAbort(waiter);\n\t\t\t\twaiter.reject(error);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (state.reservations.has(waiter.attemptId)) return;\n\t\t\tif (\n\t\t\t\t(state.budget.maxCostUsd !== undefined || state.budget.maxWallClockMs !== undefined) &&\n\t\t\t\tstate.reservations.size > 0\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst availableTokens =\n\t\t\t\tstate.budget.maxTokens === undefined\n\t\t\t\t\t? waiter.requestedMaxTokens\n\t\t\t\t\t: Math.max(0, state.budget.maxTokens - this.budgetedTokens(state) - this.reservedTokens(state));\n\t\t\tif (availableTokens <= 0) return;\n\t\t\tconst maxTokens = Math.min(waiter.requestedMaxTokens, availableTokens);\n\t\t\tstate.waiters.shift();\n\t\t\tthis.detachAbort(waiter);\n\t\t\tconst reservationState = { maxTokens };\n\t\t\tstate.reservations.set(waiter.attemptId, reservationState);\n\t\t\tlet released = false;\n\t\t\twaiter.resolve({\n\t\t\t\tmaxTokens,\n\t\t\t\trelease: () => {\n\t\t\t\t\tif (released) return;\n\t\t\t\t\treleased = true;\n\t\t\t\t\tif (state.reservations.get(waiter.attemptId) === reservationState) {\n\t\t\t\t\t\tstate.reservations.delete(waiter.attemptId);\n\t\t\t\t\t}\n\t\t\t\t\tthis.drainWaiters(state);\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate detachAbort(waiter: ProviderBudgetWaiter): void {\n\t\tif (waiter.signal && waiter.onAbort) waiter.signal.removeEventListener(\"abort\", waiter.onAbort);\n\t}\n\n\tprivate budgetedTokens(state: TreeBudgetState): number {\n\t\treturn [...state.attempts.values()].reduce((total, usage) => total + budgetedTokens(usage), 0);\n\t}\n\n\tprivate reservedTokens(state: TreeBudgetState): number {\n\t\treturn [...state.reservations.values()].reduce((total, reservation) => total + reservation.maxTokens, 0);\n\t}\n\n\tprivate assertAvailable(state: TreeBudgetState, subject: string): void {\n\t\tconst usages = [...state.attempts.values()];\n\t\tif (state.budget.maxAttempts !== undefined && usages.length > state.budget.maxAttempts) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxAttempts\", subject);\n\t\t}\n\t\tif (state.budget.maxTokens !== undefined && this.budgetedTokens(state) >= state.budget.maxTokens) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxTokens\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxCostUsd !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.costUsd, 0) >= state.budget.maxCostUsd\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxCostUsd\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxToolCalls !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.toolCalls, 0) >= state.budget.maxToolCalls\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxToolCalls\", subject);\n\t\t}\n\t\tif (\n\t\t\tstate.budget.maxWallClockMs !== undefined &&\n\t\t\tusages.reduce((total, usage) => total + usage.activeWallClockMs, 0) >= state.budget.maxWallClockMs\n\t\t) {\n\t\t\tthrow new WorkerTreeBudgetExceededError(\"maxWallClockMs\", subject);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AttemptRuntimeState } from "../orchestration/task-runtime.ts";
|
|
2
2
|
import type { WorkerExecutionPlan } from "./worker-execution-policy.ts";
|
|
3
|
+
import { type WorkerWriteReservationLease } from "./worker-write-reservation.ts";
|
|
3
4
|
export type WorkerWriteReservationAdmission = {
|
|
4
5
|
kind: "granted";
|
|
5
6
|
} | {
|
|
@@ -8,6 +9,10 @@ export type WorkerWriteReservationAdmission = {
|
|
|
8
9
|
kind: "denied";
|
|
9
10
|
reasonCode: "write_reservation_scope_invalid" | "write_reservation_unavailable";
|
|
10
11
|
};
|
|
12
|
+
export interface WorkerWriteReservationWaitYield {
|
|
13
|
+
laneId: string;
|
|
14
|
+
lease: WorkerWriteReservationLease;
|
|
15
|
+
}
|
|
11
16
|
export interface WorkerWriteReservationCoordinatorOptions {
|
|
12
17
|
agentDir: string;
|
|
13
18
|
getCwd(): string;
|
|
@@ -25,14 +30,23 @@ export declare class WorkerWriteReservationCoordinator {
|
|
|
25
30
|
private readonly options;
|
|
26
31
|
private readonly store;
|
|
27
32
|
private readonly leases;
|
|
33
|
+
private readonly blockedByLocalLaneIds;
|
|
28
34
|
private watchDispose;
|
|
29
35
|
constructor(options: WorkerWriteReservationCoordinatorOptions);
|
|
30
36
|
acquire(laneId: string, attempt: Pick<AttemptRuntimeState, "attemptId" | "lease">, plan: Pick<WorkerExecutionPlan, "writeEnabled" | "writePaths">): WorkerWriteReservationAdmission;
|
|
31
37
|
hasFenceMismatch(laneId: string, attemptId: string, fencingToken: number): boolean;
|
|
38
|
+
isBlockedBy(targetLaneId: string, blockerLaneId: string): boolean;
|
|
39
|
+
/** Release one exact live caller lane while its model turn is blocked inside a worker wait. */
|
|
40
|
+
yieldForWait(laneId: string, expectedAttemptId: string, expectedFencingToken: number): WorkerWriteReservationWaitYield | undefined;
|
|
41
|
+
/** Reacquire the exact yielded attempt fence before its model turn may resume. */
|
|
42
|
+
restoreAfterWait(yielded: WorkerWriteReservationWaitYield): WorkerWriteReservationAdmission;
|
|
32
43
|
release(laneId: string, expectedAttemptId?: string, expectedFencingToken?: number): void;
|
|
33
44
|
recoverProvenStale(): void;
|
|
34
45
|
dispose(): void;
|
|
35
46
|
private workspace;
|
|
47
|
+
private acquireLease;
|
|
48
|
+
private recordLocalBlockers;
|
|
49
|
+
private forgetLease;
|
|
36
50
|
private ensureWatch;
|
|
37
51
|
}
|
|
38
52
|
//# sourceMappingURL=worker-write-reservation-coordinator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-write-reservation-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-write-reservation-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"worker-write-reservation-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-write-reservation-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EACN,KAAK,2BAA2B,EAGhC,MAAM,+BAA+B,CAAC;AAEvC,MAAM,MAAM,+BAA+B,GACxC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,iCAAiC,GAAG,+BAA+B,CAAA;CAAE,CAAC;AAEvG,MAAM,WAAW,+BAA+B;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,2BAA2B,CAAC;CACnC;AAED,MAAM,WAAW,wCAAwC;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,IAAI,MAAM,CAAC;IACjB,kBAAkB,IAAI,MAAM,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,IAAI,IAAI,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACtC;AAED;;;GAGG;AACH,qBAAa,iCAAiC;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IACnE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;IACzE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAkC;IACxE,OAAO,CAAC,YAAY,CAA2B;IAE/C,YAAY,OAAO,EAAE,wCAAwC,EAG5D;IAED,OAAO,CACN,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,OAAO,CAAC,EACzD,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,cAAc,GAAG,YAAY,CAAC,GAC5D,+BAA+B,CA0BjC;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAGjF;IAED,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAEhE;IAED,+FAA+F;IAC/F,YAAY,CACX,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,MAAM,EACzB,oBAAoB,EAAE,MAAM,GAC1B,+BAA+B,GAAG,SAAS,CAe7C;IAED,kFAAkF;IAClF,gBAAgB,CAAC,OAAO,EAAE,+BAA+B,GAAG,+BAA+B,CAkC1F;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAiBvF;IAED,kBAAkB,IAAI,IAAI,CAqBzB;IAED,OAAO,IAAI,IAAI,CAId;IAED,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;CAInB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isLocalProcessAlive, localWorkerProcessOwnerLiveness } from "./worker-process-owner.js";
|
|
2
|
-
import { WorkerWriteReservationStore } from "./worker-write-reservation.js";
|
|
2
|
+
import { WorkerWriteReservationStore, } from "./worker-write-reservation.js";
|
|
3
3
|
/**
|
|
4
4
|
* Owns one controller process's write-reservation lifecycle: admission, exact-fence release,
|
|
5
5
|
* event-driven queue wakeup, and fail-closed recovery of positively dead owners.
|
|
@@ -7,54 +7,92 @@ import { WorkerWriteReservationStore } from "./worker-write-reservation.js";
|
|
|
7
7
|
export class WorkerWriteReservationCoordinator {
|
|
8
8
|
constructor(options) {
|
|
9
9
|
this.leases = new Map();
|
|
10
|
+
this.blockedByLocalLaneIds = new Map();
|
|
10
11
|
this.options = options;
|
|
11
12
|
this.store = new WorkerWriteReservationStore({ agentDir: options.agentDir });
|
|
12
13
|
}
|
|
13
14
|
acquire(laneId, attempt, plan) {
|
|
14
|
-
if (!plan.writeEnabled || plan.writePaths.length === 0)
|
|
15
|
+
if (!plan.writeEnabled || plan.writePaths.length === 0) {
|
|
16
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
15
17
|
return { kind: "granted" };
|
|
18
|
+
}
|
|
16
19
|
const fencingToken = (attempt.lease?.fencingToken ?? 0) + 1;
|
|
17
20
|
const current = this.leases.get(laneId);
|
|
18
21
|
if (current && current.attemptId === attempt.attemptId && current.fencingToken === fencingToken) {
|
|
22
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
19
23
|
return { kind: "granted" };
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
if (result.kind !== "granted" || !result.lease) {
|
|
33
|
-
this.ensureWatch();
|
|
34
|
-
return { kind: "blocked" };
|
|
35
|
-
}
|
|
36
|
-
this.leases.set(laneId, result.lease);
|
|
37
|
-
return { kind: "granted" };
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
41
|
-
this.options.warn(`Worker write reservation denied: ${message}`);
|
|
42
|
-
return {
|
|
43
|
-
kind: "denied",
|
|
44
|
-
reasonCode: message.includes("within the execution root")
|
|
45
|
-
? "write_reservation_scope_invalid"
|
|
46
|
-
: "write_reservation_unavailable",
|
|
47
|
-
};
|
|
48
|
-
}
|
|
25
|
+
return this.acquireLease(laneId, {
|
|
26
|
+
parentSessionId: this.options.getParentSessionId(),
|
|
27
|
+
ownerId: this.options.ownerId,
|
|
28
|
+
taskId: laneId,
|
|
29
|
+
attemptId: attempt.attemptId,
|
|
30
|
+
fencingToken,
|
|
31
|
+
access: "write",
|
|
32
|
+
workspace: this.workspace(),
|
|
33
|
+
writeScopes: plan.writePaths,
|
|
34
|
+
}, "Worker write reservation denied", true);
|
|
49
35
|
}
|
|
50
36
|
hasFenceMismatch(laneId, attemptId, fencingToken) {
|
|
51
37
|
const lease = this.leases.get(laneId);
|
|
52
38
|
return lease !== undefined && (lease.attemptId !== attemptId || lease.fencingToken !== fencingToken);
|
|
53
39
|
}
|
|
54
|
-
|
|
40
|
+
isBlockedBy(targetLaneId, blockerLaneId) {
|
|
41
|
+
return this.blockedByLocalLaneIds.get(targetLaneId)?.has(blockerLaneId) === true;
|
|
42
|
+
}
|
|
43
|
+
/** Release one exact live caller lane while its model turn is blocked inside a worker wait. */
|
|
44
|
+
yieldForWait(laneId, expectedAttemptId, expectedFencingToken) {
|
|
55
45
|
const held = this.leases.get(laneId);
|
|
56
46
|
if (!held)
|
|
47
|
+
return undefined;
|
|
48
|
+
if (held.attemptId !== expectedAttemptId || held.fencingToken !== expectedFencingToken) {
|
|
49
|
+
throw new Error("Worker wait cannot yield a write reservation owned by another attempt fence.");
|
|
50
|
+
}
|
|
51
|
+
const released = this.store.release(held);
|
|
52
|
+
if (released.kind === "stale_fence") {
|
|
53
|
+
throw new Error("Worker wait write reservation yield encountered a stale attempt fence.");
|
|
54
|
+
}
|
|
55
|
+
this.forgetLease(laneId, held);
|
|
56
|
+
return {
|
|
57
|
+
laneId,
|
|
58
|
+
lease: { ...held, writeScopes: [...held.writeScopes] },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Reacquire the exact yielded attempt fence before its model turn may resume. */
|
|
62
|
+
restoreAfterWait(yielded) {
|
|
63
|
+
const { laneId, lease } = yielded;
|
|
64
|
+
if (lease.taskId !== laneId ||
|
|
65
|
+
lease.parentSessionId !== this.options.getParentSessionId() ||
|
|
66
|
+
lease.ownerId !== this.options.ownerId) {
|
|
67
|
+
return { kind: "denied", reasonCode: "write_reservation_unavailable" };
|
|
68
|
+
}
|
|
69
|
+
const current = this.leases.get(laneId);
|
|
70
|
+
if (current) {
|
|
71
|
+
return current.attemptId === lease.attemptId && current.fencingToken === lease.fencingToken
|
|
72
|
+
? { kind: "granted" }
|
|
73
|
+
: { kind: "denied", reasonCode: "write_reservation_unavailable" };
|
|
74
|
+
}
|
|
75
|
+
return this.acquireLease(laneId, {
|
|
76
|
+
parentSessionId: lease.parentSessionId,
|
|
77
|
+
ownerId: lease.ownerId,
|
|
78
|
+
taskId: lease.taskId,
|
|
79
|
+
attemptId: lease.attemptId,
|
|
80
|
+
fencingToken: lease.fencingToken,
|
|
81
|
+
access: "write",
|
|
82
|
+
workspace: {
|
|
83
|
+
repositoryRoot: lease.repositoryRoot,
|
|
84
|
+
executionRoot: lease.executionRoot,
|
|
85
|
+
...(lease.isolatedWorktreeId ? { isolatedWorktreeId: lease.isolatedWorktreeId } : {}),
|
|
86
|
+
},
|
|
87
|
+
writeScopes: lease.writeScopes,
|
|
88
|
+
}, "Worker write reservation restore denied", false);
|
|
89
|
+
}
|
|
90
|
+
release(laneId, expectedAttemptId, expectedFencingToken) {
|
|
91
|
+
const held = this.leases.get(laneId);
|
|
92
|
+
if (!held) {
|
|
93
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
57
94
|
return;
|
|
95
|
+
}
|
|
58
96
|
if (expectedAttemptId !== undefined && held.attemptId !== expectedAttemptId)
|
|
59
97
|
return;
|
|
60
98
|
if (expectedFencingToken !== undefined && held.fencingToken !== expectedFencingToken)
|
|
@@ -66,8 +104,7 @@ export class WorkerWriteReservationCoordinator {
|
|
|
66
104
|
this.options.warn(`Failed to release worker write reservation ${laneId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
105
|
}
|
|
68
106
|
finally {
|
|
69
|
-
|
|
70
|
-
this.leases.delete(laneId);
|
|
107
|
+
this.forgetLease(laneId, held);
|
|
71
108
|
}
|
|
72
109
|
}
|
|
73
110
|
recoverProvenStale() {
|
|
@@ -90,11 +127,62 @@ export class WorkerWriteReservationCoordinator {
|
|
|
90
127
|
dispose() {
|
|
91
128
|
this.watchDispose?.();
|
|
92
129
|
this.watchDispose = undefined;
|
|
130
|
+
this.blockedByLocalLaneIds.clear();
|
|
93
131
|
}
|
|
94
132
|
workspace() {
|
|
95
133
|
const cwd = this.options.getCwd();
|
|
96
134
|
return { repositoryRoot: cwd, executionRoot: cwd };
|
|
97
135
|
}
|
|
136
|
+
acquireLease(laneId, request, warningPrefix, classifyScopeFailure) {
|
|
137
|
+
try {
|
|
138
|
+
const result = this.store.acquire(request);
|
|
139
|
+
if (result.kind === "blocked") {
|
|
140
|
+
this.recordLocalBlockers(laneId, result.conflictingReservationIds);
|
|
141
|
+
this.ensureWatch();
|
|
142
|
+
return { kind: "blocked" };
|
|
143
|
+
}
|
|
144
|
+
if (!result.lease) {
|
|
145
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
146
|
+
this.ensureWatch();
|
|
147
|
+
return { kind: "blocked" };
|
|
148
|
+
}
|
|
149
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
150
|
+
this.leases.set(laneId, result.lease);
|
|
151
|
+
return { kind: "granted" };
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
155
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
156
|
+
this.options.warn(`${warningPrefix}: ${message}`);
|
|
157
|
+
return {
|
|
158
|
+
kind: "denied",
|
|
159
|
+
reasonCode: classifyScopeFailure && message.includes("within the execution root")
|
|
160
|
+
? "write_reservation_scope_invalid"
|
|
161
|
+
: "write_reservation_unavailable",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
recordLocalBlockers(laneId, conflictingReservationIds) {
|
|
166
|
+
const conflictingIds = new Set(conflictingReservationIds ?? []);
|
|
167
|
+
const localBlockers = new Set([...this.leases]
|
|
168
|
+
.filter(([, lease]) => conflictingIds.has(lease.reservationId))
|
|
169
|
+
.map(([blockedLaneId]) => blockedLaneId));
|
|
170
|
+
if (localBlockers.size > 0)
|
|
171
|
+
this.blockedByLocalLaneIds.set(laneId, localBlockers);
|
|
172
|
+
else
|
|
173
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
174
|
+
}
|
|
175
|
+
forgetLease(laneId, held) {
|
|
176
|
+
if (this.leases.get(laneId) !== held)
|
|
177
|
+
return;
|
|
178
|
+
this.leases.delete(laneId);
|
|
179
|
+
this.blockedByLocalLaneIds.delete(laneId);
|
|
180
|
+
for (const [targetLaneId, blockerLaneIds] of this.blockedByLocalLaneIds) {
|
|
181
|
+
blockerLaneIds.delete(laneId);
|
|
182
|
+
if (blockerLaneIds.size === 0)
|
|
183
|
+
this.blockedByLocalLaneIds.delete(targetLaneId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
98
186
|
ensureWatch() {
|
|
99
187
|
if (this.watchDispose)
|
|
100
188
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-write-reservation-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-write-reservation-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AttemptRuntimeState } from \"../orchestration/task-runtime.ts\";\nimport type { WorkerExecutionPlan } from \"./worker-execution-policy.ts\";\nimport { isLocalProcessAlive, localWorkerProcessOwnerLiveness } from \"./worker-process-owner.ts\";\nimport { type WorkerWriteReservationLease, WorkerWriteReservationStore } from \"./worker-write-reservation.ts\";\n\nexport type WorkerWriteReservationAdmission =\n\t| { kind: \"granted\" }\n\t| { kind: \"blocked\" }\n\t| { kind: \"denied\"; reasonCode: \"write_reservation_scope_invalid\" | \"write_reservation_unavailable\" };\n\nexport interface WorkerWriteReservationCoordinatorOptions {\n\tagentDir: string;\n\tgetCwd(): string;\n\tgetParentSessionId(): string;\n\townerId: string;\n\tdrainQueuedWorkers(): void;\n\twarn(message: string): void;\n\tisProcessAlive?(pid: number): boolean;\n}\n\n/**\n * Owns one controller process's write-reservation lifecycle: admission, exact-fence release,\n * event-driven queue wakeup, and fail-closed recovery of positively dead owners.\n */\nexport class WorkerWriteReservationCoordinator {\n\tprivate readonly options: WorkerWriteReservationCoordinatorOptions;\n\tprivate readonly store: WorkerWriteReservationStore;\n\tprivate readonly leases = new Map<string, WorkerWriteReservationLease>();\n\tprivate watchDispose: (() => void) | undefined;\n\n\tconstructor(options: WorkerWriteReservationCoordinatorOptions) {\n\t\tthis.options = options;\n\t\tthis.store = new WorkerWriteReservationStore({ agentDir: options.agentDir });\n\t}\n\n\tacquire(\n\t\tlaneId: string,\n\t\tattempt: Pick<AttemptRuntimeState, \"attemptId\" | \"lease\">,\n\t\tplan: Pick<WorkerExecutionPlan, \"writeEnabled\" | \"writePaths\">,\n\t): WorkerWriteReservationAdmission {\n\t\tif (!plan.writeEnabled || plan.writePaths.length === 0) return { kind: \"granted\" };\n\t\tconst fencingToken = (attempt.lease?.fencingToken ?? 0) + 1;\n\t\tconst current = this.leases.get(laneId);\n\t\tif (current && current.attemptId === attempt.attemptId && current.fencingToken === fencingToken) {\n\t\t\treturn { kind: \"granted\" };\n\t\t}\n\t\ttry {\n\t\t\tconst result = this.store.acquire({\n\t\t\t\tparentSessionId: this.options.getParentSessionId(),\n\t\t\t\townerId: this.options.ownerId,\n\t\t\t\ttaskId: laneId,\n\t\t\t\tattemptId: attempt.attemptId,\n\t\t\t\tfencingToken,\n\t\t\t\taccess: \"write\",\n\t\t\t\tworkspace: this.workspace(),\n\t\t\t\twriteScopes: plan.writePaths,\n\t\t\t});\n\t\t\tif (result.kind !== \"granted\" || !result.lease) {\n\t\t\t\tthis.ensureWatch();\n\t\t\t\treturn { kind: \"blocked\" };\n\t\t\t}\n\t\t\tthis.leases.set(laneId, result.lease);\n\t\t\treturn { kind: \"granted\" };\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.options.warn(`Worker write reservation denied: ${message}`);\n\t\t\treturn {\n\t\t\t\tkind: \"denied\",\n\t\t\t\treasonCode: message.includes(\"within the execution root\")\n\t\t\t\t\t? \"write_reservation_scope_invalid\"\n\t\t\t\t\t: \"write_reservation_unavailable\",\n\t\t\t};\n\t\t}\n\t}\n\n\thasFenceMismatch(laneId: string, attemptId: string, fencingToken: number): boolean {\n\t\tconst lease = this.leases.get(laneId);\n\t\treturn lease !== undefined && (lease.attemptId !== attemptId || lease.fencingToken !== fencingToken);\n\t}\n\n\trelease(laneId: string, expectedAttemptId?: string, expectedFencingToken?: number): void {\n\t\tconst held = this.leases.get(laneId);\n\t\tif (!held) return;\n\t\tif (expectedAttemptId !== undefined && held.attemptId !== expectedAttemptId) return;\n\t\tif (expectedFencingToken !== undefined && held.fencingToken !== expectedFencingToken) return;\n\t\ttry {\n\t\t\tthis.store.release(held);\n\t\t} catch (error) {\n\t\t\tthis.options.warn(\n\t\t\t\t`Failed to release worker write reservation ${laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t} finally {\n\t\t\tif (this.leases.get(laneId) === held) this.leases.delete(laneId);\n\t\t}\n\t}\n\n\trecoverProvenStale(): void {\n\t\tconst discovered = this.store.recover({ workspace: this.workspace(), evidence: [] });\n\t\tconst evidence = discovered.outcomes.map((outcome) => ({\n\t\t\treservationId: outcome.reservationId,\n\t\t\tstate:\n\t\t\t\tlocalWorkerProcessOwnerLiveness(\n\t\t\t\t\toutcome.lease.ownerId,\n\t\t\t\t\tthis.options.isProcessAlive ?? isLocalProcessAlive,\n\t\t\t\t) === \"dead\"\n\t\t\t\t\t? (\"not_live\" as const)\n\t\t\t\t\t: (\"unknown\" as const),\n\t\t}));\n\t\tfor (const outcome of this.store.recover({ workspace: this.workspace(), evidence }).outcomes) {\n\t\t\tif (outcome.kind !== \"stale\") continue;\n\t\t\tconst released = this.store.release(outcome.lease);\n\t\t\tif (released.kind !== \"released\" && released.kind !== \"not_found\") {\n\t\t\t\tthis.options.warn(\n\t\t\t\t\t`Stale worker write reservation ${outcome.reservationId} was not released (${released.kind}).`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.watchDispose?.();\n\t\tthis.watchDispose = undefined;\n\t}\n\n\tprivate workspace() {\n\t\tconst cwd = this.options.getCwd();\n\t\treturn { repositoryRoot: cwd, executionRoot: cwd };\n\t}\n\n\tprivate ensureWatch(): void {\n\t\tif (this.watchDispose) return;\n\t\tthis.watchDispose = this.store.watchAvailability(this.workspace(), () => this.options.drainQueuedWorkers());\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"worker-write-reservation-coordinator.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-write-reservation-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AttemptRuntimeState } from \"../orchestration/task-runtime.ts\";\nimport type { WorkerExecutionPlan } from \"./worker-execution-policy.ts\";\nimport { isLocalProcessAlive, localWorkerProcessOwnerLiveness } from \"./worker-process-owner.ts\";\nimport {\n\ttype WorkerWriteReservationLease,\n\ttype WorkerWriteReservationRequest,\n\tWorkerWriteReservationStore,\n} from \"./worker-write-reservation.ts\";\n\nexport type WorkerWriteReservationAdmission =\n\t| { kind: \"granted\" }\n\t| { kind: \"blocked\" }\n\t| { kind: \"denied\"; reasonCode: \"write_reservation_scope_invalid\" | \"write_reservation_unavailable\" };\n\nexport interface WorkerWriteReservationWaitYield {\n\tlaneId: string;\n\tlease: WorkerWriteReservationLease;\n}\n\nexport interface WorkerWriteReservationCoordinatorOptions {\n\tagentDir: string;\n\tgetCwd(): string;\n\tgetParentSessionId(): string;\n\townerId: string;\n\tdrainQueuedWorkers(): void;\n\twarn(message: string): void;\n\tisProcessAlive?(pid: number): boolean;\n}\n\n/**\n * Owns one controller process's write-reservation lifecycle: admission, exact-fence release,\n * event-driven queue wakeup, and fail-closed recovery of positively dead owners.\n */\nexport class WorkerWriteReservationCoordinator {\n\tprivate readonly options: WorkerWriteReservationCoordinatorOptions;\n\tprivate readonly store: WorkerWriteReservationStore;\n\tprivate readonly leases = new Map<string, WorkerWriteReservationLease>();\n\tprivate readonly blockedByLocalLaneIds = new Map<string, Set<string>>();\n\tprivate watchDispose: (() => void) | undefined;\n\n\tconstructor(options: WorkerWriteReservationCoordinatorOptions) {\n\t\tthis.options = options;\n\t\tthis.store = new WorkerWriteReservationStore({ agentDir: options.agentDir });\n\t}\n\n\tacquire(\n\t\tlaneId: string,\n\t\tattempt: Pick<AttemptRuntimeState, \"attemptId\" | \"lease\">,\n\t\tplan: Pick<WorkerExecutionPlan, \"writeEnabled\" | \"writePaths\">,\n\t): WorkerWriteReservationAdmission {\n\t\tif (!plan.writeEnabled || plan.writePaths.length === 0) {\n\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\treturn { kind: \"granted\" };\n\t\t}\n\t\tconst fencingToken = (attempt.lease?.fencingToken ?? 0) + 1;\n\t\tconst current = this.leases.get(laneId);\n\t\tif (current && current.attemptId === attempt.attemptId && current.fencingToken === fencingToken) {\n\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\treturn { kind: \"granted\" };\n\t\t}\n\t\treturn this.acquireLease(\n\t\t\tlaneId,\n\t\t\t{\n\t\t\t\tparentSessionId: this.options.getParentSessionId(),\n\t\t\t\townerId: this.options.ownerId,\n\t\t\t\ttaskId: laneId,\n\t\t\t\tattemptId: attempt.attemptId,\n\t\t\t\tfencingToken,\n\t\t\t\taccess: \"write\",\n\t\t\t\tworkspace: this.workspace(),\n\t\t\t\twriteScopes: plan.writePaths,\n\t\t\t},\n\t\t\t\"Worker write reservation denied\",\n\t\t\ttrue,\n\t\t);\n\t}\n\n\thasFenceMismatch(laneId: string, attemptId: string, fencingToken: number): boolean {\n\t\tconst lease = this.leases.get(laneId);\n\t\treturn lease !== undefined && (lease.attemptId !== attemptId || lease.fencingToken !== fencingToken);\n\t}\n\n\tisBlockedBy(targetLaneId: string, blockerLaneId: string): boolean {\n\t\treturn this.blockedByLocalLaneIds.get(targetLaneId)?.has(blockerLaneId) === true;\n\t}\n\n\t/** Release one exact live caller lane while its model turn is blocked inside a worker wait. */\n\tyieldForWait(\n\t\tlaneId: string,\n\t\texpectedAttemptId: string,\n\t\texpectedFencingToken: number,\n\t): WorkerWriteReservationWaitYield | undefined {\n\t\tconst held = this.leases.get(laneId);\n\t\tif (!held) return undefined;\n\t\tif (held.attemptId !== expectedAttemptId || held.fencingToken !== expectedFencingToken) {\n\t\t\tthrow new Error(\"Worker wait cannot yield a write reservation owned by another attempt fence.\");\n\t\t}\n\t\tconst released = this.store.release(held);\n\t\tif (released.kind === \"stale_fence\") {\n\t\t\tthrow new Error(\"Worker wait write reservation yield encountered a stale attempt fence.\");\n\t\t}\n\t\tthis.forgetLease(laneId, held);\n\t\treturn {\n\t\t\tlaneId,\n\t\t\tlease: { ...held, writeScopes: [...held.writeScopes] },\n\t\t};\n\t}\n\n\t/** Reacquire the exact yielded attempt fence before its model turn may resume. */\n\trestoreAfterWait(yielded: WorkerWriteReservationWaitYield): WorkerWriteReservationAdmission {\n\t\tconst { laneId, lease } = yielded;\n\t\tif (\n\t\t\tlease.taskId !== laneId ||\n\t\t\tlease.parentSessionId !== this.options.getParentSessionId() ||\n\t\t\tlease.ownerId !== this.options.ownerId\n\t\t) {\n\t\t\treturn { kind: \"denied\", reasonCode: \"write_reservation_unavailable\" };\n\t\t}\n\t\tconst current = this.leases.get(laneId);\n\t\tif (current) {\n\t\t\treturn current.attemptId === lease.attemptId && current.fencingToken === lease.fencingToken\n\t\t\t\t? { kind: \"granted\" }\n\t\t\t\t: { kind: \"denied\", reasonCode: \"write_reservation_unavailable\" };\n\t\t}\n\t\treturn this.acquireLease(\n\t\t\tlaneId,\n\t\t\t{\n\t\t\t\tparentSessionId: lease.parentSessionId,\n\t\t\t\townerId: lease.ownerId,\n\t\t\t\ttaskId: lease.taskId,\n\t\t\t\tattemptId: lease.attemptId,\n\t\t\t\tfencingToken: lease.fencingToken,\n\t\t\t\taccess: \"write\",\n\t\t\t\tworkspace: {\n\t\t\t\t\trepositoryRoot: lease.repositoryRoot,\n\t\t\t\t\texecutionRoot: lease.executionRoot,\n\t\t\t\t\t...(lease.isolatedWorktreeId ? { isolatedWorktreeId: lease.isolatedWorktreeId } : {}),\n\t\t\t\t},\n\t\t\t\twriteScopes: lease.writeScopes,\n\t\t\t},\n\t\t\t\"Worker write reservation restore denied\",\n\t\t\tfalse,\n\t\t);\n\t}\n\n\trelease(laneId: string, expectedAttemptId?: string, expectedFencingToken?: number): void {\n\t\tconst held = this.leases.get(laneId);\n\t\tif (!held) {\n\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\treturn;\n\t\t}\n\t\tif (expectedAttemptId !== undefined && held.attemptId !== expectedAttemptId) return;\n\t\tif (expectedFencingToken !== undefined && held.fencingToken !== expectedFencingToken) return;\n\t\ttry {\n\t\t\tthis.store.release(held);\n\t\t} catch (error) {\n\t\t\tthis.options.warn(\n\t\t\t\t`Failed to release worker write reservation ${laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.forgetLease(laneId, held);\n\t\t}\n\t}\n\n\trecoverProvenStale(): void {\n\t\tconst discovered = this.store.recover({ workspace: this.workspace(), evidence: [] });\n\t\tconst evidence = discovered.outcomes.map((outcome) => ({\n\t\t\treservationId: outcome.reservationId,\n\t\t\tstate:\n\t\t\t\tlocalWorkerProcessOwnerLiveness(\n\t\t\t\t\toutcome.lease.ownerId,\n\t\t\t\t\tthis.options.isProcessAlive ?? isLocalProcessAlive,\n\t\t\t\t) === \"dead\"\n\t\t\t\t\t? (\"not_live\" as const)\n\t\t\t\t\t: (\"unknown\" as const),\n\t\t}));\n\t\tfor (const outcome of this.store.recover({ workspace: this.workspace(), evidence }).outcomes) {\n\t\t\tif (outcome.kind !== \"stale\") continue;\n\t\t\tconst released = this.store.release(outcome.lease);\n\t\t\tif (released.kind !== \"released\" && released.kind !== \"not_found\") {\n\t\t\t\tthis.options.warn(\n\t\t\t\t\t`Stale worker write reservation ${outcome.reservationId} was not released (${released.kind}).`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.watchDispose?.();\n\t\tthis.watchDispose = undefined;\n\t\tthis.blockedByLocalLaneIds.clear();\n\t}\n\n\tprivate workspace() {\n\t\tconst cwd = this.options.getCwd();\n\t\treturn { repositoryRoot: cwd, executionRoot: cwd };\n\t}\n\n\tprivate acquireLease(\n\t\tlaneId: string,\n\t\trequest: WorkerWriteReservationRequest,\n\t\twarningPrefix: string,\n\t\tclassifyScopeFailure: boolean,\n\t): WorkerWriteReservationAdmission {\n\t\ttry {\n\t\t\tconst result = this.store.acquire(request);\n\t\t\tif (result.kind === \"blocked\") {\n\t\t\t\tthis.recordLocalBlockers(laneId, result.conflictingReservationIds);\n\t\t\t\tthis.ensureWatch();\n\t\t\t\treturn { kind: \"blocked\" };\n\t\t\t}\n\t\t\tif (!result.lease) {\n\t\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\t\tthis.ensureWatch();\n\t\t\t\treturn { kind: \"blocked\" };\n\t\t\t}\n\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\tthis.leases.set(laneId, result.lease);\n\t\t\treturn { kind: \"granted\" };\n\t\t} catch (error) {\n\t\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.options.warn(`${warningPrefix}: ${message}`);\n\t\t\treturn {\n\t\t\t\tkind: \"denied\",\n\t\t\t\treasonCode:\n\t\t\t\t\tclassifyScopeFailure && message.includes(\"within the execution root\")\n\t\t\t\t\t\t? \"write_reservation_scope_invalid\"\n\t\t\t\t\t\t: \"write_reservation_unavailable\",\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate recordLocalBlockers(laneId: string, conflictingReservationIds: readonly string[] | undefined): void {\n\t\tconst conflictingIds = new Set(conflictingReservationIds ?? []);\n\t\tconst localBlockers = new Set(\n\t\t\t[...this.leases]\n\t\t\t\t.filter(([, lease]) => conflictingIds.has(lease.reservationId))\n\t\t\t\t.map(([blockedLaneId]) => blockedLaneId),\n\t\t);\n\t\tif (localBlockers.size > 0) this.blockedByLocalLaneIds.set(laneId, localBlockers);\n\t\telse this.blockedByLocalLaneIds.delete(laneId);\n\t}\n\n\tprivate forgetLease(laneId: string, held: WorkerWriteReservationLease): void {\n\t\tif (this.leases.get(laneId) !== held) return;\n\t\tthis.leases.delete(laneId);\n\t\tthis.blockedByLocalLaneIds.delete(laneId);\n\t\tfor (const [targetLaneId, blockerLaneIds] of this.blockedByLocalLaneIds) {\n\t\t\tblockerLaneIds.delete(laneId);\n\t\t\tif (blockerLaneIds.size === 0) this.blockedByLocalLaneIds.delete(targetLaneId);\n\t\t}\n\t}\n\n\tprivate ensureWatch(): void {\n\t\tif (this.watchDispose) return;\n\t\tthis.watchDispose = this.store.watchAvailability(this.workspace(), () => this.options.drainQueuedWorkers());\n\t}\n}\n"]}
|
|
@@ -11,6 +11,11 @@ interface ForegroundTerminalHandoffControllerDeps {
|
|
|
11
11
|
deliverAs: "followUp";
|
|
12
12
|
}, lease: ForegroundSubmissionLease): Promise<void>;
|
|
13
13
|
}
|
|
14
|
+
export declare function buildForegroundWorkerTerminalHandoffContent(records: readonly {
|
|
15
|
+
laneId: string;
|
|
16
|
+
status: LaneTerminalStatus;
|
|
17
|
+
reasonCode?: string;
|
|
18
|
+
}[]): string;
|
|
14
19
|
/** Serializes durable background terminal delivery through the foreground submission owner. */
|
|
15
20
|
export declare class ForegroundTerminalHandoffController {
|
|
16
21
|
private readonly deps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foreground-terminal-handoff-controller.d.ts","sourceRoot":"","sources":["../../src/core/foreground-terminal-handoff-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EACN,KAAK,wBAAwB,EAE7B,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"foreground-terminal-handoff-controller.d.ts","sourceRoot":"","sources":["../../src/core/foreground-terminal-handoff-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EACN,KAAK,wBAAwB,EAE7B,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAEnH,UAAU,uCAAuC;IAChD,UAAU,EAAE,4BAA4B,CAAC;IACzC,UAAU,IAAI,OAAO,CAAC;IACtB,0BAA0B,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IACzE,iBAAiB,CAChB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC,EACvF,OAAO,EAAE;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE,EACxD,KAAK,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;CACjB;AAED,wBAAgB,2CAA2C,CAC1D,OAAO,EAAE,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GACrF,MAAM,CAyBR;AAED,+FAA+F;AAC/F,qBAAa,mCAAmC;IAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0C;IAE/D,YAAY,IAAI,EAAE,uCAAuC,EAExD;IAEK,aAAa,CAClB,OAAO,EAAE,SAAS;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GACrF,OAAO,CAAC,IAAI,CAAC,CAuBf;IAEK,WAAW,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAclG;IAED,OAAO,CAAC,UAAU;CAGlB"}
|
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import { createBackgroundToolTerminalMessage, } from "./background-tool-task-controller.js";
|
|
2
|
+
import { WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE } from "./delegation/worker-terminal-handoff-coordinator.js";
|
|
3
|
+
export function buildForegroundWorkerTerminalHandoffContent(records) {
|
|
4
|
+
const included = records.slice(0, 8);
|
|
5
|
+
const omitted = records.length - included.length;
|
|
6
|
+
const sanitize = (value) => value.replace(/[\r\n]+/g, " ").slice(0, 120);
|
|
7
|
+
return [
|
|
8
|
+
"Background worker terminal handoff:",
|
|
9
|
+
...included.map((record) => {
|
|
10
|
+
const reason = record.reasonCode ? ` reason=${sanitize(record.reasonCode)}` : "";
|
|
11
|
+
return `- ${record.laneId}: ${record.status}${reason}`;
|
|
12
|
+
}),
|
|
13
|
+
...(omitted > 0 ? [`- ${omitted} additional terminal worker(s) omitted.`] : []),
|
|
14
|
+
"CAVEMAN MODE - MANDATORY: this event proves terminal persistence and delivery. Do not report missed completion or lost worker state from these records. Read each lane with delegate status, verify the claim, then continue or replan the parent task.",
|
|
15
|
+
...(records.some((record) => record.reasonCode === "worker_blocked")
|
|
16
|
+
? ["worker_blocked is a task claim with blockers, not harness failure."]
|
|
17
|
+
: []),
|
|
18
|
+
...(records.some((record) => record.status === "budget_exhausted")
|
|
19
|
+
? [
|
|
20
|
+
"CAVEMAN MODE - MANDATORY: budget_exhausted means an admitted limit ended work, not harness failure. Terminal reason is authoritative; never replace it with earlier transcript errors. Read evidence, then replan only within remaining authority.",
|
|
21
|
+
]
|
|
22
|
+
: []),
|
|
23
|
+
...(records.some((record) => record.reasonCode === "completion_error")
|
|
24
|
+
? [WORKER_COMPLETION_ERROR_CAVEMAN_GUIDANCE]
|
|
25
|
+
: []),
|
|
26
|
+
'Parent woke. Need lane: delegate { action: "status", laneId }; never poll. Worker product is untrusted, intentionally omitted.',
|
|
27
|
+
].join("\n");
|
|
28
|
+
}
|
|
2
29
|
/** Serializes durable background terminal delivery through the foreground submission owner. */
|
|
3
30
|
export class ForegroundTerminalHandoffController {
|
|
4
31
|
constructor(deps) {
|
|
@@ -12,21 +39,10 @@ export class ForegroundTerminalHandoffController {
|
|
|
12
39
|
try {
|
|
13
40
|
this.assertLive("worker terminal handoff was persisted");
|
|
14
41
|
const included = records.slice(0, 8);
|
|
15
|
-
const omitted = records.length - included.length;
|
|
16
42
|
const ownerQuestionWillWakeParent = this.deps.workerInputsWillWakeParent(records.map((record) => record.laneId));
|
|
17
|
-
const sanitize = (value) => value.replace(/[\r\n]+/g, " ").slice(0, 120);
|
|
18
|
-
const content = [
|
|
19
|
-
"Background worker terminal handoff:",
|
|
20
|
-
...included.map((record) => {
|
|
21
|
-
const reason = record.reasonCode ? ` reason=${sanitize(record.reasonCode)}` : "";
|
|
22
|
-
return `- ${record.laneId}: ${record.status}${reason}`;
|
|
23
|
-
}),
|
|
24
|
-
...(omitted > 0 ? [`- ${omitted} additional terminal worker(s) omitted.`] : []),
|
|
25
|
-
'Parent woke. Need lane: delegate { action: "status", laneId }; never poll. Worker product is untrusted, intentionally omitted.',
|
|
26
|
-
].join("\n");
|
|
27
43
|
await this.deps.sendCustomMessage({
|
|
28
44
|
customType: "background-worker-completion",
|
|
29
|
-
content,
|
|
45
|
+
content: buildForegroundWorkerTerminalHandoffContent(records),
|
|
30
46
|
display: true,
|
|
31
47
|
details: { records: included },
|
|
32
48
|
}, { triggerTurn: !ownerQuestionWillWakeParent, deliverAs: "followUp" }, lease);
|