@plurnk/plurnk-service 1.3.12 → 1.4.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 +84 -77
- package/INSTALL.md +50 -25
- package/README.md +24 -10
- package/SPEC.md +2311 -928
- package/dist/Paths.d.ts +4 -1
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +23 -21
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/edit-receipt.d.ts +13 -28
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +285 -104
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/edited-span.d.ts.map +1 -1
- package/dist/content/edited-span.js +2 -5
- package/dist/content/edited-span.js.map +1 -1
- package/dist/content/index.d.ts +3 -3
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-marker.d.ts +6 -9
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +7 -11
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +14 -25
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +77 -107
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/mimetype-binary.d.ts +2 -2
- package/dist/content/mimetype-binary.d.ts.map +1 -1
- package/dist/content/mimetype-binary.js +10 -10
- package/dist/content/mimetype-binary.js.map +1 -1
- package/dist/content/path-mimetype.js +3 -3
- package/dist/content/path-mimetype.js.map +1 -1
- package/dist/content/read-resolve.d.ts +8 -4
- package/dist/content/read-resolve.d.ts.map +1 -1
- package/dist/content/read-resolve.js +101 -49
- package/dist/content/read-resolve.js.map +1 -1
- package/dist/core/BranchReceipt.d.ts +7 -0
- package/dist/core/BranchReceipt.d.ts.map +1 -0
- package/dist/core/BranchReceipt.js +27 -0
- package/dist/core/BranchReceipt.js.map +1 -0
- package/dist/core/BudgetOverflow.d.ts +23 -0
- package/dist/core/BudgetOverflow.d.ts.map +1 -0
- package/dist/core/BudgetOverflow.js +61 -0
- package/dist/core/BudgetOverflow.js.map +1 -0
- package/dist/core/BudgetReadout.d.ts +8 -0
- package/dist/core/BudgetReadout.d.ts.map +1 -0
- package/dist/core/BudgetReadout.js +79 -0
- package/dist/core/BudgetReadout.js.map +1 -0
- package/dist/core/ChannelWrite.d.ts +28 -9
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +28 -21
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +11 -10
- package/dist/core/CoreSchemeServices.d.ts +10 -4
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +7 -1
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +29 -20
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +1488 -599
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/DurableStatement.d.ts +6 -0
- package/dist/core/DurableStatement.d.ts.map +1 -0
- package/dist/core/DurableStatement.js +51 -0
- package/dist/core/DurableStatement.js.map +1 -0
- package/dist/core/Engine.d.ts +48 -20
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +1208 -789
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +309 -217
- package/dist/core/EnvFlags.js +1 -1
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/ErrorDetail.d.ts +6 -0
- package/dist/core/ErrorDetail.d.ts.map +1 -0
- package/dist/core/ErrorDetail.js +20 -0
- package/dist/core/ErrorDetail.js.map +1 -0
- package/dist/core/ExecutorRegistry.d.ts +14 -3
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +56 -30
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/GitBranch.d.ts +20 -0
- package/dist/core/GitBranch.d.ts.map +1 -0
- package/dist/core/GitBranch.js +110 -0
- package/dist/core/GitBranch.js.map +1 -0
- package/dist/core/JournalTurn.d.ts +9 -0
- package/dist/core/JournalTurn.d.ts.map +1 -0
- package/dist/core/JournalTurn.js +14 -0
- package/dist/core/JournalTurn.js.map +1 -0
- package/dist/core/JournalTurn.sql +10 -0
- package/dist/core/LogBody.d.ts +17 -0
- package/dist/core/LogBody.d.ts.map +1 -0
- package/dist/core/LogBody.js +148 -0
- package/dist/core/LogBody.js.map +1 -0
- package/dist/core/LoopFlagsReader.d.ts +7 -0
- package/dist/core/LoopFlagsReader.d.ts.map +1 -0
- package/dist/core/LoopFlagsReader.js +33 -0
- package/dist/core/LoopFlagsReader.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +8 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +55 -9
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +9 -3
- package/dist/core/NoticeChannel.d.ts +13 -0
- package/dist/core/NoticeChannel.d.ts.map +1 -0
- package/dist/core/NoticeChannel.js +40 -0
- package/dist/core/NoticeChannel.js.map +1 -0
- package/dist/core/Owner.d.ts +0 -1
- package/dist/core/Owner.d.ts.map +1 -1
- package/dist/core/Owner.js +2 -5
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +25 -24
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +313 -375
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.d.ts +26 -0
- package/dist/core/ProblemLog.d.ts.map +1 -0
- package/dist/core/ProblemLog.js +58 -0
- package/dist/core/ProblemLog.js.map +1 -0
- package/dist/core/ProposalLifecycle.d.ts +15 -21
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +291 -78
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +51 -48
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +14 -8
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +189 -114
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ServiceTeardown.d.ts +11 -0
- package/dist/core/ServiceTeardown.d.ts.map +1 -0
- package/dist/core/ServiceTeardown.js +70 -0
- package/dist/core/ServiceTeardown.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +29 -0
- package/dist/core/StoredPacket.d.ts.map +1 -0
- package/dist/core/StoredPacket.js +147 -0
- package/dist/core/StoredPacket.js.map +1 -0
- package/dist/core/StrikeRail.d.ts +1 -2
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +25 -55
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/WorkerControlAddress.d.ts +17 -0
- package/dist/core/WorkerControlAddress.d.ts.map +1 -0
- package/dist/core/WorkerControlAddress.js +44 -0
- package/dist/core/WorkerControlAddress.js.map +1 -0
- package/dist/core/WorkerName.d.ts +31 -0
- package/dist/core/WorkerName.d.ts.map +1 -0
- package/dist/core/WorkerName.js +95 -0
- package/dist/core/WorkerName.js.map +1 -0
- package/dist/core/WorkerName.sql +36 -0
- package/dist/core/WorkspaceGate.d.ts +14 -0
- package/dist/core/WorkspaceGate.d.ts.map +1 -0
- package/dist/core/WorkspaceGate.js +155 -0
- package/dist/core/WorkspaceGate.js.map +1 -0
- package/dist/core/caps/CapsResolve.d.ts +1 -1
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +5 -11
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +24 -8
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +4 -13
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +15 -6
- 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 +12 -11
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbProjectionCaps.d.ts +5 -5
- package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +21 -4
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -4
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +57 -62
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/DbTagCaps.d.ts +5 -12
- package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
- package/dist/core/caps/DbTagCaps.js +14 -7
- package/dist/core/caps/DbTagCaps.js.map +1 -1
- package/dist/core/content-hash.js +1 -1
- package/dist/core/content-hash.js.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +55 -30
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +41 -27
- package/dist/core/git-env.d.ts +2 -0
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +13 -18
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-iso.d.ts.map +1 -1
- package/dist/core/git-iso.js +9 -15
- package/dist/core/git-iso.js.map +1 -1
- package/dist/core/git-membership.d.ts +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +198 -146
- 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 +10 -11
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/owner.sql +1 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +7 -11
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +2 -20
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +242 -368
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +12 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +49 -29
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/results.d.ts +16 -5
- package/dist/core/results.d.ts.map +1 -1
- package/dist/core/results.js +27 -18
- package/dist/core/results.js.map +1 -1
- package/dist/core/ruler_count.d.ts +4 -0
- package/dist/core/ruler_count.d.ts.map +1 -0
- package/dist/core/ruler_count.js +7 -0
- package/dist/core/ruler_count.js.map +1 -0
- package/dist/core/scheme-types.d.ts +9 -11
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/search-gate.d.ts.map +1 -1
- package/dist/core/search-gate.js +3 -11
- package/dist/core/search-gate.js.map +1 -1
- package/dist/core/teaching-corpus.d.ts +6 -0
- package/dist/core/teaching-corpus.d.ts.map +1 -0
- package/dist/core/teaching-corpus.js +23 -0
- package/dist/core/teaching-corpus.js.map +1 -0
- package/dist/core/teaching.d.ts +0 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +2 -8
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/token-ruler.d.ts.map +1 -1
- package/dist/core/token-ruler.js +3 -16
- package/dist/core/token-ruler.js.map +1 -1
- package/dist/core/turn-scheduler.d.ts +1 -1
- package/dist/core/turn-scheduler.d.ts.map +1 -1
- package/dist/core/turn-scheduler.js +1 -1
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/worker-cap.d.ts +2 -4
- package/dist/core/worker-cap.d.ts.map +1 -1
- package/dist/core/worker-cap.js +13 -4
- package/dist/core/worker-cap.js.map +1 -1
- package/dist/core/{run-ops.sql → worker-ops.sql} +11 -11
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +17 -9
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts +2 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +337 -138
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +19 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/matrix/live-specimen.d.ts +9 -0
- package/dist/matrix/live-specimen.d.ts.map +1 -0
- package/dist/matrix/live-specimen.js +37 -0
- package/dist/matrix/live-specimen.js.map +1 -0
- package/dist/observe/api.d.ts +6 -0
- package/dist/observe/api.d.ts.map +1 -0
- package/dist/observe/api.js +11 -0
- package/dist/observe/api.js.map +1 -0
- package/dist/observe/init.d.ts +7 -0
- package/dist/observe/init.d.ts.map +1 -0
- package/dist/observe/init.js +159 -0
- package/dist/observe/init.js.map +1 -0
- package/dist/observe/metrics.d.ts +6 -0
- package/dist/observe/metrics.d.ts.map +1 -0
- package/dist/observe/metrics.js +15 -0
- package/dist/observe/metrics.js.map +1 -0
- package/dist/observe/spans.d.ts +4 -0
- package/dist/observe/spans.d.ts.map +1 -0
- package/dist/observe/spans.js +51 -0
- package/dist/observe/spans.js.map +1 -0
- package/dist/schemes/EffectPolicy.d.ts +1 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +5 -2
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts +6 -11
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +364 -247
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +8 -7
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +48 -9
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +7 -11
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +279 -142
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +4 -8
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +475 -208
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +62 -30
- package/dist/schemes/Prompt.d.ts +3 -2
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +9 -6
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Skill.d.ts +1 -1
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +2 -3
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts +8 -16
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +179 -69
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-chunk.d.ts.map +1 -1
- package/dist/schemes/_entry-chunk.js +12 -5
- package/dist/schemes/_entry-chunk.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +10 -9
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +59 -13
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +20 -8
- package/dist/schemes/_entry-find.d.ts +20 -15
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +339 -174
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +20 -8
- package/dist/schemes/_entry-graph.d.ts +4 -2
- package/dist/schemes/_entry-graph.d.ts.map +1 -1
- package/dist/schemes/_entry-graph.js +55 -31
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-graph.sql +37 -22
- package/dist/schemes/_entry-manifest.d.ts +10 -15
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +50 -268
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +9 -14
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +149 -77
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +1 -1
- package/dist/schemes/_entry-semantic.d.ts +23 -8
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +141 -60
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +63 -45
- package/dist/schemes/_entry-send.d.ts +3 -4
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +48 -23
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_path-scope.d.ts +23 -0
- package/dist/schemes/_path-scope.d.ts.map +1 -0
- package/dist/schemes/_path-scope.js +61 -0
- package/dist/schemes/_path-scope.js.map +1 -0
- package/dist/schemes/_search-candidate.d.ts +20 -0
- package/dist/schemes/_search-candidate.d.ts.map +1 -0
- package/dist/schemes/_search-candidate.js +19 -0
- package/dist/schemes/_search-candidate.js.map +1 -0
- package/dist/schemes/_search-exclusion.d.ts +7 -0
- package/dist/schemes/_search-exclusion.d.ts.map +1 -0
- package/dist/schemes/_search-exclusion.js +23 -0
- package/dist/schemes/_search-exclusion.js.map +1 -0
- package/dist/schemes/_search-index.d.ts +6 -0
- package/dist/schemes/_search-index.d.ts.map +1 -0
- package/dist/schemes/_search-index.js +326 -0
- package/dist/schemes/_search-index.js.map +1 -0
- package/dist/schemes/cosine.js +1 -1
- package/dist/schemes/cosine.js.map +1 -1
- package/dist/schemes/exec-abort.js +3 -3
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/schemes/exec-env.js +3 -3
- package/dist/schemes/exec-env.js.map +1 -1
- package/dist/server/BranchBatches.d.ts +48 -0
- package/dist/server/BranchBatches.d.ts.map +1 -0
- package/dist/server/BranchBatches.js +591 -0
- package/dist/server/BranchBatches.js.map +1 -0
- package/dist/server/Daemon.d.ts +36 -66
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +920 -446
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +31 -0
- package/dist/server/DaemonModule.d.ts.map +1 -0
- package/dist/server/DaemonModule.js +2 -0
- package/dist/server/DaemonModule.js.map +1 -0
- package/dist/server/branch-batch.sql +152 -0
- package/dist/server/client-input.d.ts +12 -0
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +262 -57
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +15 -7
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +92 -62
- package/dist/server/envelope.d.ts +2 -5
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +119 -95
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +19 -23
- package/dist/server/exec-poll-backoff.js +1 -1
- package/dist/server/exec-poll-backoff.js.map +1 -1
- package/dist/server/lifecycle-recovery.sql +79 -2
- package/dist/server/logEntry.d.ts +3 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +4 -2
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +1 -1
- package/dist/server/loop-model.d.ts.map +1 -1
- package/dist/server/loop-model.js +22 -9
- package/dist/server/loop-model.js.map +1 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +5 -4
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/seam-entry-read.sql +15 -10
- package/dist/server/seam-log-read.sql +2 -2
- package/dist/server/seam-loop.sql +1 -1
- package/dist/server/seam-proposal-list.sql +17 -7
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +66 -60
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +897 -0
- package/package.json +57 -26
- package/dist/core/PluginLoader.d.ts +0 -20
- package/dist/core/PluginLoader.d.ts.map +0 -1
- package/dist/core/PluginLoader.js +0 -142
- package/dist/core/PluginLoader.js.map +0 -1
- package/dist/core/TelemetryChannel.d.ts +0 -37
- package/dist/core/TelemetryChannel.d.ts.map +0 -1
- package/dist/core/TelemetryChannel.js +0 -80
- package/dist/core/TelemetryChannel.js.map +0 -1
- package/dist/core/path-decode.d.ts +0 -3
- package/dist/core/path-decode.d.ts.map +0 -1
- package/dist/core/path-decode.js +0 -9
- package/dist/core/path-decode.js.map +0 -1
- package/dist/core/plugin-attribution.d.ts +0 -5
- package/dist/core/plugin-attribution.d.ts.map +0 -1
- package/dist/core/plugin-attribution.js +0 -39
- package/dist/core/plugin-attribution.js.map +0 -1
- package/dist/core/world-state.d.ts +0 -10
- package/dist/core/world-state.d.ts.map +0 -1
- package/dist/core/world-state.js +0 -35
- package/dist/core/world-state.js.map +0 -1
- package/dist/core/world-state.sql +0 -35
- package/dist/core/zero-pin.d.ts +0 -3
- package/dist/core/zero-pin.d.ts.map +0 -1
- package/dist/core/zero-pin.js +0 -16
- package/dist/core/zero-pin.js.map +0 -1
- package/dist/server/auto.d.ts +0 -6
- package/dist/server/auto.d.ts.map +0 -1
- package/dist/server/auto.js +0 -63
- package/dist/server/auto.js.map +0 -1
- package/dist/server/clientTurn.d.ts +0 -6
- package/dist/server/clientTurn.d.ts.map +0 -1
- package/dist/server/clientTurn.js +0 -22
- package/dist/server/clientTurn.js.map +0 -1
- package/dist/server/clientTurn.sql +0 -10
- package/dist/server/noProposals.d.ts +0 -6
- package/dist/server/noProposals.d.ts.map +0 -1
- package/dist/server/noProposals.js +0 -37
- package/dist/server/noProposals.js.map +0 -1
- package/dist/server/version-info.d.ts +0 -14
- package/dist/server/version-info.d.ts.map +0 -1
- package/dist/server/version-info.js +0 -69
- package/dist/server/version-info.js.map +0 -1
- package/migrations/0000-00-00.01_schema.sql +0 -536
- package/migrations/0004_loop-provider.sql +0 -3
- package/migrations/0005_subscription-published-channel.sql +0 -3
- package/migrations/0006_loop-max-turns.sql +0 -3
|
@@ -4,24 +4,89 @@ import { rulerCount } from "./token-ruler.js";
|
|
|
4
4
|
import { docsExcludeSet } from "./teaching.js";
|
|
5
5
|
import { Policy } from "@plurnk/plurnk-execs";
|
|
6
6
|
import WorkspaceSettings from "./workspace-settings.js";
|
|
7
|
-
import
|
|
7
|
+
import LoopFlagsReader from "./LoopFlagsReader.js";
|
|
8
8
|
import { readPacketInject, readSystemPolicy, readProjectPolicy } from "./packet-inject.js";
|
|
9
9
|
import { readFile } from "node:fs/promises";
|
|
10
|
-
import { resolve as resolvePath } from "node:path";
|
|
11
10
|
import Paths from "../Paths.js";
|
|
11
|
+
import { readTeachingSource } from "./teaching-corpus.js";
|
|
12
12
|
// Shared module imported by both Engine and bin/digest.ts, so wire
|
|
13
13
|
// projection and digest projection are structurally one function — no
|
|
14
14
|
// drift between wire and digest possible.
|
|
15
15
|
import PacketWire from "./packet-wire.js";
|
|
16
|
-
import { scopeEnvToAlias, resolveActiveAlias } from "@plurnk/plurnk-providers";
|
|
16
|
+
import { assertPromptTokenMeasurement, scopeEnvToAlias, resolveActiveAlias } from "@plurnk/plurnk-providers";
|
|
17
17
|
import ProviderInstantiate from "./ProviderInstantiate.js";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
import BudgetOverflow from "./BudgetOverflow.js";
|
|
19
|
+
import BudgetReadout from "./BudgetReadout.js";
|
|
20
|
+
const trimHorizontal = (value) => value.replace(/^[\t ]+|[\t ]+$/gu, "");
|
|
21
|
+
const tableCells = (line) => {
|
|
22
|
+
if (!line.startsWith("|") || !line.endsWith("|"))
|
|
23
|
+
return null;
|
|
24
|
+
const cells = [];
|
|
25
|
+
let start = 1;
|
|
26
|
+
for (let index = 1; index < line.length - 1; index += 1) {
|
|
27
|
+
if (line[index] !== "|")
|
|
28
|
+
continue;
|
|
29
|
+
let escapes = 0;
|
|
30
|
+
for (let previous = index - 1; previous >= start && line[previous] === "\\"; previous -= 1)
|
|
31
|
+
escapes += 1;
|
|
32
|
+
if (escapes % 2 === 1)
|
|
33
|
+
continue;
|
|
34
|
+
cells.push(line.slice(start, index));
|
|
35
|
+
start = index + 1;
|
|
36
|
+
}
|
|
37
|
+
cells.push(line.slice(start, -1));
|
|
38
|
+
return cells;
|
|
39
|
+
};
|
|
40
|
+
const isTableDivider = (cells) => cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/u.test(trimHorizontal(cell)));
|
|
41
|
+
// {§definition-table-projection} — plurnk.md remains spacious for human editing;
|
|
42
|
+
// only its well-formed Markdown tables lose authoring alignment on the packet wire.
|
|
43
|
+
const compactDefinitionTables = (markdown) => {
|
|
44
|
+
const lines = markdown.split("\n");
|
|
45
|
+
let fence = null;
|
|
46
|
+
let inTable = false;
|
|
47
|
+
let dividerIndex = -1;
|
|
48
|
+
return lines.map((rawLine, index) => {
|
|
49
|
+
const carriageReturn = rawLine.endsWith("\r") ? "\r" : "";
|
|
50
|
+
const line = carriageReturn.length > 0 ? rawLine.slice(0, -1) : rawLine;
|
|
51
|
+
const fenceRun = line.match(/^ {0,3}(`{3,}|~{3,})/u)?.[1];
|
|
52
|
+
if (fence !== null) {
|
|
53
|
+
const closingRun = line.match(/^ {0,3}(`+|~+)[\t ]*$/u)?.[1];
|
|
54
|
+
if (closingRun?.[0] === fence.marker && closingRun.length >= fence.length)
|
|
55
|
+
fence = null;
|
|
56
|
+
return rawLine;
|
|
57
|
+
}
|
|
58
|
+
if (fenceRun !== undefined) {
|
|
59
|
+
fence = { marker: fenceRun[0], length: fenceRun.length };
|
|
60
|
+
inTable = false;
|
|
61
|
+
dividerIndex = -1;
|
|
62
|
+
return rawLine;
|
|
63
|
+
}
|
|
64
|
+
const cells = tableCells(line);
|
|
65
|
+
if (!inTable) {
|
|
66
|
+
const nextRawLine = lines[index + 1] ?? "";
|
|
67
|
+
const nextLine = nextRawLine.endsWith("\r") ? nextRawLine.slice(0, -1) : nextRawLine;
|
|
68
|
+
const dividerCells = tableCells(nextLine);
|
|
69
|
+
if (cells === null || dividerCells === null || cells.length !== dividerCells.length || !isTableDivider(dividerCells))
|
|
70
|
+
return rawLine;
|
|
71
|
+
inTable = true;
|
|
72
|
+
dividerIndex = index + 1;
|
|
73
|
+
}
|
|
74
|
+
else if (cells === null) {
|
|
75
|
+
inTable = false;
|
|
76
|
+
dividerIndex = -1;
|
|
77
|
+
return rawLine;
|
|
78
|
+
}
|
|
79
|
+
if (index === dividerIndex) {
|
|
80
|
+
const divider = cells.map((cell) => {
|
|
81
|
+
const value = trimHorizontal(cell);
|
|
82
|
+
return `${value.startsWith(":") ? ":" : ""}---${value.endsWith(":") ? ":" : ""}`;
|
|
83
|
+
});
|
|
84
|
+
return `|${divider.join("|")}|${carriageReturn}`;
|
|
85
|
+
}
|
|
86
|
+
return `| ${cells.map(trimHorizontal).join(" | ")} |${carriageReturn}`;
|
|
87
|
+
}).join("\n");
|
|
88
|
+
};
|
|
89
|
+
// {§tokenomics-window-partition} — the four partition numbers. REQUIRED (fail-hard, the
|
|
25
90
|
// providers-env convention): the ceiling is DERIVED from these, never set directly
|
|
26
91
|
// (PLURNK_BUDGET_CEILING is retired — a settable ceiling let policy contradict physics).
|
|
27
92
|
const readPartitionIntFrom = (env, name, min) => {
|
|
@@ -31,40 +96,47 @@ const readPartitionIntFrom = (env, name, min) => {
|
|
|
31
96
|
throw new Error(`${name} must be an integer >= ${min}; got ${raw}`);
|
|
32
97
|
return n;
|
|
33
98
|
};
|
|
34
|
-
|
|
99
|
+
const readOptionalPositiveIntFrom = (env, name) => {
|
|
100
|
+
const raw = env[name];
|
|
101
|
+
if (raw === undefined || raw.length === 0)
|
|
102
|
+
return null;
|
|
103
|
+
const n = Number(raw);
|
|
104
|
+
if (!Number.isInteger(n) || n <= 0)
|
|
105
|
+
throw new Error(`${name} must be a positive integer; got ${raw}`);
|
|
106
|
+
return n;
|
|
107
|
+
};
|
|
108
|
+
// Packet assembly (SPEC {§packet-assembly}) + the budget grinder ({§grinder}):
|
|
35
109
|
// builds the spec'd request packet, measures it, and reclaims window on overflow.
|
|
36
110
|
class PacketBuilder {
|
|
37
111
|
#db;
|
|
38
112
|
#schemes;
|
|
39
|
-
#
|
|
113
|
+
#problems;
|
|
40
114
|
// Boot-discovered runtime executors, late-injected on Engine after daemon
|
|
41
115
|
// start() — read through a thunk so the post-construction set is visible.
|
|
42
116
|
#executors;
|
|
43
|
-
// §tokenomics-window-partition — the partition is PER-ALIAS
|
|
117
|
+
// {§tokenomics-window-partition} — the partition is PER-ALIAS, resolved per provider in
|
|
44
118
|
// #partitionFor and cached by alias; no boot-time global read.
|
|
45
|
-
constructor({ db, schemes,
|
|
119
|
+
constructor({ db, schemes, problems, executors }) {
|
|
46
120
|
this.#db = db;
|
|
47
121
|
this.#schemes = schemes;
|
|
48
|
-
this.#
|
|
122
|
+
this.#problems = problems;
|
|
49
123
|
this.#executors = executors;
|
|
50
|
-
//
|
|
124
|
+
// {§tokenomics-window-partition} — the envelope rides the provider; construction only runs the retired-knob shed
|
|
51
125
|
// so a stale operator .env fails at BOOT, not first use.
|
|
52
|
-
|
|
126
|
+
const bootAlias = resolveActiveAlias(process.env)?.alias ?? "";
|
|
127
|
+
this.#safetyFor(bootAlias);
|
|
128
|
+
this.#promptBudgetCapFor(bootAlias);
|
|
53
129
|
}
|
|
54
|
-
//
|
|
55
|
-
// envelope (n_predict honored to the context wall — the cap MUST bound it, providers#10);
|
|
56
|
-
// cloud aliases get a generous default and the backend self-clamps to its true output limit.
|
|
130
|
+
// {§tokenomics-window-partition} — provider generation settings and core packet policy both resolve per alias.
|
|
57
131
|
// scopeEnvToAlias resolves PLURNK_SERVICE_*_<alias> over the bare fallback with providers' own
|
|
58
132
|
// battle-tested suffix parser. Cached per alias; the boot-global case falls back to the active
|
|
59
133
|
// alias when a provider carries no side-table entry (a test Mock).
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
// the ruler's own packing margin — a service fact, not a model fact.
|
|
64
|
-
static #KNOBS = ["PLURNK_SERVICE_SAFETY"];
|
|
134
|
+
// Provider context and response reserves remain provider-owned. Core owns only its virtual
|
|
135
|
+
// prompt budget and the ruler's packing-safety margin.
|
|
136
|
+
static #KNOBS = ["PLURNK_SERVICE_PROMPT_BUDGET", "PLURNK_SERVICE_SAFETY"];
|
|
65
137
|
#shedChecked = false;
|
|
66
138
|
#safetyFor(alias) {
|
|
67
|
-
//
|
|
139
|
+
// {§tokenomics-window-partition} hard shed: the three misprefixed partition knobs moved to the
|
|
68
140
|
// provider tier; a stale operator .env must never silently lose its envelope to the move.
|
|
69
141
|
if (!this.#shedChecked) {
|
|
70
142
|
this.#shedChecked = true;
|
|
@@ -76,108 +148,84 @@ class PacketBuilder {
|
|
|
76
148
|
for (const k of Object.keys(process.env)) {
|
|
77
149
|
const m = /^PLURNK_SERVICE_(CTX|CONTEXT_WINDOW|REASONING|ASSISTANT|COMPLETION)(_.*)?$/.exec(k);
|
|
78
150
|
if (m !== null)
|
|
79
|
-
throw new Error(`${k} is retired
|
|
151
|
+
throw new Error(`${k} is retired: the envelope is provider-owned — the knob is ${MOVED[m[1]]}${m[2] ?? ""}.`);
|
|
80
152
|
}
|
|
81
153
|
}
|
|
82
154
|
const view = scopeEnvToAlias(process.env, alias, _a.#KNOBS);
|
|
83
155
|
return readPartitionIntFrom(view, "PLURNK_SERVICE_SAFETY", 0);
|
|
84
156
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
#isUnboundedWindow(provider) {
|
|
89
|
-
return provider.contextWindow === null;
|
|
157
|
+
#promptBudgetCapFor(alias) {
|
|
158
|
+
const view = scopeEnvToAlias(process.env, alias, _a.#KNOBS);
|
|
159
|
+
return readOptionalPositiveIntFrom(view, "PLURNK_SERVICE_PROMPT_BUDGET");
|
|
90
160
|
}
|
|
91
161
|
#partitionFor(provider) {
|
|
92
162
|
const alias = ProviderInstantiate.aliasOf(provider) ?? resolveActiveAlias(process.env)?.alias ?? "";
|
|
93
163
|
return { reasoning: provider.reasoningReserve ?? null, completion: provider.completionReserve ?? null, safety: this.#safetyFor(alias) };
|
|
94
164
|
}
|
|
95
|
-
// #528 — the operator's CONTEXT_WINDOW pin is the LOG-budget cap, core-composed: the provider
|
|
96
|
-
// reports its natural window (construction strips the pin), and the cap tightens only the
|
|
97
|
-
// prompt — never the reserves, which stay task-natural. Alias-scoped else bare; garbage fails hard.
|
|
98
|
-
#capFor(provider) {
|
|
99
|
-
const alias = ProviderInstantiate.aliasOf(provider) ?? resolveActiveAlias(process.env)?.alias ?? "";
|
|
100
|
-
const raw = scopeEnvToAlias(process.env, alias).PLURNK_PROVIDERS_CONTEXT_WINDOW;
|
|
101
|
-
if (raw === undefined || raw.length === 0)
|
|
102
|
-
return null;
|
|
103
|
-
const cap = Number.parseInt(raw, 10);
|
|
104
|
-
if (!Number.isInteger(cap) || cap <= 0)
|
|
105
|
-
throw new Error(`PLURNK_PROVIDERS_CONTEXT_WINDOW must be a positive integer, got '${raw}'`);
|
|
106
|
-
return cap;
|
|
107
|
-
}
|
|
108
165
|
// The generation envelope — REASONING + COMPLETION, one undifferentiated pool, passed on
|
|
109
|
-
// every generate({maxTokens}): no decode is unbounded (§tokenomics-window-partition). Per
|
|
110
|
-
// alias
|
|
166
|
+
// every generate({maxTokens}): no decode is unbounded ({§tokenomics-window-partition}). Per
|
|
167
|
+
// alias: gemma's measured envelope; a cloud alias's generous default the backend clamps.
|
|
111
168
|
maxTokensFor(provider) {
|
|
112
169
|
const { reasoning, completion } = this.#partitionFor(provider);
|
|
113
170
|
if (reasoning === null || completion === null)
|
|
114
|
-
return null; //
|
|
171
|
+
return null; // {§tokenomics-window-unpollable-deliberate}: unknown envelope, no cap; the backend clamps
|
|
115
172
|
return reasoning + completion;
|
|
116
173
|
}
|
|
117
|
-
// §tokenomics-window-partition — the prompt ceiling
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
// FORGOT the response lives there too. Reserves exceeding the window is a configuration
|
|
123
|
-
// contradiction — fail hard. ratio floors at 1: an overcounting ruler never expands the budget.
|
|
124
|
-
// #274/#312 follow-up (owner): the CLIENT-facing gauge denominator — the prompt budget the
|
|
125
|
-
// packet actually lives under (effective window minus the partition reserves), in REAL token
|
|
126
|
-
// space (usage.prompt, the numerator, is real; the calibration ratio maps measured→real and
|
|
127
|
-
// has no business here). The raw n_ctx overstates usable room by the reserve total.
|
|
174
|
+
// {§tokenomics-window-partition} — the natural prompt ceiling is the provider's
|
|
175
|
+
// effective context window minus its response reserves and the service's ruler
|
|
176
|
+
// safety. An optional service prompt budget may only tighten that result. It is
|
|
177
|
+
// model-facing grinder policy, never provider physics or a generation setting.
|
|
178
|
+
// The client-facing gauge, grinder ceiling, and persisted promptBudget use this one value.
|
|
128
179
|
promptBudgetFor(provider) {
|
|
129
|
-
return this.ceilingFor(provider); // ONE derivation
|
|
180
|
+
return this.ceilingFor(provider); // ONE derivation — the gauge denominator IS the grinder ceiling
|
|
130
181
|
}
|
|
131
|
-
// §tokenomics-agnostic-ruler — the ceiling is the real window partition (window − reserves),
|
|
182
|
+
// {§tokenomics-agnostic-ruler} — the ceiling is the real window partition (window − reserves),
|
|
132
183
|
// NO calibration ratio: the model-facing measure is the chars/2 ruler (an over-count for
|
|
133
184
|
// typical text), so comparing ruler-weight to the real-token ceiling is itself the conservative
|
|
134
|
-
// bias
|
|
135
|
-
//
|
|
185
|
+
// bias - the packet reports less room than the provider usually has; authoritative
|
|
186
|
+
// provider request evidence guards the pathological tail at recovery admission.
|
|
136
187
|
ceilingFor(provider) {
|
|
137
|
-
|
|
138
|
-
|
|
188
|
+
const alias = ProviderInstantiate.aliasOf(provider) ?? resolveActiveAlias(process.env)?.alias ?? "";
|
|
189
|
+
const operatorCap = this.#promptBudgetCapFor(alias);
|
|
190
|
+
// Unknown provider physics stays unknown; an explicit virtual ceiling still bounds
|
|
191
|
+
// PLURNK's packet without pretending to describe the backend.
|
|
192
|
+
if (provider.contextWindow === null)
|
|
193
|
+
return operatorCap;
|
|
139
194
|
const { reasoning, completion, safety } = this.#partitionFor(provider);
|
|
140
195
|
if (reasoning === null || completion === null)
|
|
141
|
-
return
|
|
196
|
+
return operatorCap;
|
|
142
197
|
const naturalBudget = provider.contextWindow - reasoning - completion - safety;
|
|
143
198
|
if (naturalBudget <= 0) {
|
|
144
|
-
|
|
145
|
-
// #507 — post-migration this contradiction has ONE cause: pinned absolute reserves
|
|
199
|
+
// {§tokenomics-window-partition} — this contradiction has one cause: pinned absolute reserves
|
|
146
200
|
// exceeding the window the provider detected (percent reserves derive and cannot contradict).
|
|
147
201
|
throw new Error(`window partition contradiction for alias '${alias}': window ${provider.contextWindow} <= reserves ${reasoning}+${completion}+${safety}. Pinned PLURNK_PROVIDERS_{REASONING,COMPLETION}_RESERVE absolutes exceed the detected window — repin them under it, or use percent reserves, which derive from the window.`);
|
|
148
202
|
}
|
|
149
|
-
|
|
150
|
-
// window). A cap tighter than the reserves is deliberate tightening, not a contradiction —
|
|
151
|
-
// the budget floors at 1 (0 and 1 force the same every-packet-413; the usage record needs
|
|
152
|
-
// a positive denominator). ONE derivation: the grinder ceiling IS the gauge denominator.
|
|
153
|
-
const cap = this.#capFor(provider);
|
|
154
|
-
if (cap === null)
|
|
155
|
-
return naturalBudget;
|
|
156
|
-
return Math.max(1, Math.min(cap, provider.contextWindow) - reasoning - completion - safety);
|
|
203
|
+
return operatorCap === null ? naturalBudget : Math.min(operatorCap, naturalBudget);
|
|
157
204
|
}
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
// the stored packet and the wire payload share one source of truth.
|
|
162
|
-
async buildRequestPacket({ initialMessages, requirements, workspaceId, workerId, loopId, currentTurnSeq, provider, gitStatus, telemetryErrors: presetTelemetry, }) {
|
|
205
|
+
// {§packet-stored-shape} — assemble the system/user request before the
|
|
206
|
+
// provider call; complete the same record with the provider response.
|
|
207
|
+
async buildRequestPacket({ initialMessages, requirements, workspaceId, workerId, loopId, currentTurnSeq, provider, gitStatus, notices = [], }) {
|
|
163
208
|
const byRole = (role) => initialMessages.filter((m) => m.role === role).map((m) => m.content).join("\n\n");
|
|
164
209
|
// plurnk.md (grammar/dialects) ONLY — the definition is the hot-path grammar.
|
|
165
|
-
// The scheme catalogue is its own `schemes` section below tools (§schemes-directory),
|
|
166
|
-
// NOT appended here:
|
|
167
|
-
// the scheme set at packet-time
|
|
168
|
-
const system_definition = byRole("system");
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
// the runLoop caller's messages.user for tests that bypass the
|
|
173
|
-
// foist mechanism entirely.
|
|
210
|
+
// The scheme catalogue is its own `schemes` section below tools ({§schemes-directory}),
|
|
211
|
+
// NOT appended here: the language teaching is scheme-agnostic, so the service advertises
|
|
212
|
+
// the installed scheme set at packet-time via SchemeRegistry.teach().
|
|
213
|
+
const system_definition = compactDefinitionTables(byRole("system"));
|
|
214
|
+
// The prompt section sources the loop's prompt:///<loop>/<N> entries.
|
|
215
|
+
// Inject and turn-1 initialization write them. Bare callers that
|
|
216
|
+
// bypass prompt persistence fall back to messages.user.
|
|
174
217
|
const loopSeqRow = await this.#db.engine_loop_sequence.get({ loop_id: loopId });
|
|
175
|
-
const
|
|
218
|
+
const promptPrefix = promptLoopPrefix(loopSeqRow?.sequence ?? loopId);
|
|
219
|
+
const promptRows = (await this.#db.drain_get_all_prompt_bodies_for_loop.all({
|
|
220
|
+
owner_id: workerId,
|
|
221
|
+
pattern: `${promptPrefix}%`,
|
|
222
|
+
prefix_len: promptPrefix.length,
|
|
223
|
+
}))
|
|
176
224
|
.filter((r) => typeof r.content === "string" && r.content.length > 0);
|
|
177
|
-
//
|
|
178
|
-
// each prompt's content reaches the model through its
|
|
179
|
-
// prior prompts stay READable by the listed address
|
|
180
|
-
// unfair curation imposition. Fallback: callers that bypass
|
|
225
|
+
// The section is a paths list (the errors shape - no bodies);
|
|
226
|
+
// each prompt's content reaches the model through its actionless prompt row, and
|
|
227
|
+
// prior prompts stay READable by the listed address - never silently lost, never an
|
|
228
|
+
// unfair curation imposition. Fallback: callers that bypass persistence (bare messages)
|
|
181
229
|
// still get their user text rendered directly.
|
|
182
230
|
const prompt = promptRows.length > 0
|
|
183
231
|
? promptRows.map((r) => `* prompt://${r.pathname}`).join("\n")
|
|
@@ -186,44 +234,29 @@ class PacketBuilder {
|
|
|
186
234
|
// exactly how it went missing (callers read the sysprompt but never the
|
|
187
235
|
// requirements). Read Paths.defaultRequirements (PLURNK_SERVICE_REQUIREMENTS env →
|
|
188
236
|
// requirements.md) fresh each build so edits take effect; a non-empty param wins.
|
|
189
|
-
const baseRequirements = requirements.length > 0
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
237
|
+
const baseRequirements = requirements.length > 0
|
|
238
|
+
? requirements
|
|
239
|
+
: Paths.defaultRequirementsTeachingSource === null
|
|
240
|
+
? await readFile(Paths.defaultRequirements, "utf8")
|
|
241
|
+
: await readTeachingSource(Paths.defaultRequirementsTeachingSource);
|
|
242
|
+
// {§emission-admission}: the definition owns PLAN framing, so the packet
|
|
243
|
+
// injects no duplicate syntax or plan directive.
|
|
194
244
|
const log = await this.#buildLog(workerId);
|
|
195
|
-
const
|
|
196
|
-
const countTokens = rulerCount; // §tokenomics-agnostic-ruler — the ONE model-facing ruler (chars/2), not the provider
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
// model is never taught a tag it'll then be 403'd on (the taught→emitted→rejected→508 spiral).
|
|
200
|
-
const activeSchemes = this.#schemes.resolveForLoop(await this.#loadLoopFlags(loopId));
|
|
245
|
+
const failures = await this.buildFailurePointers(loopId, currentTurnSeq);
|
|
246
|
+
const countTokens = rulerCount; // {§tokenomics-agnostic-ruler} — the ONE model-facing ruler (chars/2), not the provider
|
|
247
|
+
// {§tools-loop-affinity}: teaching and dispatch resolve the same loop flags.
|
|
248
|
+
const activeSchemes = this.#schemes.resolveForLoop(await LoopFlagsReader.read(this.#db, loopId));
|
|
201
249
|
const tools = this.#collectTools(await this.#workspaceEnabled(workspaceId), await WorkspaceSettings.questionsEnabled(this.#db, workspaceId), activeSchemes);
|
|
202
|
-
// Budget readout (SPEC.md §tokenomics). Two-pass: render the budget from
|
|
203
|
-
// the structured log's subtotals with a {{tokensFree}} placeholder, build
|
|
204
|
-
// the section list, measure the assembled total, resolve free, substitute.
|
|
205
|
-
// Subtotals come from the real log render — meta and fences included — not
|
|
206
|
-
// a serialized approximation. ceiling is the provider's window ×
|
|
207
|
-
// PLURNK_BUDGET_CEILING (null when no window is reported → headline
|
|
208
|
-
// omitted, section lines still shown). §tokenomics-render-weight-budget
|
|
209
250
|
const ceiling = this.ceilingFor(provider);
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
// system = the timeless (definition/tools/schemes/policy — byte-stable doctrine), user
|
|
216
|
-
// = the situated (append-mostly log → per-turn status clump → recap), so the prefix
|
|
217
|
-
// cache survives through the log's frozen head instead of dying at the first gauge
|
|
218
|
-
// digit. Trust is the one-way ADMISSION rule, not the slot: system admits only
|
|
219
|
-
// framework-authored, non-injectable content; engine-authored status may ride user;
|
|
220
|
-
// attacker-reachable text may never ride system. The budget section carries its
|
|
221
|
-
// {{tokensFree}} placeholders here; they resolve below once the assembled total is known.
|
|
222
|
-
const inject = await readPacketInject(); // #240 — operator section, per-turn, fail-hard on a broken path
|
|
251
|
+
const budgetReadout = BudgetReadout.draft(ceiling);
|
|
252
|
+
// The canonical default order, trust boundary, and cache-locality bias are
|
|
253
|
+
// specified at {§packet-cache-monotone}. Budget placeholders resolve only
|
|
254
|
+
// after trusted whole-list transforms establish the packet being measured.
|
|
255
|
+
const inject = await readPacketInject(); // {§packet-inject} — per-turn; a broken configured path fails hard
|
|
223
256
|
const workspaceRoot = (await this.#db.envelope_get_workspace.get({ id: workspaceId }))?.project_root ?? null;
|
|
224
257
|
const systemPolicy = await readSystemPolicy(); // ~/.plurnk/AGENTS.md (or PLURNK_SERVICE_POLICY)
|
|
225
258
|
const projectPolicy = await readProjectPolicy(workspaceRoot); // <projectRoot>/AGENTS.md (or PLURNK_SERVICE_PROJECT)
|
|
226
|
-
// Child-orientation (§child-orientation): the live things
|
|
259
|
+
// Child-orientation ({§child-orientation}): the live things this worker holds — open streams +
|
|
227
260
|
// unconcluded child workers — surfaced every turn as terse `* <status> <path>` pointers (same shape
|
|
228
261
|
// as errors) just above the errors section. Orienting STATE so the model never loses track of
|
|
229
262
|
// what it's holding (the premature-terminate trap), never advice on what to do. Empty → omitted.
|
|
@@ -232,193 +265,71 @@ class PacketBuilder {
|
|
|
232
265
|
const childWorkers = (await this.#db.engine_child_workers_live.all({ worker_id: workerId }))
|
|
233
266
|
.map((r) => ({ status: r.status, path: `worker://${r.name}` }));
|
|
234
267
|
const defaults = [
|
|
235
|
-
{ name: "definition", slot: "system", header: null, content: system_definition
|
|
236
|
-
{ name: "tools", slot: "system", header: "Registered Executable Tools", content: tools.executors
|
|
268
|
+
{ name: "definition", slot: "system", header: null, content: system_definition },
|
|
269
|
+
{ name: "tools", slot: "system", header: "Registered Executable Tools", content: tools.executors },
|
|
237
270
|
...(tools.optionalOperations.length > 0
|
|
238
|
-
? [{ name: "optional-operations", slot: "system", header: "Enabled Optional Operations", content: tools.optionalOperations
|
|
271
|
+
? [{ name: "optional-operations", slot: "system", header: "Enabled Optional Operations", content: tools.optionalOperations }]
|
|
239
272
|
: []),
|
|
240
|
-
{ name: "schemes", slot: "system", header: "Schemes", content: this.#schemes.teach()
|
|
241
|
-
...(inject !== null ? [{ name: "inject", slot: "system", header: "Operator Notes", content: inject
|
|
273
|
+
{ name: "schemes", slot: "system", header: "Schemes", content: this.#schemes.teach() },
|
|
274
|
+
...(inject !== null ? [{ name: "inject", slot: "system", header: "Operator Notes", content: inject }] : []),
|
|
242
275
|
// policy: the client's privileged rules — ~/.plurnk/AGENTS.md (system) then <root>/AGENTS.md (project) — below grammar/tools/schemes, above budget-the-law. AGENTS is POLICY here, never a curatable READable entry. Empty content ⇒ section omitted.
|
|
243
|
-
{ name: "system-policy", slot: "system", header: "Policy", content: systemPolicy ?? ""
|
|
244
|
-
{ name: "project-policy", slot: "system", header: "Project Policy", content: projectPolicy ?? ""
|
|
245
|
-
// log leads
|
|
246
|
-
{ name: "log", slot: "user", header: "Log", content: PacketWire.renderLog(log, countTokens)
|
|
247
|
-
// The
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
{ name: "child-streams", slot: "user", header: "Child Streams", content: PacketWire.renderChildPointers(childStreams), tokens: 0 },
|
|
256
|
-
{ name: "child-workers", slot: "user", header: "Active Child Workers", content: PacketWire.renderChildPointers(childWorkers), tokens: 0 },
|
|
257
|
-
{ name: "errors", slot: "user", header: "Errors", content: PacketWire.renderErrors(telemetryErrors), tokens: 0 },
|
|
258
|
-
{ name: "git", slot: "user", header: "Git Status", content: PacketWire.renderGit(gitStatus), tokens: 0 },
|
|
276
|
+
{ name: "system-policy", slot: "system", header: "Policy", content: systemPolicy ?? "" },
|
|
277
|
+
{ name: "project-policy", slot: "system", header: "Project Policy", content: projectPolicy ?? "" },
|
|
278
|
+
// The append-mostly log leads volatile user status ({§packet-cache-monotone}).
|
|
279
|
+
{ name: "log", slot: "user", header: "Log", content: PacketWire.renderLog(log, countTokens) },
|
|
280
|
+
// The per-turn status clump sits between log and recap ({§packet-cache-monotone}).
|
|
281
|
+
// child-orientation: what this worker holds live — streams then child workers — just above errors. Terse
|
|
282
|
+
// pointers (the path is the actionable address the model READs/OPENs/KILLs), never advice. {§child-orientation}
|
|
283
|
+
{ name: "child-streams", slot: "user", header: "Child Streams", content: PacketWire.renderChildPointers(childStreams) },
|
|
284
|
+
{ name: "child-workers", slot: "user", header: "Active Child Workers", content: PacketWire.renderChildPointers(childWorkers) },
|
|
285
|
+
{ name: "errors", slot: "user", header: "Errors", content: PacketWire.renderFailurePointers(failures) },
|
|
286
|
+
{ name: "notices", slot: "user", header: "Notices", content: PacketWire.renderNotices(notices) },
|
|
287
|
+
{ name: "git", slot: "user", header: "Git Status", content: PacketWire.renderGit(gitStatus) },
|
|
259
288
|
// budget — LAW (a hard ceiling the model must obey).
|
|
260
|
-
{ name: "budget", slot: "user", header: "Budget", content: budgetReadout
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
{ name: "prompt", slot: "user", header: "User Prompts", content: prompt
|
|
289
|
+
{ name: "budget", slot: "user", header: "Budget", content: budgetReadout },
|
|
290
|
+
// The prompts section closes the status clump as a paths-only list;
|
|
291
|
+
// bodies arrive through first-class prompt rows.
|
|
292
|
+
{ name: "prompt", slot: "user", header: "User Prompts", content: prompt },
|
|
264
293
|
// requirements renders LAST — the user-slot footer, the syntax contract closest to the model's turn (a recency carve-out for weak models).
|
|
265
|
-
{ name: "requirements", slot: "user", header: "Recap", content: baseRequirements
|
|
294
|
+
{ name: "requirements", slot: "user", header: "Recap", content: baseRequirements },
|
|
266
295
|
];
|
|
267
|
-
// Plugin packet control (§packet-assembly): trusted schemes rewrite the
|
|
296
|
+
// Plugin packet control ({§packet-assembly}): trusted schemes rewrite the
|
|
268
297
|
// default list — add, remove, reorder — in-process, before measurement.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// Curation pressure gates on OCCUPANCY (§tokenomics-pressure-gates-on-occupancy, #308):
|
|
279
|
-
// the Turns/Heaviest tables are a standing FOLD-target list, and a high-headroom model
|
|
280
|
-
// reads them as a todo — burning turns on token hygiene at 3% of a 64k window. Under
|
|
281
|
-
// half-full, the headline's numbers stand alone (truncate at the first blank line) and
|
|
282
|
-
// the total RE-measures — the substituted figures must reconcile with what ships.
|
|
283
|
-
// A null ceiling can't calibrate, so the full readout stays.
|
|
284
|
-
// A mermaid budget (#440) self-scales to pressure, so it is never truncated — the calm
|
|
285
|
-
// low-usage view IS the point; only the tabular readout collapses under half-full.
|
|
286
|
-
if (!budgetSec.content.includes("```mermaid") && (total / ceiling) * 100 < 50) {
|
|
287
|
-
const cut = budgetSec.content.indexOf("\n\n");
|
|
288
|
-
if (cut !== -1) {
|
|
289
|
-
budgetSec.content = budgetSec.content.slice(0, cut);
|
|
290
|
-
total = countTokens(PacketWire.renderSlot(sections, "system")) + countTokens(PacketWire.renderSlot(sections, "user"));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
const tokensFree = Math.max(0, ceiling - total); // free floors at 0 on overshoot — §tokenomics-over-budget-floor
|
|
294
|
-
const percent = (total / ceiling) * 100; // usage as % of the ceiling — §tokenomics-context-percent
|
|
295
|
-
const sumTurns = logBudget.byTurn.reduce((s, t) => s + t.tokens, 0); // #440 — treemap non-turn box = total − Σturns
|
|
296
|
-
const systemCtx = Math.max(0, total - sumTurns);
|
|
297
|
-
// replaceAll: a mermaid budget recurs free/used across the headline + treemap + pie, so a
|
|
298
|
-
// single .replace would leave the diagrams carrying literal {{…}} placeholders.
|
|
299
|
-
budgetSec.content = budgetSec.content
|
|
300
|
-
.replaceAll(TOKEN_USAGE_PLACEHOLDER, String(total))
|
|
301
|
-
// Any nonzero usage under 1% is "<1" — Math.round alone claimed "1%" from 0.51%,
|
|
302
|
-
// overstating a near-empty window.
|
|
303
|
-
.replaceAll(TOKEN_PERCENT_PLACEHOLDER, total > 0 && percent < 1 ? "<1" : String(Math.round(percent)))
|
|
304
|
-
.replaceAll(TOKENS_FREE_PLACEHOLDER, String(tokensFree))
|
|
305
|
-
.replaceAll(SYSTEM_CTX_PLACEHOLDER, String(systemCtx));
|
|
306
|
-
}
|
|
298
|
+
let drafts = await this.#schemes.transformSections(defaults);
|
|
299
|
+
const budgetSection = drafts.find((section) => section.name === "budget");
|
|
300
|
+
if (budgetSection !== undefined && ceiling !== null) {
|
|
301
|
+
const content = BudgetReadout.resolve(budgetSection.content, ceiling, (candidate) => {
|
|
302
|
+
const candidateDrafts = drafts.map((section) => section === budgetSection ? { ...section, content: candidate } : section);
|
|
303
|
+
return countTokens(PacketWire.renderSlot(candidateDrafts, "system"))
|
|
304
|
+
+ countTokens(PacketWire.renderSlot(candidateDrafts, "user"));
|
|
305
|
+
});
|
|
306
|
+
drafts = drafts.map((section) => section === budgetSection ? { ...section, content } : section);
|
|
307
307
|
}
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
// Core alone turns validated drafts into measured durable sections.
|
|
309
|
+
const sections = drafts.map((section) => ({
|
|
310
|
+
...section,
|
|
311
|
+
tokens: countTokens(PacketWire.renderSection(section)),
|
|
312
|
+
}));
|
|
312
313
|
const packetTokens = countTokens(PacketWire.renderSlot(sections, "system")) + countTokens(PacketWire.renderSlot(sections, "user"));
|
|
313
|
-
return { tokens: packetTokens, sections,
|
|
314
|
-
}
|
|
315
|
-
// Budget readout body, rendered into the `## Plurnk Service Budget` section.
|
|
316
|
-
// Headline `ceiling/free` only when a ceiling exists; section lines for the
|
|
317
|
-
// curatable index/log weight the model can FOLD back. tokensFree is a
|
|
318
|
-
// placeholder here — buildRequestPacket substitutes it after measuring the packet.
|
|
319
|
-
#renderBudget(log, ceiling) {
|
|
320
|
-
const lines = [];
|
|
321
|
-
// #421 — no ceiling (unbounded window): omit the headline entirely; the section lines below
|
|
322
|
-
// stay so the model keeps its FOLD-target surface, just with no percent it can't compute.
|
|
323
|
-
if (ceiling !== null)
|
|
324
|
-
lines.push(`Token Ceiling ${ceiling} · Token Usage ${TOKEN_USAGE_PLACEHOLDER} (${TOKEN_PERCENT_PLACEHOLDER}%) · Tokens Free ${TOKENS_FREE_PLACEHOLDER}`);
|
|
325
|
-
// #440 {§budget-mermaid} — the enriched visual Budget (default on). With a ceiling to scale
|
|
326
|
-
// against, the treemap REPLACES the Turns table (per-turn composition) + a pie gauge; the
|
|
327
|
-
// heaviest-items list stays a table (#450). Self-scaled to pressure (calm→urgent), never <50%-truncated.
|
|
328
|
-
// Set PLURNK_SERVICE_BUDGET_MERMAID=off to A/B against the tabular baseline (#440's before/after).
|
|
329
|
-
if (process.env.PLURNK_SERVICE_BUDGET_MERMAID !== "off" && ceiling !== null && log.entries > 0) {
|
|
330
|
-
if (lines.length > 0)
|
|
331
|
-
lines.push("");
|
|
332
|
-
lines.push(_a.#renderBudgetMermaid(log, ceiling));
|
|
333
|
-
// #450 — the heaviest items stay a plain ranked list (a ranking isn't a composition, no
|
|
334
|
-
// treemap; two mermaid diagrams are enough visual examples) — the same table as the tabular budget.
|
|
335
|
-
lines.push(..._a.#heaviestItemsLines(log.largest));
|
|
336
|
-
return lines.join("\n");
|
|
337
|
-
}
|
|
338
|
-
if (log.entries > 0) {
|
|
339
|
-
if (lines.length > 0)
|
|
340
|
-
lines.push("");
|
|
341
|
-
lines.push(`Log entries: ${log.entries} entries, ${log.tokens} tokens`);
|
|
342
|
-
// Per-turn weight — chronological (oldest first); the turn is the grinder's
|
|
343
|
-
// rollback unit and the rail folds the newest first (§tokenomics {§tokenomics-turn-totals}).
|
|
344
|
-
if (log.byTurn.length > 0) {
|
|
345
|
-
lines.push("", "Turns:", "| turn | tokens |", "|---|--:|");
|
|
346
|
-
for (const t of log.byTurn)
|
|
347
|
-
lines.push(`| ${t.turn} | ${t.tokens} |`);
|
|
348
|
-
}
|
|
349
|
-
lines.push(..._a.#heaviestItemsLines(log.largest));
|
|
350
|
-
}
|
|
351
|
-
return lines.join("\n");
|
|
352
|
-
}
|
|
353
|
-
// The heaviest individual log items — the FOLD targets behind the weight, a ranked LIST in both the
|
|
354
|
-
// mermaid and tabular budgets (#450: a ranking isn't a composition, so it's never a chart). "items",
|
|
355
|
-
// not "entries": log:/// rows, distinct from catalog entries (plurnk.md: "EDIT is only for entries").
|
|
356
|
-
// {§tokenomics-largest-entries}
|
|
357
|
-
static #heaviestItemsLines(largest) {
|
|
358
|
-
if (largest.length === 0)
|
|
359
|
-
return [];
|
|
360
|
-
return ["", "Heaviest items (FOLD targets — folding reclaims their tokens):", "| item | tokens |", "|---|--:|",
|
|
361
|
-
...largest.map((e) => `| ${e.path} | ${e.tokens} |`)];
|
|
362
|
-
}
|
|
363
|
-
// #440 {§budget-mermaid} — the Budget as two budget-scaled mermaid diagrams (validated to render on
|
|
364
|
-
// GitHub; syntax: plurnk-plurnkdown/demo/budget-mermaid.md). Both scaled to the CEILING, so salience
|
|
365
|
-
// tracks pressure: `free` dominates at low usage (calm), turn boxes fill as it climbs (urgent).
|
|
366
|
-
// free/used/system+context are placeholders — the post-assembly total resolves them. (#450 cut the xychart.)
|
|
367
|
-
static #renderBudgetMermaid(log, ceiling) {
|
|
368
|
-
// Turn composition → treemap: turn boxes + system+context + free compose the whole ceiling —
|
|
369
|
-
// the per-turn FOLD surface (which turns are heavy, labeled `turn L/T`) the headline can't give.
|
|
370
|
-
const treemap = [
|
|
371
|
-
"```mermaid",
|
|
372
|
-
"treemap-beta",
|
|
373
|
-
`"Budget — ceiling ${ceiling}"`,
|
|
374
|
-
` "free": ${TOKENS_FREE_PLACEHOLDER}`,
|
|
375
|
-
` "system + context": ${SYSTEM_CTX_PLACEHOLDER}`,
|
|
376
|
-
...log.byTurn.map((t) => ` "turn ${t.turn}": ${t.tokens}`),
|
|
377
|
-
"```",
|
|
378
|
-
].join("\n");
|
|
379
|
-
// Gauge → pie: used vs free, budget-scaled (used + free = ceiling); also a visual exemplar for
|
|
380
|
-
// the model's own user-facing SENDs. (#450 cut the heaviest-items xychart — its bare-coordinate
|
|
381
|
-
// labels a floor model can't decode, and the treemap already surfaces per-turn heaviness.)
|
|
382
|
-
const pie = [
|
|
383
|
-
"```mermaid",
|
|
384
|
-
"pie showData",
|
|
385
|
-
` title Budget — used vs free (ceiling ${ceiling})`,
|
|
386
|
-
` "used" : ${TOKEN_USAGE_PLACEHOLDER}`,
|
|
387
|
-
` "free" : ${TOKENS_FREE_PLACEHOLDER}`,
|
|
388
|
-
"```",
|
|
389
|
-
].join("\n");
|
|
390
|
-
return [treemap, pie].join("\n\n");
|
|
314
|
+
return { tokens: packetTokens, sections, attributions: [] };
|
|
391
315
|
}
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
// never taught-then-refused. No policy (execs unset) → everything boot-registered shows.
|
|
316
|
+
// {§operator-config-workspace-execs} — the capability sheet and executor
|
|
317
|
+
// documents share one workspace predicate with dispatch.
|
|
395
318
|
async #workspaceEnabled(workspaceId) {
|
|
396
319
|
const { execs } = await WorkspaceSettings.read(this.#db, workspaceId);
|
|
397
320
|
if (execs === null)
|
|
398
321
|
return () => true;
|
|
399
322
|
return (tag) => Policy.isEnabled(tag, execs);
|
|
400
323
|
}
|
|
401
|
-
// The ## Registered Executable Tools capability sheet
|
|
402
|
-
// tag contributes its self-documenting example
|
|
403
|
-
// registered selectors from the open-ended general examples above it. §tools-capability-sheet
|
|
404
|
-
// Mirror of Dispatcher.#loadLoopFlags — the packet reads the SAME persisted flags the gate does.
|
|
405
|
-
async #loadLoopFlags(loopId) {
|
|
406
|
-
const row = await this.#db.engine_get_loop_flags.get({ loop_id: loopId });
|
|
407
|
-
if (row === undefined)
|
|
408
|
-
return DEFAULT_LOOP_FLAGS;
|
|
409
|
-
try {
|
|
410
|
-
return { ...DEFAULT_LOOP_FLAGS, ...JSON.parse(row.flags) };
|
|
411
|
-
}
|
|
412
|
-
catch {
|
|
413
|
-
return DEFAULT_LOOP_FLAGS;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
324
|
+
// The ## Registered Executable Tools capability sheet. Each available executor
|
|
325
|
+
// tag contributes its self-documenting example; the closed heading distinguishes
|
|
326
|
+
// registered selectors from the open-ended general examples above it. {§tools-capability-sheet}
|
|
416
327
|
#collectTools(workspaceEnabled, questionsOn = false, activeSchemes) {
|
|
417
|
-
//
|
|
418
|
-
//
|
|
328
|
+
// Registered executors and optional operations remain distinct fenced sheets.
|
|
329
|
+
// {§tools-capability-sheet} {§packet-operation-fences}
|
|
419
330
|
const executorOps = [];
|
|
420
331
|
const notices = [];
|
|
421
|
-
// §send-300-choices — the one-liner rides ONLY where questions are enabled (allowed +
|
|
332
|
+
// {§send-300-choices} — the one-liner rides ONLY where questions are enabled (allowed +
|
|
422
333
|
// client-requested); the fuller questions.md doc injects through docEntries the same way.
|
|
423
334
|
const optionalOperations = questionsOn
|
|
424
335
|
? "```plurnk\n<<SEND[300]:Deploy where?;staging;production:SEND\n```"
|
|
@@ -427,7 +338,7 @@ class PacketBuilder {
|
|
|
427
338
|
if (executors !== undefined) {
|
|
428
339
|
const excluded = docsExcludeSet();
|
|
429
340
|
const runtimes = executors.availableRuntimes();
|
|
430
|
-
//
|
|
341
|
+
// {§tools-capability-sheet} The sheet's lines are EXEC-usage examples, keyed on the 'exec' scheme
|
|
431
342
|
// (the op face, excludedInAsk). When inactive, say so POSITIVELY (a prose notice): plurnk.md
|
|
432
343
|
// still teaches EXEC as language, and silent absence measurably invites confabulated runtimes.
|
|
433
344
|
const execActive = activeSchemes === undefined || activeSchemes.has("exec");
|
|
@@ -437,12 +348,12 @@ class PacketBuilder {
|
|
|
437
348
|
else {
|
|
438
349
|
for (const tag of runtimes) {
|
|
439
350
|
if (excluded.has(tag))
|
|
440
|
-
continue; //
|
|
351
|
+
continue; // {§tools-capability-sheet} — exclude drops the example and doc
|
|
441
352
|
if (!workspaceEnabled(tag))
|
|
442
|
-
continue; //
|
|
353
|
+
continue; // {§operator-config-workspace-execs}
|
|
443
354
|
const entry = executors.entry(tag);
|
|
444
|
-
//
|
|
445
|
-
// materializes at plurnk
|
|
355
|
+
// {§tools-capability-sheet} — the example is the bare op fenced below; the fuller doc
|
|
356
|
+
// materializes at worker://plurnk/docs/<tag>.md. No example → no line.
|
|
446
357
|
if (entry?.example)
|
|
447
358
|
executorOps.push(entry.example);
|
|
448
359
|
}
|
|
@@ -454,28 +365,25 @@ class PacketBuilder {
|
|
|
454
365
|
return { executors: parts.join("\n\n"), optionalOperations };
|
|
455
366
|
}
|
|
456
367
|
// #note12 — the plugin-provided reference docs (schemes' + execs' `documentation`),
|
|
457
|
-
// materialized at plurnk
|
|
458
|
-
//
|
|
368
|
+
// materialized at worker://plurnk/docs/<name>.md by LoopDocs (like operator
|
|
369
|
+
// docs) so the catalog can expose each doc's token weight.
|
|
459
370
|
async docEntries(workspaceId) {
|
|
460
|
-
const out = this.#schemes.docs(); // scheme docs already drop PLURNK_SERVICE_DOCS_EXCLUDE names
|
|
461
|
-
// §send-300-choices — the conditional teaching: questions.md
|
|
371
|
+
const out = await this.#schemes.docs(); // scheme docs already drop PLURNK_SERVICE_DOCS_EXCLUDE names
|
|
372
|
+
// {§send-300-choices} {§teaching-corpus} — the conditional teaching: questions.md
|
|
462
373
|
// materializes ONLY for enabled workspaces — the same conditional-doc mechanism as the EXEC
|
|
463
374
|
// plugin docs below. An un-enabled workspace is never taught the op it can't use.
|
|
464
375
|
if (await WorkspaceSettings.questionsEnabled(this.#db, workspaceId)) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
out.push({ name: "questions", content: q });
|
|
469
|
-
}
|
|
470
|
-
catch { /* docs package without questions.md — nothing to inject */ }
|
|
376
|
+
const q = await this.#schemes.questionsDoc();
|
|
377
|
+
if (q.length > 0)
|
|
378
|
+
out.push({ name: "questions", content: q });
|
|
471
379
|
}
|
|
472
380
|
const executors = this.#executors();
|
|
473
381
|
if (executors !== undefined) {
|
|
474
382
|
const excluded = docsExcludeSet();
|
|
475
|
-
const workspaceEnabled = await this.#workspaceEnabled(workspaceId); //
|
|
383
|
+
const workspaceEnabled = await this.#workspaceEnabled(workspaceId); // {§operator-config-workspace-execs}
|
|
476
384
|
for (const tag of executors.availableRuntimes()) {
|
|
477
385
|
if (excluded.has(tag))
|
|
478
|
-
continue; //
|
|
386
|
+
continue; // {§tools-capability-sheet} — exec docs honor the same exclude
|
|
479
387
|
if (!workspaceEnabled(tag))
|
|
480
388
|
continue;
|
|
481
389
|
const doc = executors.entry(tag)?.documentation;
|
|
@@ -485,90 +393,120 @@ class PacketBuilder {
|
|
|
485
393
|
}
|
|
486
394
|
return out;
|
|
487
395
|
}
|
|
488
|
-
// SPEC §grinder — the budget grinder. Runs pre-LLM (in runTurn, after the packet
|
|
396
|
+
// SPEC {§grinder} — the budget grinder. Runs pre-LLM (in runTurn, after the packet
|
|
489
397
|
// is built, before provider.generate); fires only on actual overflow. One rule:
|
|
490
398
|
// fold the NEWEST turn boundary's open rows (errors exempt) — never history —
|
|
491
399
|
// strike, rebuild, re-measure. Folds (never deletes). The strike it raises and
|
|
492
400
|
// the hard-stop it can signal are returned to runLoop, which owns abandonment.
|
|
493
|
-
// §grinder-overflow-only — fires only on actual overflow, never speculatively
|
|
401
|
+
// {§grinder-overflow-only} — fires only on actual overflow, never speculatively
|
|
494
402
|
async enforceBudget({ packet, provider, workerId, loopId, turnId, mintSequence, rebuild }) {
|
|
495
403
|
const ceiling = this.ceilingFor(provider);
|
|
496
404
|
const measure = (p) => p.tokens;
|
|
497
|
-
//
|
|
498
|
-
//
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
405
|
+
// {§tokenomics-window-unpollable-deliberate} — a null policy ceiling never triggers grinding. If a virtual ceiling
|
|
406
|
+
// does trigger recovery while provider physics is unknown, physical admission
|
|
407
|
+
// separately fails closed under {§tokenomics-physical-admission}.
|
|
408
|
+
if (ceiling === null || measure(packet) <= ceiling) {
|
|
409
|
+
return { packet, fit: true, struck: false, recorded: false };
|
|
410
|
+
}
|
|
411
|
+
// ONE rule, every turn — turn 1 and turn 101 alike ({§grinder-layer1-rollback}): fold the
|
|
502
412
|
// NEWEST turn boundary's still-open rows (the prior turn's emissions + this turn's
|
|
503
413
|
// pre-model rows; errors exempt) in one set-op, strike once, rebuild, re-measure.
|
|
504
|
-
//
|
|
505
|
-
//
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
completePacket(requestPacket, assistant, assistantRaw, provider) {
|
|
529
|
-
const assistantTokens = rulerCount(assistant.content); // §tokenomics-agnostic-ruler — render-weight in ruler units (usage_* keep the provider's real count)
|
|
414
|
+
// The model owns history visibility. The grinder never reaches back; it folds only the
|
|
415
|
+
// newest boundary required to produce a physically valid packet. Continued overflow
|
|
416
|
+
// follows the explicit recovery/hard-stop contract ({§grinder-fold-strikes}).
|
|
417
|
+
const usage = measure(packet);
|
|
418
|
+
await this.#db.engine_grinder_fold_newest_turn({ loop_id: loopId, turn_id: turnId });
|
|
419
|
+
let current = await rebuild();
|
|
420
|
+
if (measure(current) > ceiling) {
|
|
421
|
+
// Engine owns the hard-overflow branch and records its one occurrence with
|
|
422
|
+
// the enforced recovery constraint (or terminal physics), so this layer does
|
|
423
|
+
// not mint a second, weaker account of the same failure.
|
|
424
|
+
return { packet: current, fit: false, struck: true, recorded: false };
|
|
425
|
+
}
|
|
426
|
+
// The fold recovered the request. Preserve the triggering measurements on one
|
|
427
|
+
// actionless row and rebuild once so its Problem surfaces in this same packet.
|
|
428
|
+
await this.#problems.record({
|
|
429
|
+
workerId,
|
|
430
|
+
loopId,
|
|
431
|
+
turnId,
|
|
432
|
+
sequence: mintSequence,
|
|
433
|
+
origin: "plurnk",
|
|
434
|
+
source: "rail",
|
|
435
|
+
result: BudgetOverflow.foldedResult(usage, ceiling),
|
|
436
|
+
});
|
|
437
|
+
current = await rebuild();
|
|
530
438
|
return {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
assistantRaw,
|
|
439
|
+
packet: current,
|
|
440
|
+
fit: measure(current) <= ceiling,
|
|
441
|
+
struck: true,
|
|
442
|
+
recorded: true,
|
|
536
443
|
};
|
|
537
444
|
}
|
|
538
|
-
//
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
445
|
+
// {§tokenomics-physical-admission}: one request-shaped physical predicate.
|
|
446
|
+
// The exact PacketWire messages used for dispatch are the measurement input;
|
|
447
|
+
// empirical estimates cannot authorize recovery against a hard window.
|
|
448
|
+
async physicalAdmission(packet, provider, signal) {
|
|
449
|
+
if (provider.contextWindow === null) {
|
|
450
|
+
return {
|
|
451
|
+
admitted: false,
|
|
452
|
+
reason: "unknown_context_window",
|
|
453
|
+
detail: `provider ${JSON.stringify(provider.model)} reports no physical context window`,
|
|
454
|
+
capacity: null,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
const maxTokens = this.maxTokensFor(provider);
|
|
458
|
+
if (maxTokens === null) {
|
|
459
|
+
return {
|
|
460
|
+
admitted: false,
|
|
461
|
+
reason: "unknown_output_envelope",
|
|
462
|
+
detail: `provider ${JSON.stringify(provider.model)} reports no resolved output envelope`,
|
|
463
|
+
capacity: null,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const capacity = provider.contextWindow - maxTokens;
|
|
467
|
+
const measurement = assertPromptTokenMeasurement(await provider.countPromptTokens(PacketWire.packetToWireMessages(packet), signal), `provider ${JSON.stringify(provider.model)}`);
|
|
468
|
+
if (measurement.kind === "estimate") {
|
|
469
|
+
return {
|
|
470
|
+
admitted: false,
|
|
471
|
+
reason: "estimate",
|
|
472
|
+
detail: `${measurement.source} is an empirical estimate and cannot authorize physical recovery: ${measurement.detail}`,
|
|
473
|
+
capacity,
|
|
474
|
+
measurement,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
if (measurement.tokens > capacity) {
|
|
478
|
+
return {
|
|
479
|
+
admitted: false,
|
|
480
|
+
reason: "over_capacity",
|
|
481
|
+
detail: `${measurement.kind} prompt measurement ${measurement.tokens} exceeds physical prompt capacity ${capacity}`,
|
|
482
|
+
capacity,
|
|
483
|
+
measurement,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
return { admitted: true, capacity, measurement };
|
|
487
|
+
}
|
|
488
|
+
// Every prior-turn operation failure is durable before packet assembly.
|
|
489
|
+
// The model-facing Errors section is only a terse projection of those rows;
|
|
490
|
+
// it never reconstructs failure truth from an in-memory event.
|
|
491
|
+
async buildFailurePointers(loopId, currentTurnSeq) {
|
|
492
|
+
const rows = await this.#db.engine_render_errors.all({ loop_id: loopId, current_turn_seq: currentTurnSeq });
|
|
493
|
+
return rows.map((r) => ({
|
|
553
494
|
status: r.status_rx,
|
|
554
|
-
|
|
495
|
+
coordinate: `${r.loop_seq}/${r.turn_seq}/${r.sequence}/${r.op}`,
|
|
555
496
|
}));
|
|
556
|
-
const bufferEvents = this.#telemetry.drain(loopId).filter((e) => e.level !== "info");
|
|
557
|
-
return [...bufferEvents, ...logErrors];
|
|
558
497
|
}
|
|
559
|
-
// SPEC §packet the log section — chronological action-entries for the loop.
|
|
498
|
+
// SPEC {§packet} the log section — chronological action-entries for the loop.
|
|
560
499
|
// Snapshot is taken at packet build (pre-dispatch this turn), so it
|
|
561
500
|
// reflects "what has happened before this turn." Each row carries a
|
|
562
501
|
// log:///<loop_seq>/<turn_seq>/<sequence> coordinate the model can READ.
|
|
563
502
|
async #buildLog(workerId) {
|
|
564
|
-
// SPEC §packet-terms:
|
|
503
|
+
// SPEC {§packet-terms}: workers own log entries — log is the worker's history,
|
|
565
504
|
// not the loop's. Span all loops in the worker so the model sees
|
|
566
505
|
// earlier loops' work as conversational memory.
|
|
567
506
|
//
|
|
568
|
-
// User prompts are first-class log entries
|
|
569
|
-
//
|
|
570
|
-
//
|
|
571
|
-
// synthetic / shim layer.
|
|
507
|
+
// User prompts are first-class actionless log entries written by
|
|
508
|
+
// runTurn. They surface naturally in this query without synthetic
|
|
509
|
+
// EDIT/READ delivery rows.
|
|
572
510
|
const rows = await this.#db.engine_render_log.all({ worker_id: workerId });
|
|
573
511
|
return rows.map((r) => ({
|
|
574
512
|
coordinate: `${r.loop_seq}/${r.turn_seq}/${r.sequence}`,
|
|
@@ -581,7 +519,7 @@ class PacketBuilder {
|
|
|
581
519
|
username: r.username, password: r.password,
|
|
582
520
|
hostname: r.hostname, port: r.port,
|
|
583
521
|
pathname: r.pathname,
|
|
584
|
-
|
|
522
|
+
query: r.query,
|
|
585
523
|
fragment: r.fragment,
|
|
586
524
|
},
|
|
587
525
|
status: r.status_rx,
|