@plurnk/plurnk-service 1.16.4 → 1.17.0
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/.env.defaults +122 -246
- package/INSTALL.md +84 -138
- package/README.md +9 -5
- package/SPEC.md +1710 -1015
- package/dist/Paths.d.ts +2 -0
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +2 -0
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.d.ts.map +1 -1
- package/dist/build-info.js +7 -1
- package/dist/build-info.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/body-preview.d.ts +8 -0
- package/dist/content/body-preview.d.ts.map +1 -0
- package/dist/content/body-preview.js +39 -0
- package/dist/content/body-preview.js.map +1 -0
- package/dist/content/byte-view.d.ts +1 -4
- package/dist/content/byte-view.d.ts.map +1 -1
- package/dist/content/byte-view.js.map +1 -1
- package/dist/content/edit-collision.d.ts.map +1 -1
- package/dist/content/edit-collision.js +3 -4
- package/dist/content/edit-collision.js.map +1 -1
- package/dist/content/line-anchors.d.ts +2 -2
- package/dist/content/line-anchors.d.ts.map +1 -1
- package/dist/content/line-anchors.js +4 -3
- package/dist/content/line-anchors.js.map +1 -1
- package/dist/content/line-selection.d.ts +9 -0
- package/dist/content/line-selection.d.ts.map +1 -0
- package/dist/content/line-selection.js +29 -0
- package/dist/content/line-selection.js.map +1 -0
- package/dist/content/matcher.d.ts +0 -1
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +2 -3
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/pattern-edits.d.ts +39 -0
- package/dist/content/pattern-edits.d.ts.map +1 -0
- package/dist/content/pattern-edits.js +121 -0
- package/dist/content/pattern-edits.js.map +1 -0
- package/dist/content/read-projector.d.ts +18 -9
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +132 -35
- package/dist/content/read-projector.js.map +1 -1
- package/dist/content/read-resolve.d.ts +3 -1
- package/dist/content/read-resolve.d.ts.map +1 -1
- package/dist/content/read-resolve.js +39 -7
- package/dist/content/read-resolve.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +3 -5
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +91 -83
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BareBatchRunner.d.ts +6 -1
- package/dist/core/BareBatchRunner.d.ts.map +1 -1
- package/dist/core/BareBatchRunner.js +20 -5
- package/dist/core/BareBatchRunner.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +2 -3
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +23 -32
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +3 -8
- package/dist/core/CapabilityPolicies.d.ts.map +1 -1
- package/dist/core/CapabilityPolicies.js +2 -28
- package/dist/core/CapabilityPolicies.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +10 -10
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +87 -65
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +14 -11
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +11 -12
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +99 -9
- package/dist/core/ClientInteractions.d.ts.map +1 -1
- package/dist/core/ClientInteractions.js +7 -0
- package/dist/core/ClientInteractions.js.map +1 -1
- package/dist/core/CoreSchemeServices.d.ts +13 -10
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +13 -5
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/DataStatementRunner.d.ts +2 -2
- package/dist/core/DataStatementRunner.d.ts.map +1 -1
- package/dist/core/DataStatementRunner.js +36 -39
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +19 -26
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +369 -219
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Dispatcher.sql +66 -0
- package/dist/core/DurableStatement.d.ts.map +1 -1
- package/dist/core/DurableStatement.js +2 -1
- package/dist/core/DurableStatement.js.map +1 -1
- package/dist/core/EditMutations.d.ts +14 -18
- package/dist/core/EditMutations.d.ts.map +1 -1
- package/dist/core/EditMutations.js +211 -280
- package/dist/core/EditMutations.js.map +1 -1
- package/dist/core/EditMutations.sql +15 -0
- package/dist/core/EditSequence.d.ts +13 -0
- package/dist/core/EditSequence.d.ts.map +1 -0
- package/dist/core/EditSequence.js +73 -0
- package/dist/core/EditSequence.js.map +1 -0
- package/dist/core/Engine.d.ts +17 -23
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +73 -163
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +0 -724
- package/dist/core/EntryAddressBinding.d.ts +7 -17
- package/dist/core/EntryAddressBinding.d.ts.map +1 -1
- package/dist/core/EntryAddressBinding.js +12 -72
- package/dist/core/EntryAddressBinding.js.map +1 -1
- package/dist/core/ExecutionOutputs.d.ts +9 -0
- package/dist/core/ExecutionOutputs.d.ts.map +1 -0
- package/dist/core/ExecutionOutputs.js +36 -0
- package/dist/core/ExecutionOutputs.js.map +1 -0
- package/dist/core/ExecutionOutputs.sql +13 -0
- package/dist/core/ExecutorRegistry.d.ts +7 -5
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +36 -32
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/HostPaths.d.ts +1 -0
- package/dist/core/HostPaths.d.ts.map +1 -1
- package/dist/core/HostPaths.js +4 -0
- package/dist/core/HostPaths.js.map +1 -1
- package/dist/core/InferenceCall.d.ts.map +1 -1
- package/dist/core/InferenceCall.js +1 -2
- package/dist/core/InferenceCall.js.map +1 -1
- package/dist/core/InferenceCall.sql +29 -0
- package/dist/core/KillHandler.d.ts +1 -0
- package/dist/core/KillHandler.d.ts.map +1 -1
- package/dist/core/KillHandler.js +24 -21
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/LogBody.d.ts +8 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +42 -11
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.d.ts +1 -0
- package/dist/core/LogEntryProjection.d.ts.map +1 -1
- package/dist/core/LogEntryProjection.js +18 -10
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LogVisibility.d.ts +1 -0
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +3 -0
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LogWriter.d.ts +2 -3
- package/dist/core/LogWriter.d.ts.map +1 -1
- package/dist/core/LogWriter.js +25 -32
- package/dist/core/LogWriter.js.map +1 -1
- package/dist/core/LogWriter.sql +23 -0
- package/dist/core/LoopDriver.d.ts +11 -8
- package/dist/core/LoopDriver.d.ts.map +1 -1
- package/dist/core/LoopDriver.js +163 -189
- package/dist/core/LoopDriver.js.map +1 -1
- package/dist/core/LoopDriver.sql +11 -0
- package/dist/core/LoopLifecycle.d.ts +32 -2
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +88 -4
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +145 -28
- package/dist/core/LoopPolicyReader.sql +6 -0
- package/dist/core/MembershipMaterialization.d.ts.map +1 -1
- package/dist/core/MembershipMaterialization.js +6 -28
- package/dist/core/MembershipMaterialization.js.map +1 -1
- package/dist/core/ModelCall.sql +70 -0
- package/dist/core/MutationEffects.d.ts +5 -3
- package/dist/core/MutationEffects.d.ts.map +1 -1
- package/dist/core/MutationEffects.js +10 -28
- package/dist/core/MutationEffects.js.map +1 -1
- package/dist/core/NativeContent.d.ts +6 -0
- package/dist/core/NativeContent.d.ts.map +1 -0
- package/dist/core/NativeContent.js +16 -0
- package/dist/core/NativeContent.js.map +1 -0
- package/dist/core/NativeContent.sql +6 -0
- package/dist/core/NoticeChannel.js +1 -1
- package/dist/core/NoticeChannel.js.map +1 -1
- package/dist/core/OperatorConfig.js +5 -5
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +8 -5
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +117 -81
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +146 -0
- package/dist/core/PatternSelection.d.ts +28 -0
- package/dist/core/PatternSelection.d.ts.map +1 -0
- package/dist/core/PatternSelection.js +42 -0
- package/dist/core/PatternSelection.js.map +1 -0
- package/dist/core/ProblemLog.d.ts.map +1 -1
- package/dist/core/ProblemLog.js +0 -1
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/PromptFrames.d.ts +12 -0
- package/dist/core/PromptFrames.d.ts.map +1 -0
- package/dist/core/PromptFrames.js +28 -0
- package/dist/core/PromptFrames.js.map +1 -0
- package/dist/core/ProposalLifecycle.d.ts +0 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +20 -19
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProposalLifecycle.sql +33 -0
- package/dist/core/ProviderInstantiate.d.ts +1 -1
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +7 -14
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ReasoningView.d.ts +9 -0
- package/dist/core/ReasoningView.d.ts.map +1 -0
- package/dist/core/ReasoningView.js +47 -0
- package/dist/core/ReasoningView.js.map +1 -0
- package/dist/core/ResourceBindings.d.ts +16 -0
- package/dist/core/ResourceBindings.d.ts.map +1 -0
- package/dist/core/ResourceBindings.js +45 -0
- package/dist/core/ResourceBindings.js.map +1 -0
- package/dist/core/ResourceMutations.d.ts +5 -8
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +6 -7
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/ResourceSelector.d.ts +2 -2
- package/dist/core/ResourceSelector.d.ts.map +1 -1
- package/dist/core/ResourceSelector.js +122 -62
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.d.ts +4 -2
- package/dist/core/ResourceTransfers.d.ts.map +1 -1
- package/dist/core/ResourceTransfers.js +95 -26
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/RuntimeWorker.d.ts +5 -0
- package/dist/core/RuntimeWorker.d.ts.map +1 -0
- package/dist/core/RuntimeWorker.js +10 -0
- package/dist/core/RuntimeWorker.js.map +1 -0
- package/dist/core/RuntimeWorker.sql +5 -0
- package/dist/core/SchemeRegistry.d.ts +12 -16
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +58 -84
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/StoredPacket.d.ts +6 -1
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +30 -10
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts +9 -6
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +60 -113
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/StrikeRail.sql +12 -0
- package/dist/core/TerminalResult.d.ts +1 -1
- package/dist/core/TerminalResult.d.ts.map +1 -1
- package/dist/core/TerminalResult.js +2 -2
- package/dist/core/TerminalResult.js.map +1 -1
- package/dist/core/TokenCalibration.d.ts +1 -6
- package/dist/core/TokenCalibration.d.ts.map +1 -1
- package/dist/core/TokenCalibration.js +13 -9
- package/dist/core/TokenCalibration.js.map +1 -1
- package/dist/core/TokenCalibration.sql +15 -0
- package/dist/core/ToolInputSchema.d.ts +6 -0
- package/dist/core/ToolInputSchema.d.ts.map +1 -0
- package/dist/core/ToolInputSchema.js +43 -0
- package/dist/core/ToolInputSchema.js.map +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +76 -52
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/Turn.d.ts +5 -2
- package/dist/core/Turn.d.ts.map +1 -1
- package/dist/core/Turn.js +13 -11
- package/dist/core/Turn.js.map +1 -1
- package/dist/core/Turn.sql +25 -39
- package/dist/core/{SendBroadcastHandler.d.ts → TurnDispositionHandler.d.ts} +25 -17
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -0
- package/dist/core/TurnDispositionHandler.js +198 -0
- package/dist/core/TurnDispositionHandler.js.map +1 -0
- package/dist/core/TurnMaterialization.d.ts +2 -3
- package/dist/core/TurnMaterialization.d.ts.map +1 -1
- package/dist/core/TurnMaterialization.js +40 -15
- package/dist/core/TurnMaterialization.js.map +1 -1
- package/dist/core/TurnMaterialization.sql +44 -0
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +8 -64
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts +9 -12
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +232 -408
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/TurnRunner.sql +74 -0
- package/dist/core/TurnSources.sql +39 -0
- package/dist/core/WorkerControlAddress.d.ts +1 -0
- package/dist/core/WorkerControlAddress.d.ts.map +1 -1
- package/dist/core/WorkerControlAddress.js +5 -0
- package/dist/core/WorkerControlAddress.js.map +1 -1
- package/dist/core/WorkerControlHandler.d.ts +1 -3
- package/dist/core/WorkerControlHandler.d.ts.map +1 -1
- package/dist/core/WorkerControlHandler.js +41 -48
- package/dist/core/WorkerControlHandler.js.map +1 -1
- package/dist/core/WorkerName.d.ts +8 -6
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +33 -24
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +7 -10
- package/dist/core/WorkspaceGate.d.ts +1 -1
- package/dist/core/WorkspaceGate.d.ts.map +1 -1
- package/dist/core/WorkspaceGate.js +29 -6
- package/dist/core/WorkspaceGate.js.map +1 -1
- package/dist/core/ambient.sql +236 -0
- package/dist/core/attachments.d.ts +2 -1
- package/dist/core/attachments.d.ts.map +1 -1
- package/dist/core/attachments.js +5 -4
- package/dist/core/attachments.js.map +1 -1
- package/dist/core/caps/CapsResolve.d.ts +2 -3
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js +5 -5
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +4 -6
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +2 -1
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +11 -17
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +3 -5
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +1 -1
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +5 -7
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +0 -2
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +4 -20
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js +4 -2
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/file-materialization.d.ts +4 -1
- package/dist/core/file-materialization.d.ts.map +1 -1
- package/dist/core/file-materialization.js +14 -0
- package/dist/core/file-materialization.js.map +1 -1
- package/dist/core/fork.d.ts +1 -6
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +9 -153
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +162 -185
- package/dist/core/git-env.d.ts +1 -0
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +39 -2
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +64 -48
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +25 -19
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/glob_match.d.ts +4 -0
- package/dist/core/glob_match.d.ts.map +1 -0
- package/dist/core/glob_match.js +7 -0
- package/dist/core/glob_match.js.map +1 -0
- package/dist/core/maintenance.sql +6 -0
- package/dist/core/mutation-types.d.ts +7 -28
- package/dist/core/mutation-types.d.ts.map +1 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +2 -3
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +8 -6
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +131 -163
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +5 -12
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/scheme-types.d.ts +3 -3
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/sha256.d.ts +4 -0
- package/dist/core/sha256.d.ts.map +1 -0
- package/dist/core/sha256.js +6 -0
- package/dist/core/sha256.js.map +1 -0
- package/dist/core/teaching.js +1 -1
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/turn-scheduler.d.ts.map +1 -1
- package/dist/core/turn-scheduler.js +5 -18
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/turn-signals.d.ts +0 -6
- package/dist/core/turn-signals.d.ts.map +1 -1
- package/dist/core/turn-signals.js +1 -7
- package/dist/core/turn-signals.js.map +1 -1
- package/dist/core/worker-ops.sql +15 -22
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +18 -2
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/core/workspace-settings.sql +6 -0
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +27 -90
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/DigestRender.d.ts.map +1 -1
- package/dist/digest/DigestRender.js +14 -54
- package/dist/digest/DigestRender.js.map +1 -1
- package/dist/digest/digest-rows.d.ts +10 -32
- package/dist/digest/digest-rows.d.ts.map +1 -1
- package/dist/digest/digest.sql +43 -18
- package/dist/schemes/Exec.d.ts +6 -12
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +256 -188
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +8 -6
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +33 -61
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/ExecutionInput.d.ts +12 -0
- package/dist/schemes/ExecutionInput.d.ts.map +1 -0
- package/dist/schemes/ExecutionInput.js +94 -0
- package/dist/schemes/ExecutionInput.js.map +1 -0
- package/dist/schemes/File.d.ts +5 -2
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +62 -92
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +84 -79
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +183 -15
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +3 -12
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts +5 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +6 -14
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/Skill.d.ts +12 -7
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +149 -21
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/TurnSource.d.ts +12 -0
- package/dist/schemes/TurnSource.d.ts.map +1 -0
- package/dist/schemes/TurnSource.js +116 -0
- package/dist/schemes/TurnSource.js.map +1 -0
- package/dist/schemes/Worker.d.ts +3 -3
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +61 -208
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +12 -15
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +63 -63
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +142 -46
- package/dist/schemes/_entry-find.d.ts +1 -3
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +111 -112
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +22 -14
- package/dist/schemes/_entry-fts.d.ts +14 -0
- package/dist/schemes/_entry-fts.d.ts.map +1 -0
- package/dist/schemes/_entry-fts.js +82 -0
- package/dist/schemes/_entry-fts.js.map +1 -0
- package/dist/schemes/_entry-fts.sql +31 -0
- package/dist/schemes/_entry-graph.d.ts.map +1 -1
- package/dist/schemes/_entry-graph.js +6 -14
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-graph.sql +29 -44
- package/dist/schemes/_entry-manifest.d.ts +2 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +15 -12
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-manifest.sql +26 -0
- package/dist/schemes/_entry-ops.d.ts +3 -5
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +30 -43
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +5 -6
- package/dist/schemes/_entry-readable.d.ts +8 -0
- package/dist/schemes/_entry-readable.d.ts.map +1 -0
- package/dist/schemes/_entry-readable.js +38 -0
- package/dist/schemes/_entry-readable.js.map +1 -0
- package/dist/schemes/_entry-send.d.ts +1 -1
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +3 -3
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_search-index.d.ts +1 -3
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +79 -110
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/schemes/_search-index.sql +30 -0
- package/dist/schemes/exec-runtime.d.ts +1 -1
- package/dist/schemes/exec-runtime.d.ts.map +1 -1
- package/dist/schemes/exec-runtime.js.map +1 -1
- package/dist/server/ClientReads.d.ts +2 -2
- package/dist/server/ClientReads.d.ts.map +1 -1
- package/dist/server/ClientReads.js +5 -8
- package/dist/server/ClientReads.js.map +1 -1
- package/dist/server/Daemon.d.ts +14 -21
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +135 -156
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +23 -21
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +8 -21
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +278 -306
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/Functionality.d.ts +11 -12
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +129 -101
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +3 -5
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +20 -58
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +5 -4
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +24 -37
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/PlurnkSkill.d.ts +11 -0
- package/dist/server/PlurnkSkill.d.ts.map +1 -0
- package/dist/server/PlurnkSkill.js +41 -0
- package/dist/server/PlurnkSkill.js.map +1 -0
- package/dist/server/Retention.d.ts +22 -0
- package/dist/server/Retention.d.ts.map +1 -0
- package/dist/server/Retention.js +54 -0
- package/dist/server/Retention.js.map +1 -0
- package/dist/server/Retention.sql +36 -0
- package/dist/server/ServiceModules.d.ts +5 -0
- package/dist/server/ServiceModules.d.ts.map +1 -0
- package/dist/server/ServiceModules.js +10 -0
- package/dist/server/ServiceModules.js.map +1 -0
- package/dist/server/SkillsFunctionality.d.ts +14 -19
- package/dist/server/SkillsFunctionality.d.ts.map +1 -1
- package/dist/server/SkillsFunctionality.js +97 -104
- package/dist/server/SkillsFunctionality.js.map +1 -1
- package/dist/server/WorkerModelResolver.d.ts +4 -0
- package/dist/server/WorkerModelResolver.d.ts.map +1 -1
- package/dist/server/WorkerModelResolver.js +72 -39
- package/dist/server/WorkerModelResolver.js.map +1 -1
- package/dist/server/WorkspaceCapabilities.d.ts +21 -0
- package/dist/server/WorkspaceCapabilities.d.ts.map +1 -0
- package/dist/server/{WorkerCapabilities.js → WorkspaceCapabilities.js} +40 -40
- package/dist/server/WorkspaceCapabilities.js.map +1 -0
- package/dist/server/WorkspaceResidency.d.ts +36 -0
- package/dist/server/WorkspaceResidency.d.ts.map +1 -0
- package/dist/server/WorkspaceResidency.js +199 -0
- package/dist/server/WorkspaceResidency.js.map +1 -0
- package/dist/server/client-input.d.ts +1 -4
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +4 -45
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +4 -22
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +65 -42
- package/dist/server/envelope.d.ts +8 -0
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +9 -7
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +49 -13
- package/dist/server/lifecycle-recovery.sql +14 -17
- package/dist/server/logEntry.d.ts +1 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +4 -1
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +25 -1
- package/dist/server/loopDocs.d.ts +2 -2
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +38 -31
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/loopDocs.sql +1 -3
- package/dist/server/model-catalog.d.ts.map +1 -1
- package/dist/server/model-catalog.js +2 -1
- package/dist/server/model-catalog.js.map +1 -1
- package/dist/server/model-route.d.ts +1 -1
- package/dist/server/model-route.d.ts.map +1 -1
- package/dist/server/model-route.js +4 -2
- package/dist/server/model-route.js.map +1 -1
- package/dist/server/seam-entry-read.sql +3 -4
- package/dist/server/seam-loop.sql +2 -9
- package/dist/server/workspace-capabilities.sql +19 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +5 -17
- package/dist/service.js.map +1 -1
- package/docs/members.md +83 -0
- package/docs/skills.md +50 -0
- package/migrations/001_workspaces.sql +53 -0
- package/migrations/002_workers.sql +183 -0
- package/migrations/003_loops.sql +326 -0
- package/migrations/004_inference.sql +360 -0
- package/migrations/005_entries.sql +207 -0
- package/migrations/006_log.sql +578 -0
- package/migrations/007_subscriptions.sql +175 -0
- package/migrations/008_interactions.sql +29 -0
- package/package.json +33 -40
- package/digest-sql/channel-dispositions/dispositions.sql +0 -15
- package/digest-sql/channel-state/state.sql +0 -6
- package/digest-sql/curation/curation.sql +0 -6
- package/digest-sql/derivations/derivations.sql +0 -4
- package/digest-sql/embeddings/embeddings.sql +0 -4
- package/digest-sql/entry-dispositions/dispositions.sql +0 -15
- package/digest-sql/entry-state/state.sql +0 -6
- package/digest-sql/token-counts/token-counts.sql +0 -2
- package/dist/core/EmbeddingCall.d.ts +0 -23
- package/dist/core/EmbeddingCall.d.ts.map +0 -1
- package/dist/core/EmbeddingCall.js +0 -149
- package/dist/core/EmbeddingCall.js.map +0 -1
- package/dist/core/OverflowTurn.d.ts +0 -11
- package/dist/core/OverflowTurn.d.ts.map +0 -1
- package/dist/core/OverflowTurn.js +0 -80
- package/dist/core/OverflowTurn.js.map +0 -1
- package/dist/core/Owner.d.ts +0 -8
- package/dist/core/Owner.d.ts.map +0 -1
- package/dist/core/Owner.js +0 -46
- package/dist/core/Owner.js.map +0 -1
- package/dist/core/SendBroadcastHandler.d.ts.map +0 -1
- package/dist/core/SendBroadcastHandler.js +0 -159
- package/dist/core/SendBroadcastHandler.js.map +0 -1
- package/dist/core/VectorPump.d.ts +0 -28
- package/dist/core/VectorPump.d.ts.map +0 -1
- package/dist/core/VectorPump.js +0 -130
- package/dist/core/VectorPump.js.map +0 -1
- package/dist/core/owner.sql +0 -11
- package/dist/core/worker-settings.d.ts +0 -10
- package/dist/core/worker-settings.d.ts.map +0 -1
- package/dist/core/worker-settings.js +0 -53
- package/dist/core/worker-settings.js.map +0 -1
- package/dist/schemes/_entry-chunk.d.ts +0 -14
- package/dist/schemes/_entry-chunk.d.ts.map +0 -1
- package/dist/schemes/_entry-chunk.js +0 -165
- package/dist/schemes/_entry-chunk.js.map +0 -1
- package/dist/schemes/_entry-semantic.d.ts +0 -63
- package/dist/schemes/_entry-semantic.d.ts.map +0 -1
- package/dist/schemes/_entry-semantic.js +0 -299
- package/dist/schemes/_entry-semantic.js.map +0 -1
- package/dist/schemes/_entry-semantic.sql +0 -99
- package/dist/schemes/cosine.d.ts +0 -4
- package/dist/schemes/cosine.d.ts.map +0 -1
- package/dist/schemes/cosine.js +0 -9
- package/dist/schemes/cosine.js.map +0 -1
- package/dist/server/WorkerCapabilities.d.ts +0 -21
- package/dist/server/WorkerCapabilities.d.ts.map +0 -1
- package/dist/server/WorkerCapabilities.js.map +0 -1
- package/dist/server/WorkerResidency.d.ts +0 -40
- package/dist/server/WorkerResidency.d.ts.map +0 -1
- package/dist/server/WorkerResidency.js +0 -283
- package/dist/server/WorkerResidency.js.map +0 -1
- package/dist/server/seam-log-read.sql +0 -21
- package/dist/server/worker-capabilities.sql +0 -28
- package/migrations/001_schema.sql +0 -2207
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
3
|
import { aggregateProviderAccounting } from "@plurnk/plurnk-providers";
|
|
3
4
|
import { routeForSpec } from "./model-route.js";
|
|
4
5
|
import ChannelWrite from "../core/ChannelWrite.js";
|
|
5
6
|
import ErrorDetail from "../core/ErrorDetail.js";
|
|
7
|
+
import { taskTiming } from "../core/LoopLifecycle.js";
|
|
6
8
|
import { DEFAULT_LOOP_POLICY } from "../core/scheme-types.js";
|
|
7
9
|
import Results, { OperationFailureError } from "../core/results.js";
|
|
8
10
|
import { observed } from "../observe/spans.js";
|
|
@@ -13,7 +15,7 @@ import { execPollBackoffMs } from "./exec-poll-backoff.js";
|
|
|
13
15
|
// Owns the worker-local queue consumer and every process-local edge that may
|
|
14
16
|
// wake, cancel, or retire it. Daemon retains provider/process policy and the
|
|
15
17
|
// external facade, supplying only the named capabilities below.
|
|
16
|
-
|
|
18
|
+
class DrainSupervisor {
|
|
17
19
|
#db;
|
|
18
20
|
#lifecycle;
|
|
19
21
|
#injectPrompt;
|
|
@@ -22,30 +24,26 @@ export default class DrainSupervisor {
|
|
|
22
24
|
#runLoop;
|
|
23
25
|
#loopUsage;
|
|
24
26
|
#loopAttributions;
|
|
25
|
-
#takeParkDeadline;
|
|
26
27
|
#cancelSubscription;
|
|
27
28
|
#hasActiveStreams;
|
|
28
|
-
#isDetachedSubscription;
|
|
29
29
|
#readSystemPrompt;
|
|
30
30
|
#emitLogEntry;
|
|
31
31
|
#emit;
|
|
32
32
|
// The handle is the drain identity. Start/exit compare by reference so an
|
|
33
33
|
// exiting drain cannot clobber a successor that raced in.
|
|
34
34
|
#activeDrains = new Map();
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#wakeFailures = [];
|
|
35
|
+
#settlementTasks = new Set();
|
|
36
|
+
#settlementFailures = [];
|
|
38
37
|
// One cancellation scope spans a worker's loops and streams. It outlives
|
|
39
38
|
// any single drain and is replaced only after it has been aborted.
|
|
40
39
|
#workerAborts = new Map();
|
|
41
|
-
#
|
|
42
|
-
#pollTimers = new Map();
|
|
40
|
+
#loopTimers = new Map();
|
|
43
41
|
#pollBackoff = new Map();
|
|
44
42
|
#drainLocks = new Map();
|
|
45
|
-
#
|
|
43
|
+
#admissionLocks = new Map();
|
|
46
44
|
#completionWakeGates = new Map();
|
|
47
45
|
#acceptingWork = false;
|
|
48
|
-
constructor({ db, lifecycle, injectPrompt, assertInjectionCompatibility, reconcilePrompts, runLoop, loopUsage, loopAttributions,
|
|
46
|
+
constructor({ db, lifecycle, injectPrompt, assertInjectionCompatibility, reconcilePrompts, runLoop, loopUsage, loopAttributions, cancelSubscription, hasActiveStreams, readSystemPrompt, emitLogEntry, emit, }) {
|
|
49
47
|
this.#db = db;
|
|
50
48
|
this.#lifecycle = lifecycle;
|
|
51
49
|
this.#injectPrompt = injectPrompt;
|
|
@@ -54,10 +52,8 @@ export default class DrainSupervisor {
|
|
|
54
52
|
this.#runLoop = runLoop;
|
|
55
53
|
this.#loopUsage = loopUsage;
|
|
56
54
|
this.#loopAttributions = loopAttributions;
|
|
57
|
-
this.#takeParkDeadline = takeParkDeadline;
|
|
58
55
|
this.#cancelSubscription = cancelSubscription;
|
|
59
56
|
this.#hasActiveStreams = hasActiveStreams;
|
|
60
|
-
this.#isDetachedSubscription = isDetachedSubscription;
|
|
61
57
|
this.#readSystemPrompt = readSystemPrompt;
|
|
62
58
|
this.#emitLogEntry = emitLogEntry;
|
|
63
59
|
this.#emit = emit;
|
|
@@ -71,28 +67,24 @@ export default class DrainSupervisor {
|
|
|
71
67
|
if (!scope.signal.aborted)
|
|
72
68
|
scope.abort(reason);
|
|
73
69
|
}
|
|
74
|
-
for (const timer of this.#
|
|
75
|
-
clearTimeout(timer);
|
|
76
|
-
for (const timer of this.#parkTimers.values())
|
|
70
|
+
for (const { timer } of this.#loopTimers.values())
|
|
77
71
|
clearTimeout(timer);
|
|
78
72
|
this.#pollBackoff.clear();
|
|
79
|
-
this.#
|
|
80
|
-
this.#parkTimers.clear();
|
|
73
|
+
this.#loopTimers.clear();
|
|
81
74
|
}
|
|
82
75
|
async idle() {
|
|
83
76
|
for (;;) {
|
|
84
77
|
const pending = [
|
|
85
78
|
...[...this.#activeDrains.values()].map(({ promise }) => promise),
|
|
86
|
-
...this.#
|
|
87
|
-
...this.#wakeTasks,
|
|
79
|
+
...this.#settlementTasks,
|
|
88
80
|
];
|
|
89
81
|
if (pending.length === 0)
|
|
90
82
|
break;
|
|
91
83
|
await Promise.allSettled(pending);
|
|
92
84
|
}
|
|
93
|
-
const failures = this.#
|
|
85
|
+
const failures = this.#settlementFailures.splice(0);
|
|
94
86
|
if (failures.length > 0) {
|
|
95
|
-
throw new AggregateError(failures, "
|
|
87
|
+
throw new AggregateError(failures, "worker lifecycle settlement failed");
|
|
96
88
|
}
|
|
97
89
|
}
|
|
98
90
|
async inject(args) {
|
|
@@ -100,10 +92,23 @@ export default class DrainSupervisor {
|
|
|
100
92
|
throw new Error("drain injection cannot combine an explicit policy with a fresh-loop policy");
|
|
101
93
|
}
|
|
102
94
|
const { workspaceId, workerId, prompt } = args;
|
|
103
|
-
const
|
|
104
|
-
if (!this.#
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
const delivery = await this.#withAdmissionLock(workspaceId, () => this.#withDrainLock(workerId, async () => {
|
|
96
|
+
if (!this.#acceptingWork)
|
|
97
|
+
throw new Error("The daemon is not accepting work.");
|
|
98
|
+
if (args.sourceLoopId !== undefined) {
|
|
99
|
+
const source = await this.#db.drain_message_source.get({
|
|
100
|
+
loop_id: args.sourceLoopId,
|
|
101
|
+
});
|
|
102
|
+
if (source === undefined || source.workspace_id !== workspaceId) {
|
|
103
|
+
throw new Error(`message source loop ${args.sourceLoopId} does not belong to workspace ${workspaceId}`);
|
|
104
|
+
}
|
|
105
|
+
if (source.status !== 102) {
|
|
106
|
+
throw new OperationFailureError(Results.failure("daemon:admission", "source-not-running", 409, `The originating task is not running (status ${source.status}); no message was admitted.`, {}, { loopId: args.sourceLoopId, sourceStatus: source.status, retryable: false }));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const active = args.schedule === undefined
|
|
110
|
+
? await this.#db.drain_current_loop_for_worker.get({ worker_id: workerId })
|
|
111
|
+
: undefined;
|
|
107
112
|
if (active !== undefined) {
|
|
108
113
|
await this.#assertInjectionCompatibility({
|
|
109
114
|
workerId,
|
|
@@ -116,93 +121,61 @@ export default class DrainSupervisor {
|
|
|
116
121
|
...(args.policy === undefined ? {} : { policy: args.policy }),
|
|
117
122
|
});
|
|
118
123
|
}
|
|
119
|
-
const result =
|
|
124
|
+
const result = active === undefined ? null
|
|
125
|
+
: await this.#injectPrompt(active.id, prompt, args.openPaths ?? [], args.source);
|
|
120
126
|
if (result !== null) {
|
|
121
127
|
// runLoop may already have parked in the database while this drain
|
|
122
128
|
// is still registered. Wake that state now; if it is still running,
|
|
123
129
|
// the serialized park-boundary check below supplies the wake edge.
|
|
124
|
-
await this.#
|
|
130
|
+
await this.#wakeLoop(workerId, result.loopId);
|
|
125
131
|
return { action: "injected_next_turn", loopId: result.loopId, turnSeq: result.turnSeq };
|
|
126
132
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
loopId: slept.id,
|
|
139
|
-
providerSpec: args.providerSpec,
|
|
140
|
-
providerSpecExplicit: args.providerSpecExplicit,
|
|
141
|
-
reasoningPolicy: args.reasoningPolicy,
|
|
142
|
-
...(args.childProviderSpec === undefined ? {} : { childProviderSpec: args.childProviderSpec }),
|
|
143
|
-
...(args.turnCeiling === undefined ? {} : { turnCeiling: args.turnCeiling }),
|
|
144
|
-
...(args.policy === undefined ? {} : { policy: args.policy }),
|
|
145
|
-
});
|
|
146
|
-
const injected = await this.#injectPrompt(workerId, prompt, args.openPaths ?? [], args.source);
|
|
147
|
-
await this.#lifecycle.wake(slept.id);
|
|
148
|
-
const started = await this.ensureDrain({ workspaceId, workerId, systemPrompt: args.systemPrompt });
|
|
149
|
-
return {
|
|
150
|
-
action: "injected_next_turn",
|
|
151
|
-
loopId: slept.id,
|
|
152
|
-
...(injected?.turnSeq === undefined ? {} : { turnSeq: injected.turnSeq }),
|
|
153
|
-
...(started ?? {}),
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const loopId = await this.enqueueFreshLoop({
|
|
158
|
-
workerId,
|
|
159
|
-
prompt,
|
|
160
|
-
...(args.source === undefined ? {} : { source: args.source }),
|
|
161
|
-
providerSpec: args.providerSpec,
|
|
162
|
-
reasoningPolicy: args.reasoningPolicy,
|
|
163
|
-
childProviderSpec: args.childProviderSpec ?? null,
|
|
164
|
-
maxTurns: args.turnCeiling?.effective,
|
|
165
|
-
policy: args.policy ?? args.freshLoopPolicy,
|
|
166
|
-
openPaths: args.openPaths,
|
|
167
|
-
});
|
|
168
|
-
const started = await this.ensureDrain({ workspaceId, workerId, systemPrompt: args.systemPrompt });
|
|
169
|
-
return { action: "enqueued_new_loop", loopId, ...(started ?? {}) };
|
|
170
|
-
}
|
|
171
|
-
enqueueFreshLoop(args) {
|
|
172
|
-
return this.#withDrainLock(args.workerId, async () => {
|
|
173
|
-
const seqRow = await this.#db.loop_run_next_sequence.get({ worker_id: args.workerId });
|
|
174
|
-
if (seqRow === undefined)
|
|
175
|
-
throw new Error("enqueueFreshLoop: next-sequence query returned no row");
|
|
176
|
-
// {§worker-model-selection} — resolve the complete route before persistence;
|
|
177
|
-
// the loop snapshot stores the immutable route ids, never re-serialized JSON.
|
|
178
|
-
const modelRouteId = await routeForSpec(this.#db, args.providerSpec);
|
|
179
|
-
const spawnRouteId = await routeForSpec(this.#db, args.childProviderSpec);
|
|
180
|
-
const loopRow = await this.#db.drain_enqueue_loop.get({
|
|
181
|
-
worker_id: args.workerId,
|
|
182
|
-
sequence: seqRow.next,
|
|
183
|
-
prompt: args.prompt,
|
|
184
|
-
prompt_source: args.source ?? null,
|
|
185
|
-
model_route_id: modelRouteId,
|
|
186
|
-
spawn_model_route_id: spawnRouteId,
|
|
187
|
-
reasoning_policy: args.reasoningPolicy,
|
|
188
|
-
max_turns: args.maxTurns ?? Number(process.env.PLURNK_SERVICE_MAX_TURNS ?? "50"),
|
|
133
|
+
const accepted = await this.#enqueueFreshLoop({
|
|
134
|
+
workerId,
|
|
135
|
+
prompt,
|
|
136
|
+
...(args.source === undefined ? {} : { source: args.source }),
|
|
137
|
+
providerSpec: args.providerSpec,
|
|
138
|
+
reasoningPolicy: args.reasoningPolicy,
|
|
139
|
+
childProviderSpec: args.childProviderSpec ?? null,
|
|
140
|
+
maxTurns: args.turnCeiling?.effective,
|
|
141
|
+
policy: args.policy ?? args.freshLoopPolicy,
|
|
142
|
+
openPaths: args.openPaths,
|
|
143
|
+
schedule: args.schedule,
|
|
189
144
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
});
|
|
145
|
+
return { action: "enqueued_new_loop", ...accepted };
|
|
146
|
+
}));
|
|
147
|
+
const started = await this.ensureDrain({ workspaceId, workerId, systemPrompt: args.systemPrompt });
|
|
148
|
+
return { ...delivery, ...(started ?? {}) };
|
|
149
|
+
}
|
|
150
|
+
async #enqueueFreshLoop(args) {
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
if (args.schedule !== undefined) {
|
|
153
|
+
const { delayMs, intervalMs } = args.schedule;
|
|
154
|
+
if (!Number.isSafeInteger(delayMs) || delayMs < 0 || now + delayMs > 8.64e15
|
|
155
|
+
|| (intervalMs !== undefined && (!Number.isSafeInteger(intervalMs) || intervalMs <= 0 || now + delayMs + intervalMs > 8.64e15))) {
|
|
156
|
+
throw new TypeError("task schedule requires nonnegative delay and positive interval in safe integer milliseconds within the supported date range");
|
|
203
157
|
}
|
|
204
|
-
|
|
158
|
+
}
|
|
159
|
+
// {§worker-model-selection} — resolve the complete route before persistence;
|
|
160
|
+
// the loop snapshot stores the immutable route ids, never re-serialized JSON.
|
|
161
|
+
const modelRouteId = await routeForSpec(this.#db, args.providerSpec);
|
|
162
|
+
const spawnRouteId = await routeForSpec(this.#db, args.childProviderSpec);
|
|
163
|
+
const loopRow = await this.#db.drain_enqueue_loop.get({
|
|
164
|
+
worker_id: args.workerId,
|
|
165
|
+
prompt: args.prompt,
|
|
166
|
+
prompt_source: args.source ?? null,
|
|
167
|
+
model_route_id: modelRouteId,
|
|
168
|
+
spawn_model_route_id: spawnRouteId,
|
|
169
|
+
reasoning_policy: args.reasoningPolicy,
|
|
170
|
+
max_turns: args.maxTurns ?? Number(process.env.PLURNK_SERVICE_MAX_TURNS ?? "50"),
|
|
171
|
+
policy: JSON.stringify({ ...DEFAULT_LOOP_POLICY, ...args.policy }),
|
|
172
|
+
open_paths: JSON.stringify(args.openPaths ?? []),
|
|
173
|
+
scheduled_at: args.schedule === undefined ? null : now + args.schedule.delayMs,
|
|
174
|
+
repeat_interval_ms: args.schedule?.intervalMs ?? null,
|
|
205
175
|
});
|
|
176
|
+
if (loopRow === undefined)
|
|
177
|
+
throw new Error("enqueueFreshLoop: loop enqueue returned no row");
|
|
178
|
+
return { loopId: loopRow.id, ...taskTiming(loopRow) };
|
|
206
179
|
}
|
|
207
180
|
// Consume one worker's durable queue until a lock-held empty re-claim
|
|
208
181
|
// relinquishes this exact drain identity.
|
|
@@ -221,7 +194,7 @@ export default class DrainSupervisor {
|
|
|
221
194
|
rejectFirst = rej;
|
|
222
195
|
});
|
|
223
196
|
let firstSettled = false;
|
|
224
|
-
const claim = () => this.#db.drain_claim_next_loop.get({ worker_id: workerId });
|
|
197
|
+
const claim = () => this.#db.drain_claim_next_loop.get({ worker_id: workerId, now: Date.now() });
|
|
225
198
|
const drainPromise = (async () => {
|
|
226
199
|
let loopsDrained = 0;
|
|
227
200
|
let lastResult = null;
|
|
@@ -248,6 +221,7 @@ export default class DrainSupervisor {
|
|
|
248
221
|
break;
|
|
249
222
|
}
|
|
250
223
|
currentLoopId = loopRow.id;
|
|
224
|
+
this.#clearLoopTimer(loopRow.id);
|
|
251
225
|
const onSettled = async (logEntryId) => {
|
|
252
226
|
await this.#emitLogEntry(workspaceId, logEntryId).catch((error) => {
|
|
253
227
|
console.error("log/entry broadcast failed:", error instanceof Error ? error.message : String(error));
|
|
@@ -269,32 +243,11 @@ export default class DrainSupervisor {
|
|
|
269
243
|
return loopResult;
|
|
270
244
|
});
|
|
271
245
|
if (result.result.status === 202) {
|
|
272
|
-
// The loop
|
|
246
|
+
// The loop parked — suspended, not terminated. Leave it at 202
|
|
273
247
|
// (resumable); no loop/terminated, no orphan-reconcile. A stream conclusion
|
|
274
248
|
// through handleWakeWorker re-queues it; if it holds a polled stream, a poll timer
|
|
275
249
|
// wakes it every P to inspect ({§exec-poll}). {§worker-lifecycle-wake-liveness}.
|
|
276
|
-
|
|
277
|
-
// {§send-premature-terminate}/scoped SEND signal 202 — the park deadline:
|
|
278
|
-
// dispatcher recorded the marker's seconds; a bounded park is woken at T
|
|
279
|
-
// regardless of arrivals, so a park always has a next turn. -1 (indefinite:
|
|
280
|
-
// the butler, a [300] ask) schedules nothing — irc/inject/conclusions wake it.
|
|
281
|
-
// In-memory: a daemon restart drops pending deadlines.
|
|
282
|
-
if (currentLoopId !== null) {
|
|
283
|
-
const deadline = this.#takeParkDeadline(currentLoopId);
|
|
284
|
-
const prior = this.#parkTimers.get(workerId);
|
|
285
|
-
if (prior !== undefined) {
|
|
286
|
-
clearTimeout(prior);
|
|
287
|
-
this.#parkTimers.delete(workerId);
|
|
288
|
-
}
|
|
289
|
-
if (deadline !== undefined && deadline > 0) {
|
|
290
|
-
const t = setTimeout(() => {
|
|
291
|
-
this.#parkTimers.delete(workerId);
|
|
292
|
-
void this.#wakeParkedWorker(workspaceId, workerId, systemPrompt).catch((err) => console.error("park-deadline wake failed:", err instanceof Error ? err.message : String(err)));
|
|
293
|
-
}, deadline * 1000);
|
|
294
|
-
t.unref();
|
|
295
|
-
this.#parkTimers.set(workerId, t);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
250
|
+
await this.scheduleWakes(workspaceId, workerId, systemPrompt);
|
|
298
251
|
// Serialize the park boundary against active prompt injection.
|
|
299
252
|
// Whichever side arrives first owns a wake edge: injection wakes
|
|
300
253
|
// an already-parked loop, while this check wakes a prompt written
|
|
@@ -302,42 +255,37 @@ export default class DrainSupervisor {
|
|
|
302
255
|
const promptWaiting = await this.#withDrainLock(workerId, async () => {
|
|
303
256
|
const prefix = promptLoopPrefix(loopRow.sequence);
|
|
304
257
|
const undelivered = await this.#db.drain_undelivered_prompts_for_loop.get({
|
|
305
|
-
|
|
258
|
+
worker_id: workerId,
|
|
306
259
|
pattern: `${prefix}%`,
|
|
307
260
|
prefix_len: prefix.length,
|
|
308
261
|
loop_id: loopRow.id,
|
|
309
262
|
});
|
|
310
263
|
if (undelivered === undefined)
|
|
311
264
|
return false;
|
|
312
|
-
|
|
313
|
-
return true;
|
|
265
|
+
return this.#wakeLoop(workerId, loopRow.id);
|
|
314
266
|
});
|
|
315
267
|
if (promptWaiting) {
|
|
316
268
|
currentLoopId = null;
|
|
317
269
|
continue;
|
|
318
270
|
}
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
// claimable and the drain re-runs it on the next claim below.
|
|
323
|
-
if (this.#owedWakes.delete(workerId)) {
|
|
324
|
-
await this.#lifecycle.wake(loopRow.id);
|
|
271
|
+
// {§loop-wake-identity}: events observed by another loop
|
|
272
|
+
// cannot consume this loop's completion wake.
|
|
273
|
+
if (await this.#wakeLoop(workerId, loopRow.id, { eventOnly: true })) {
|
|
325
274
|
currentLoopId = null;
|
|
326
275
|
continue;
|
|
327
276
|
}
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
// conclude-before-block race). An idle wait never reaches here — it concluded at dispatch.
|
|
277
|
+
// {§worker-wait-timing}: the wait now belongs to its
|
|
278
|
+
// durable clock or completion obligations, not this drain.
|
|
331
279
|
currentLoopId = null;
|
|
332
280
|
continue;
|
|
333
281
|
}
|
|
334
|
-
this.#
|
|
282
|
+
this.#pollBackoff.delete(loopRow.id);
|
|
335
283
|
const [usage, attributions, turnIds] = await Promise.all([
|
|
336
284
|
this.#loopUsage(loopRow.id),
|
|
337
285
|
this.#loopAttributions(loopRow.id),
|
|
338
286
|
this.#lifecycle.turnIds(loopRow.id),
|
|
339
287
|
]);
|
|
340
|
-
this.#
|
|
288
|
+
this.#publishTermination(workspaceId, {
|
|
341
289
|
workerId,
|
|
342
290
|
loopId: loopRow.id,
|
|
343
291
|
result: result.result,
|
|
@@ -396,7 +344,7 @@ export default class DrainSupervisor {
|
|
|
396
344
|
this.#loopAttributions(currentLoopId),
|
|
397
345
|
]);
|
|
398
346
|
if (cancelled !== null) {
|
|
399
|
-
this.#
|
|
347
|
+
this.#publishTermination(workspaceId, {
|
|
400
348
|
workerId,
|
|
401
349
|
loopId: currentLoopId,
|
|
402
350
|
result: cancelled,
|
|
@@ -450,7 +398,7 @@ export default class DrainSupervisor {
|
|
|
450
398
|
this.#loopUsage(currentLoopId),
|
|
451
399
|
this.#loopAttributions(currentLoopId),
|
|
452
400
|
]);
|
|
453
|
-
this.#
|
|
401
|
+
this.#publishTermination(workspaceId, {
|
|
454
402
|
workerId,
|
|
455
403
|
loopId: currentLoopId,
|
|
456
404
|
result: settled,
|
|
@@ -474,21 +422,12 @@ export default class DrainSupervisor {
|
|
|
474
422
|
}
|
|
475
423
|
if (this.#activeDrains.get(workerId) === handle)
|
|
476
424
|
this.#activeDrains.delete(workerId);
|
|
425
|
+
await this.scheduleWakes(workspaceId, workerId, systemPrompt);
|
|
477
426
|
}
|
|
478
427
|
return { loopsDrained, lastResult };
|
|
479
428
|
})();
|
|
480
429
|
handle.promise = drainPromise;
|
|
481
430
|
this.#activeDrains.set(workerId, handle);
|
|
482
|
-
// Topology join ({§worker-loop-lifecycle}): when this drain exits having CONCLUDED the worker, wake its parent
|
|
483
|
-
// if parked. Runs after the drain fully tears down (settled promise) so the quiescence check sees
|
|
484
|
-
// final state; speculative (#onDrainExit no-ops unless the worker concluded AND the parent is parked).
|
|
485
|
-
const drainExitTask = drainPromise.then(() => this.#onDrainExit(workspaceId, workerId, systemPrompt), () => this.#onDrainExit(workspaceId, workerId, systemPrompt));
|
|
486
|
-
this.#drainExitTasks.add(drainExitTask);
|
|
487
|
-
void drainExitTask.catch((err) => {
|
|
488
|
-
console.error(`parent wake after worker ${workerId} settlement failed:`, err);
|
|
489
|
-
}).finally(() => {
|
|
490
|
-
this.#drainExitTasks.delete(drainExitTask);
|
|
491
|
-
});
|
|
492
431
|
// Swallow unhandled rejections (drain aborts with no awaiter); the
|
|
493
432
|
// error already surfaced via firstLoopPromise or was logged inside.
|
|
494
433
|
drainPromise.catch(() => { });
|
|
@@ -502,12 +441,20 @@ export default class DrainSupervisor {
|
|
|
502
441
|
// A promise-chain mutex: each caller awaits the prior holder; the tail self-prunes
|
|
503
442
|
// when idle so the Map stays bounded to workers mid-transition.
|
|
504
443
|
#withDrainLock(workerId, fn) {
|
|
505
|
-
|
|
444
|
+
return _a.#withLock(this.#drainLocks, workerId, fn);
|
|
445
|
+
}
|
|
446
|
+
// {§worker-causal-admission}: workspace control precedes worker queue control;
|
|
447
|
+
// neither encloses provider/tool execution or waits for a drain to finish.
|
|
448
|
+
#withAdmissionLock(workspaceId, fn) {
|
|
449
|
+
return _a.#withLock(this.#admissionLocks, workspaceId, fn);
|
|
450
|
+
}
|
|
451
|
+
static #withLock(locks, id, fn) {
|
|
452
|
+
const prev = locks.get(id) ?? Promise.resolve();
|
|
506
453
|
const run = prev.then(fn, fn);
|
|
507
454
|
const tail = run.catch(() => { });
|
|
508
|
-
|
|
509
|
-
void tail.then(() => { if (
|
|
510
|
-
|
|
455
|
+
locks.set(id, tail);
|
|
456
|
+
void tail.then(() => { if (locks.get(id) === tail)
|
|
457
|
+
locks.delete(id); });
|
|
511
458
|
return run;
|
|
512
459
|
}
|
|
513
460
|
// The drain guarantee, serialized per worker via #withDrainLock so it can't race a
|
|
@@ -516,18 +463,33 @@ export default class DrainSupervisor {
|
|
|
516
463
|
// or its lock-held exit re-claim → return null. A registered-but-ABORTING drain is
|
|
517
464
|
// in teardown and won't claim, so we don't defer to it — start fresh, or the loop
|
|
518
465
|
// strands on a cancel/resume race (I6 no-lost-loop). Otherwise start one.
|
|
519
|
-
ensureDrain(opts) {
|
|
520
|
-
|
|
466
|
+
async ensureDrain(opts) {
|
|
467
|
+
let deferred = false;
|
|
468
|
+
const started = await this.#withDrainLock(opts.workerId, async () => {
|
|
469
|
+
if (!this.#acceptingWork)
|
|
470
|
+
return null;
|
|
521
471
|
const existing = this.#activeDrains.get(opts.workerId);
|
|
522
472
|
if (existing !== undefined && !existing.controller.signal.aborted)
|
|
523
473
|
return null;
|
|
474
|
+
if (await this.#db.drain_ready_loop.get({ worker_id: opts.workerId, now: Date.now() }) === undefined) {
|
|
475
|
+
deferred = true;
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
if (!this.#acceptingWork)
|
|
479
|
+
return null;
|
|
524
480
|
return this.#startDrain(opts);
|
|
525
481
|
});
|
|
482
|
+
if (deferred)
|
|
483
|
+
await this.scheduleWakes(opts.workspaceId, opts.workerId, opts.systemPrompt);
|
|
484
|
+
return started;
|
|
526
485
|
}
|
|
527
486
|
// Prompt promotion shares the worker lock with enqueue and drain teardown,
|
|
528
487
|
// while Daemon retains the durable prompt-policy implementation.
|
|
529
|
-
reconcileOrphanedPrompts(workerId, endedLoopId) {
|
|
530
|
-
|
|
488
|
+
async reconcileOrphanedPrompts(workerId, endedLoopId) {
|
|
489
|
+
const row = await this.#db.drain_get_worker_workspace.get({ worker_id: workerId });
|
|
490
|
+
if (row === undefined)
|
|
491
|
+
throw new Error(`prompt promotion worker ${workerId} does not exist`);
|
|
492
|
+
return this.#withAdmissionLock(row.workspace_id, () => this.#withDrainLock(workerId, () => this.#reconcilePrompts(workerId, endedLoopId)));
|
|
531
493
|
}
|
|
532
494
|
#workerSignal(workerId) {
|
|
533
495
|
const existing = this.#workerAborts.get(workerId);
|
|
@@ -538,25 +500,26 @@ export default class DrainSupervisor {
|
|
|
538
500
|
return fresh;
|
|
539
501
|
}
|
|
540
502
|
async #cancelTree(workerId, reason, includeRoot) {
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
503
|
+
const owner = await this.#db.drain_get_worker_workspace.get({ worker_id: workerId });
|
|
504
|
+
if (owner === undefined)
|
|
505
|
+
throw new Error(`cancellation worker ${workerId} does not exist`);
|
|
506
|
+
const { cancelled, subscriptions } = await this.#withAdmissionLock(owner.workspace_id, async () => {
|
|
507
|
+
const cancelled = await this.#lifecycle.cancelTree(workerId, reason, includeRoot);
|
|
508
|
+
const subscriptions = (await Promise.all(cancelled.workerIds.map((id) => ChannelWrite.findOpenSubscriptionsForWorker(this.#db, id)))).flat();
|
|
509
|
+
for (const targetWorkerId of cancelled.workerIds) {
|
|
510
|
+
for (const [loopId, timer] of this.#loopTimers) {
|
|
511
|
+
if (timer.workerId === targetWorkerId)
|
|
512
|
+
this.#clearLoopTimer(loopId);
|
|
513
|
+
}
|
|
514
|
+
const scope = this.#workerAborts.get(targetWorkerId);
|
|
515
|
+
if (scope !== undefined && !scope.signal.aborted)
|
|
516
|
+
scope.abort(reason);
|
|
552
517
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
await Promise.all(cancelled.workerIds.map(async (targetWorkerId) => this.#reapWorkerStreams(targetWorkerId)));
|
|
518
|
+
return { cancelled, subscriptions };
|
|
519
|
+
});
|
|
520
|
+
for (const { loopId } of cancelled.loops)
|
|
521
|
+
this.#pollBackoff.delete(loopId);
|
|
522
|
+
await Promise.all(subscriptions.map(({ id }) => this.#cancelSubscription(id)));
|
|
560
523
|
for (const { loopId, workerId: targetWorkerId, result } of cancelled.loops) {
|
|
561
524
|
const row = await this.#db.drain_get_worker_workspace.get({
|
|
562
525
|
worker_id: targetWorkerId,
|
|
@@ -567,7 +530,7 @@ export default class DrainSupervisor {
|
|
|
567
530
|
this.#loopUsage(loopId),
|
|
568
531
|
this.#loopAttributions(loopId),
|
|
569
532
|
]);
|
|
570
|
-
this.#
|
|
533
|
+
this.#publishTermination(row.workspace_id, {
|
|
571
534
|
workerId: targetWorkerId,
|
|
572
535
|
loopId,
|
|
573
536
|
result,
|
|
@@ -579,90 +542,55 @@ export default class DrainSupervisor {
|
|
|
579
542
|
}
|
|
580
543
|
}
|
|
581
544
|
cancelWorkerTree(workerId, reason) {
|
|
582
|
-
return this.#cancelTree(workerId, reason, true);
|
|
545
|
+
return this.#trackSettlement(this.#cancelTree(workerId, reason, true), `cancelTree(${workerId})`);
|
|
583
546
|
}
|
|
584
547
|
cancelDescendants(workerId, reason) {
|
|
585
|
-
return this.#cancelTree(workerId, reason, false);
|
|
586
|
-
}
|
|
587
|
-
// {§worker-model-selection} — the 409 boundary: a worker with a live drain
|
|
588
|
-
// holding a loop, or a parked (slept) loop, owns active work; a model
|
|
589
|
-
// selection must not mutate underneath it.
|
|
590
|
-
async hasLiveWork(workerId) {
|
|
591
|
-
if (this.#activeDrains.has(workerId)) {
|
|
592
|
-
const active = await this.#db.drain_current_loop_for_worker.get({ worker_id: workerId });
|
|
593
|
-
if (active !== undefined)
|
|
594
|
-
return true;
|
|
595
|
-
}
|
|
596
|
-
const slept = await this.#db.drain_find_slept_loop.get({ worker_id: workerId });
|
|
597
|
-
return slept !== undefined;
|
|
548
|
+
return this.#trackSettlement(this.#cancelTree(workerId, reason, false), `cancelDescendants(${workerId})`);
|
|
598
549
|
}
|
|
599
550
|
cancel(workerId, reason = "user_cancelled") {
|
|
600
551
|
const hadDrain = this.#activeDrains.has(workerId);
|
|
601
552
|
const hadWork = hadDrain || this.#hasActiveStreams(workerId);
|
|
602
|
-
|
|
603
|
-
if (pollTimer !== undefined) {
|
|
604
|
-
clearTimeout(pollTimer);
|
|
605
|
-
this.#pollTimers.delete(workerId);
|
|
606
|
-
}
|
|
607
|
-
void this.cancelWorkerTree(workerId, reason).catch((error) => {
|
|
608
|
-
console.error(`cancelTree(${workerId}) failed:`, error);
|
|
609
|
-
});
|
|
553
|
+
void this.cancelWorkerTree(workerId, reason);
|
|
610
554
|
return hadWork;
|
|
611
555
|
}
|
|
612
|
-
async #reapWorkerStreams(workerId) {
|
|
613
|
-
const open = await ChannelWrite.findOpenSubscriptionsForWorker(this.#db, workerId);
|
|
614
|
-
await Promise.all(open.map(({ id }) => this.#cancelSubscription(id)));
|
|
615
|
-
}
|
|
616
556
|
// {§module-shutdown-order}: the producer emits synchronously, while the
|
|
617
557
|
// supervisor owns the asynchronous scheduler work and its shutdown truth.
|
|
618
558
|
notifyWakeWorker(payload) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
559
|
+
this.#trackSettlement(this.#handleWakeWorker(payload), "wake-on-completion");
|
|
560
|
+
}
|
|
561
|
+
#trackSettlement(task, label) {
|
|
562
|
+
this.#settlementTasks.add(task);
|
|
563
|
+
void task.then(() => { this.#settlementTasks.delete(task); }, (error) => {
|
|
564
|
+
this.#settlementTasks.delete(task);
|
|
565
|
+
this.#settlementFailures.push(error);
|
|
566
|
+
console.error(`${label} failed:`, error);
|
|
625
567
|
});
|
|
568
|
+
return task;
|
|
626
569
|
}
|
|
627
570
|
async #handleWakeWorker(payload) {
|
|
628
|
-
const {
|
|
629
|
-
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
this.#emit(workspaceId, "stream/concluded", {
|
|
633
|
-
...conclusion, wakeAction: "skipped-aborted",
|
|
634
|
-
});
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
// No resurrection ({§worker-lifecycle-no-resurrection}): a non-499 completion whose
|
|
638
|
-
// worker was cancelled (idle + its scope aborted) must not start a fresh drain —
|
|
639
|
-
// the cancel was deliberate. The deliverable is already in the channel/log and
|
|
640
|
-
// surfaces as a `collect` environment delta ({§env-delta}) if the worker is read or
|
|
641
|
-
// resumed; we just don't inject a turn. (An active worker folds the wake into its
|
|
642
|
-
// next turn via inject below; a resumed worker is active, never aborted, so it is
|
|
643
|
-
// unaffected.)
|
|
571
|
+
const { workspaceId, ...conclusion } = payload;
|
|
572
|
+
// {§worker-lifecycle-no-resurrection}: scope cancellation, not the
|
|
573
|
+
// command's result code, prevents a wake. Cancelling one command still
|
|
574
|
+
// produces an observation owed to its live worker.
|
|
644
575
|
const scope = this.#workerAborts.get(payload.workerId);
|
|
645
|
-
if (scope?.signal.aborted === true
|
|
576
|
+
if (scope?.signal.aborted === true) {
|
|
646
577
|
this.#emit(workspaceId, "stream/concluded", {
|
|
647
|
-
...conclusion, wakeAction: "skipped-cancelled",
|
|
578
|
+
...conclusion, wakeAction: payload.result.status === 499 ? "skipped-aborted" : "skipped-cancelled",
|
|
648
579
|
});
|
|
649
580
|
return;
|
|
650
581
|
}
|
|
651
582
|
const systemPrompt = await this.#readSystemPrompt();
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
-
// sibling mid-teardown (the ensureDrain lock serializes the re-claim). No fresh loop,
|
|
656
|
-
// no summary-as-prompt — the resumed loop reads the concluded stream's own state from
|
|
657
|
-
// the manifest. {§worker-lifecycle-wake-liveness}.
|
|
583
|
+
// {§notifications-stream-concluded}: publish the terminal stream fact
|
|
584
|
+
// before settlement. Rechecked wait identities, not this event, decide
|
|
585
|
+
// whether any loop actually resumes.
|
|
658
586
|
const slept = await this.#db.drain_find_slept_loop.get({ worker_id: payload.workerId });
|
|
659
587
|
if (slept !== undefined) {
|
|
660
588
|
// {§worker-optimistic-settlement} — publish this conclusion now,
|
|
661
589
|
// then let the worker-local gate coalesce only the provider
|
|
662
590
|
// dispatch. Concurrent stream/child callbacks join that one gate.
|
|
663
|
-
const settlement = this.settleCompletionWake(workspaceId, payload.workerId, systemPrompt
|
|
591
|
+
const settlement = this.settleCompletionWake(workspaceId, payload.workerId, systemPrompt);
|
|
664
592
|
this.#emit(workspaceId, "stream/concluded", {
|
|
665
|
-
...conclusion, wakeAction: "
|
|
593
|
+
...conclusion, wakeAction: "wake-pending",
|
|
666
594
|
});
|
|
667
595
|
await settlement;
|
|
668
596
|
return;
|
|
@@ -677,77 +605,130 @@ export default class DrainSupervisor {
|
|
|
677
605
|
});
|
|
678
606
|
return;
|
|
679
607
|
}
|
|
680
|
-
// No slept loop, no active drain — nothing to resume (e.g. a
|
|
608
|
+
// No slept loop, no active drain — nothing to resume (e.g. a completed worker whose
|
|
681
609
|
// streams were swept). Surface the conclusion without opening a loop.
|
|
682
610
|
this.#emit(workspaceId, "stream/concluded", {
|
|
683
611
|
...conclusion, wakeAction: "no-loop",
|
|
684
612
|
});
|
|
685
613
|
}
|
|
686
|
-
|
|
687
|
-
const
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
|
|
614
|
+
#clearLoopTimer(loopId) {
|
|
615
|
+
const current = this.#loopTimers.get(loopId);
|
|
616
|
+
if (current === undefined)
|
|
617
|
+
return;
|
|
618
|
+
clearTimeout(current.timer);
|
|
619
|
+
this.#loopTimers.delete(loopId);
|
|
620
|
+
}
|
|
621
|
+
async scheduleWakes(workspaceId, workerId, systemPrompt) {
|
|
622
|
+
await this.#withDrainLock(workerId, async () => {
|
|
623
|
+
if (!this.#acceptingWork)
|
|
624
|
+
return;
|
|
625
|
+
const waits = await this.#lifecycle.parked(workerId);
|
|
626
|
+
const queued = await this.#db.drain_scheduled_loops.all({ worker_id: workerId });
|
|
627
|
+
if (!this.#acceptingWork)
|
|
628
|
+
return;
|
|
629
|
+
for (const [loopId, timer] of this.#loopTimers) {
|
|
630
|
+
if (timer.workerId === workerId && !waits.some(({ id }) => id === loopId)
|
|
631
|
+
&& !queued.some(({ id }) => id === loopId))
|
|
632
|
+
this.#clearLoopTimer(loopId);
|
|
633
|
+
}
|
|
634
|
+
for (const wait of waits) {
|
|
635
|
+
if (wait.wait_poll_interval === null && wait.wait_poll_at === null) {
|
|
636
|
+
const interval = await this.#inheritedPollMs(workerId, wait.id);
|
|
637
|
+
if (!this.#acceptingWork)
|
|
638
|
+
return;
|
|
639
|
+
if (interval !== null) {
|
|
640
|
+
wait.wait_poll_at = Date.now() + interval;
|
|
641
|
+
await this.#lifecycle.inheritPoll(wait.id, wait.wait_revision, wait.wait_poll_at);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const dueAt = Math.min(wait.wait_deadline_at ?? Infinity, wait.wait_poll_at ?? Infinity);
|
|
645
|
+
if (!Number.isFinite(dueAt))
|
|
646
|
+
continue;
|
|
647
|
+
this.#armTimer(workspaceId, workerId, systemPrompt, wait.id, 202, wait.wait_revision, dueAt);
|
|
648
|
+
}
|
|
649
|
+
for (const task of queued) {
|
|
650
|
+
this.#armTimer(workspaceId, workerId, systemPrompt, task.id, 100, task.wait_revision, task.scheduled_at);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
#armTimer(workspaceId, workerId, systemPrompt, loopId, status, revision, dueAt) {
|
|
655
|
+
if (!this.#acceptingWork)
|
|
656
|
+
return;
|
|
657
|
+
const prior = this.#loopTimers.get(loopId);
|
|
658
|
+
if (prior?.revision === revision && prior.status === status && prior.dueAt === dueAt)
|
|
659
|
+
return;
|
|
660
|
+
this.#clearLoopTimer(loopId);
|
|
661
|
+
const timer = setTimeout(() => {
|
|
662
|
+
if (this.#loopTimers.get(loopId)?.timer !== timer)
|
|
663
|
+
return;
|
|
664
|
+
this.#loopTimers.delete(loopId);
|
|
665
|
+
this.#trackSettlement(this.#wakeTimedLoop(workspaceId, workerId, systemPrompt, loopId, status, revision), "wake-on-completion");
|
|
666
|
+
}, Math.max(1, Math.min(dueAt - Date.now(), 2_147_483_647)));
|
|
667
|
+
timer.unref();
|
|
668
|
+
this.#loopTimers.set(loopId, { workerId, status, revision, dueAt, timer });
|
|
669
|
+
}
|
|
670
|
+
async #wakeTimedLoop(workspaceId, workerId, systemPrompt, loopId, status, revision) {
|
|
671
|
+
if (!this.#acceptingWork)
|
|
672
|
+
return;
|
|
673
|
+
if (status === 100 || await this.#wakeLoop(workerId, loopId, { revision, dueAt: Date.now() })) {
|
|
674
|
+
await this.ensureDrain({ workspaceId, workerId, systemPrompt });
|
|
691
675
|
}
|
|
676
|
+
else {
|
|
677
|
+
// A capped timer or backwards clock may fire before the durable due time.
|
|
678
|
+
await this.scheduleWakes(workspaceId, workerId, systemPrompt);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
async #inheritedPollMs(workerId, loopId) {
|
|
692
682
|
const row = await this.#db.drain_worker_min_poll.get({ worker_id: workerId });
|
|
683
|
+
if (!this.#acceptingWork)
|
|
684
|
+
return null;
|
|
693
685
|
if ((row?.open_count ?? 0) === 0) {
|
|
694
|
-
this.#pollBackoff.delete(
|
|
695
|
-
return;
|
|
686
|
+
this.#pollBackoff.delete(loopId);
|
|
687
|
+
return null;
|
|
696
688
|
}
|
|
697
689
|
const pollSec = row?.poll_seconds ?? null;
|
|
698
690
|
// {§exec-poll} — a positive explicit cadence wins, zero opts out,
|
|
699
691
|
// and an absent cadence uses the worker's exponential-backoff step.
|
|
700
692
|
let delayMs;
|
|
701
693
|
if (pollSec !== null && pollSec > 0) {
|
|
702
|
-
this.#pollBackoff.delete(
|
|
694
|
+
this.#pollBackoff.delete(loopId);
|
|
703
695
|
delayMs = pollSec * 1000;
|
|
704
696
|
}
|
|
705
697
|
else if (pollSec === 0) {
|
|
706
|
-
this.#pollBackoff.delete(
|
|
707
|
-
return; // explicit opt-out
|
|
698
|
+
this.#pollBackoff.delete(loopId);
|
|
699
|
+
return null; // explicit opt-out
|
|
708
700
|
}
|
|
709
701
|
else {
|
|
710
702
|
// An open stream without an explicit cadence uses the stream polling floor.
|
|
711
703
|
// Child joins never enter this branch: durable child settlement is their only wake edge.
|
|
712
704
|
const base = Number(process.env.PLURNK_SERVICE_EXEC_POLL_SEC ?? "60");
|
|
713
705
|
const turns = Number(process.env.PLURNK_SERVICE_EXEC_POLL_TURNS ?? "8");
|
|
714
|
-
const step = this.#pollBackoff.get(
|
|
706
|
+
const step = this.#pollBackoff.get(loopId) ?? 0;
|
|
715
707
|
delayMs = execPollBackoffMs(step, base, turns);
|
|
716
|
-
this.#pollBackoff.set(
|
|
708
|
+
this.#pollBackoff.set(loopId, step + 1);
|
|
717
709
|
}
|
|
718
710
|
// Floored by the optimistic settlement cap so a `<…,1>` cannot wake a
|
|
719
711
|
// parked loop faster than the preceding turn's settlement scale.
|
|
720
|
-
|
|
721
|
-
const timer = setTimeout(() => {
|
|
722
|
-
this.#pollTimers.delete(workerId);
|
|
723
|
-
void this.#wakeParkedWorker(workspaceId, workerId, systemPrompt);
|
|
724
|
-
}, Math.max(delayMs, optimisticWaitMs));
|
|
725
|
-
timer.unref();
|
|
726
|
-
this.#pollTimers.set(workerId, timer);
|
|
712
|
+
return Math.max(delayMs, readOptimisticSettlementMs());
|
|
727
713
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
714
|
+
async #wakeLoop(workerId, loopId, condition = {}) {
|
|
715
|
+
// {§worker-lifecycle-durable-disposition}: test admission at the mutation,
|
|
716
|
+
// after asynchronous prompt, completion, or deadline selection.
|
|
717
|
+
if (!this.#acceptingWork || this.#workerAborts.get(workerId)?.signal.aborted)
|
|
718
|
+
return false;
|
|
719
|
+
return this.#lifecycle.wake(loopId, condition);
|
|
720
|
+
}
|
|
721
|
+
async #wakeParkedWorker(workspaceId, workerId, systemPrompt) {
|
|
733
722
|
if (!this.#acceptingWork)
|
|
734
723
|
return;
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
// conclusion that fired this wake arrived before the 202 committed (the conclude-before-park
|
|
742
|
-
// race). Owe the wake: the drain honors it at park so a worker hibernation never deadlocks.
|
|
743
|
-
// (No active drain → already concluded/running; nothing to wake.)
|
|
744
|
-
if (this.#activeDrains.has(workerId)) {
|
|
745
|
-
if (oweIfActive)
|
|
746
|
-
this.#owedWakes.add(workerId);
|
|
724
|
+
const waits = await this.#lifecycle.parked(workerId);
|
|
725
|
+
let woke = false;
|
|
726
|
+
for (const wait of waits) {
|
|
727
|
+
if (await this.#wakeLoop(workerId, wait.id, { revision: wait.wait_revision, eventOnly: true })) {
|
|
728
|
+
this.#clearLoopTimer(wait.id);
|
|
729
|
+
woke = true;
|
|
747
730
|
}
|
|
748
|
-
return;
|
|
749
731
|
}
|
|
750
|
-
const woke = await this.#lifecycle.wake(slept.id);
|
|
751
732
|
if (!woke)
|
|
752
733
|
return;
|
|
753
734
|
const started = await this.ensureDrain({
|
|
@@ -760,14 +741,11 @@ export default class DrainSupervisor {
|
|
|
760
741
|
});
|
|
761
742
|
}
|
|
762
743
|
async #workerHasLiveObligation(workerId) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
return openSubscriptions.some(({ id }) => !this.#isDetachedSubscription(id)) || liveChild !== undefined;
|
|
769
|
-
}
|
|
770
|
-
settleCompletionWake(workspaceId, workerId, systemPrompt, oweIfActive = true) {
|
|
744
|
+
// {§worker-obligations} — the same row the completion gate reads.
|
|
745
|
+
const held = await this.#db.worker_live_obligations.get({ worker_id: workerId });
|
|
746
|
+
return held !== undefined && (held.streams === 1 || held.workers === 1);
|
|
747
|
+
}
|
|
748
|
+
settleCompletionWake(workspaceId, workerId, systemPrompt) {
|
|
771
749
|
const existing = this.#completionWakeGates.get(workerId);
|
|
772
750
|
if (existing !== undefined) {
|
|
773
751
|
existing.conclusions++;
|
|
@@ -781,23 +759,23 @@ export default class DrainSupervisor {
|
|
|
781
759
|
promise: completed.promise,
|
|
782
760
|
};
|
|
783
761
|
this.#completionWakeGates.set(workerId, gate);
|
|
784
|
-
void this.#runCompletionWake(workspaceId, workerId, systemPrompt,
|
|
762
|
+
void this.#runCompletionWake(workspaceId, workerId, systemPrompt, gate).then(completed.resolve, completed.reject).finally(() => {
|
|
785
763
|
if (this.#completionWakeGates.get(workerId) === gate) {
|
|
786
764
|
this.#completionWakeGates.delete(workerId);
|
|
787
765
|
}
|
|
788
766
|
});
|
|
789
767
|
return gate.promise;
|
|
790
768
|
}
|
|
791
|
-
async #runCompletionWake(workspaceId, workerId, systemPrompt,
|
|
769
|
+
async #runCompletionWake(workspaceId, workerId, systemPrompt, gate) {
|
|
792
770
|
const slept = await this.#db.drain_find_slept_loop.get({ worker_id: workerId });
|
|
793
771
|
if (slept === undefined) {
|
|
794
772
|
this.#releaseCompletionWake(workerId, gate);
|
|
795
|
-
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt
|
|
773
|
+
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt);
|
|
796
774
|
}
|
|
797
775
|
const timeoutMs = readOptimisticSettlementMs();
|
|
798
776
|
if (timeoutMs === 0 || !(await this.#workerHasLiveObligation(workerId))) {
|
|
799
777
|
this.#releaseCompletionWake(workerId, gate);
|
|
800
|
-
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt
|
|
778
|
+
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt);
|
|
801
779
|
}
|
|
802
780
|
return observed("worker.wake.settlement", { "window.ms": timeoutMs }, async (span) => {
|
|
803
781
|
const startedAt = performance.now();
|
|
@@ -829,7 +807,7 @@ export default class DrainSupervisor {
|
|
|
829
807
|
this.#releaseCompletionWake(workerId, gate);
|
|
830
808
|
if (release === "cancelled")
|
|
831
809
|
return;
|
|
832
|
-
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt
|
|
810
|
+
return this.#wakeParkedWorker(workspaceId, workerId, systemPrompt);
|
|
833
811
|
});
|
|
834
812
|
}
|
|
835
813
|
#releaseCompletionWake(workerId, gate) {
|
|
@@ -837,24 +815,18 @@ export default class DrainSupervisor {
|
|
|
837
815
|
this.#completionWakeGates.delete(workerId);
|
|
838
816
|
}
|
|
839
817
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
async #onDrainExit(workspaceId, workerId, systemPrompt) {
|
|
847
|
-
const slept = await this.#db.drain_find_slept_loop.get({ worker_id: workerId });
|
|
848
|
-
if (slept !== undefined)
|
|
849
|
-
return; // parked at 202 — not concluded, the worker is still alive
|
|
850
|
-
const openSubs = (await this.#db.find_open_subscriptions_for_worker.all({ worker_id: workerId }))
|
|
851
|
-
.filter(({ id }) => !this.#isDetachedSubscription(id)); // {§exec-timeout} — `<-1>` is nobody's obligation
|
|
852
|
-
if (openSubs.length > 0)
|
|
853
|
-
return; // a stream still runs — its conclusion re-evaluates, not this exit
|
|
818
|
+
#publishTermination(workspaceId, event) {
|
|
819
|
+
this.#emit(workspaceId, "loop/terminated", event);
|
|
820
|
+
this.#trackSettlement(this.#notifyParentCompletion(workspaceId, event.workerId), "wake-on-completion");
|
|
821
|
+
}
|
|
822
|
+
// {§worker-lifecycle-child-wake}: completion belongs to a task, not drain teardown.
|
|
823
|
+
async #notifyParentCompletion(workspaceId, workerId) {
|
|
854
824
|
const parent = await this.#db.worker_parent_id.get({ worker_id: workerId });
|
|
855
825
|
if (parent?.parent_worker_id == null)
|
|
856
|
-
return;
|
|
857
|
-
await this.settleCompletionWake(workspaceId, parent.parent_worker_id,
|
|
826
|
+
return;
|
|
827
|
+
await this.settleCompletionWake(workspaceId, parent.parent_worker_id, await this.#readSystemPrompt());
|
|
858
828
|
}
|
|
859
829
|
}
|
|
830
|
+
_a = DrainSupervisor;
|
|
831
|
+
export default DrainSupervisor;
|
|
860
832
|
//# sourceMappingURL=DrainSupervisor.js.map
|