@plurnk/plurnk-service 1.14.2 → 1.16.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 +2 -2
- package/SPEC.md +243 -173
- package/digest-sql/curation/curation.sql +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/byte-view.d.ts +14 -0
- package/dist/content/byte-view.d.ts.map +1 -0
- package/dist/content/byte-view.js +33 -0
- package/dist/content/byte-view.js.map +1 -0
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +12 -1
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/line-marker.d.ts +2 -1
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +1 -0
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +1 -0
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +1 -0
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/read-projector.d.ts +4 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +80 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +43 -0
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -0
- package/dist/core/AdmittedTurnExecutor.js +245 -0
- package/dist/core/AdmittedTurnExecutor.js.map +1 -0
- package/dist/core/BareBatchRunner.d.ts +26 -0
- package/dist/core/BareBatchRunner.d.ts.map +1 -0
- package/dist/core/BareBatchRunner.js +104 -0
- package/dist/core/BareBatchRunner.js.map +1 -0
- package/dist/core/BudgetReadout.d.ts +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +42 -47
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +2 -1
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +8 -9
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +1 -1
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/DataStatementRunner.d.ts +35 -0
- package/dist/core/DataStatementRunner.d.ts.map +1 -0
- package/dist/core/DataStatementRunner.js +252 -0
- package/dist/core/DataStatementRunner.js.map +1 -0
- package/dist/core/Dispatcher.d.ts +8 -3
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +88 -738
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/EditMutations.d.ts +39 -0
- package/dist/core/EditMutations.d.ts.map +1 -0
- package/dist/core/EditMutations.js +418 -0
- package/dist/core/EditMutations.js.map +1 -0
- package/dist/core/Engine.d.ts +2 -23
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +18 -240
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +24 -23
- package/dist/core/KillHandler.d.ts +32 -0
- package/dist/core/KillHandler.d.ts.map +1 -0
- package/dist/core/KillHandler.js +179 -0
- package/dist/core/KillHandler.js.map +1 -0
- package/dist/core/LogVisibility.d.ts +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +3 -4
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LogWriter.d.ts +42 -0
- package/dist/core/LogWriter.d.ts.map +1 -0
- package/dist/core/LogWriter.js +136 -0
- package/dist/core/LogWriter.js.map +1 -0
- package/dist/core/LoopDriver.d.ts +46 -0
- package/dist/core/LoopDriver.d.ts.map +1 -0
- package/dist/core/LoopDriver.js +263 -0
- package/dist/core/LoopDriver.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +2 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/MembershipMaterialization.d.ts +7 -0
- package/dist/core/MembershipMaterialization.d.ts.map +1 -0
- package/dist/core/MembershipMaterialization.js +283 -0
- package/dist/core/MembershipMaterialization.js.map +1 -0
- package/dist/core/MutationEffects.d.ts +29 -0
- package/dist/core/MutationEffects.d.ts.map +1 -0
- package/dist/core/MutationEffects.js +318 -0
- package/dist/core/MutationEffects.js.map +1 -0
- package/dist/core/OverflowTurn.d.ts +4 -4
- package/dist/core/OverflowTurn.d.ts.map +1 -1
- package/dist/core/OverflowTurn.js +6 -7
- package/dist/core/OverflowTurn.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +31 -9
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ResourceMutations.d.ts +12 -36
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +27 -1351
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/ResourceSelector.d.ts +21 -0
- package/dist/core/ResourceSelector.d.ts.map +1 -0
- package/dist/core/ResourceSelector.js +233 -0
- package/dist/core/ResourceSelector.js.map +1 -0
- package/dist/core/ResourceTransfers.d.ts +55 -0
- package/dist/core/ResourceTransfers.d.ts.map +1 -0
- package/dist/core/ResourceTransfers.js +525 -0
- package/dist/core/ResourceTransfers.js.map +1 -0
- package/dist/core/SchemeRegistry.js +2 -2
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/SendBroadcastHandler.d.ts +40 -0
- package/dist/core/SendBroadcastHandler.d.ts.map +1 -0
- package/dist/core/SendBroadcastHandler.js +159 -0
- package/dist/core/SendBroadcastHandler.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +11 -0
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +22 -1
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +19 -9
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TokenCalibration.d.ts +16 -0
- package/dist/core/TokenCalibration.d.ts.map +1 -0
- package/dist/core/TokenCalibration.js +35 -0
- package/dist/core/TokenCalibration.js.map +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +15 -12
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/TurnMaterialization.d.ts +37 -0
- package/dist/core/TurnMaterialization.d.ts.map +1 -0
- package/dist/core/TurnMaterialization.js +296 -0
- package/dist/core/TurnMaterialization.js.map +1 -0
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +6 -8
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts +15 -27
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +76 -670
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerControlHandler.d.ts +15 -0
- package/dist/core/WorkerControlHandler.d.ts.map +1 -0
- package/dist/core/WorkerControlHandler.js +89 -0
- package/dist/core/WorkerControlHandler.js.map +1 -0
- package/dist/core/attachments.d.ts +14 -0
- package/dist/core/attachments.d.ts.map +1 -0
- package/dist/core/attachments.js +18 -0
- package/dist/core/attachments.js.map +1 -0
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +0 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +5 -16
- package/dist/core/git-membership.d.ts +15 -0
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +4 -273
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +2 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/mutation-types.d.ts +102 -0
- package/dist/core/mutation-types.d.ts.map +1 -0
- package/dist/core/mutation-types.js +2 -0
- package/dist/core/mutation-types.js.map +1 -0
- package/dist/core/operation-target-groups.js +1 -1
- package/dist/core/operation-target-groups.js.map +1 -1
- package/dist/core/packet-wire.d.ts +7 -6
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +96 -68
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +0 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +1 -1
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/statement-primary.d.ts +4 -0
- package/dist/core/statement-primary.d.ts.map +1 -0
- package/dist/core/statement-primary.js +3 -0
- package/dist/core/statement-primary.js.map +1 -0
- package/dist/core/teaching-corpus.d.ts +0 -1
- package/dist/core/teaching-corpus.d.ts.map +1 -1
- package/dist/core/teaching-corpus.js +0 -9
- package/dist/core/teaching-corpus.js.map +1 -1
- package/dist/core/turn-scheduler.js +3 -3
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/turn-signals.d.ts +15 -0
- package/dist/core/turn-signals.d.ts.map +1 -0
- package/dist/core/turn-signals.js +19 -0
- package/dist/core/turn-signals.js.map +1 -0
- package/dist/core/worker-settings.d.ts +0 -1
- package/dist/core/worker-settings.d.ts.map +1 -1
- package/dist/core/worker-settings.js +1 -1
- package/dist/core/worker-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts +3 -16
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +10 -958
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/DigestRender.d.ts +12 -0
- package/dist/digest/DigestRender.d.ts.map +1 -0
- package/dist/digest/DigestRender.js +641 -0
- package/dist/digest/DigestRender.js.map +1 -0
- package/dist/digest/DigestRequiem.d.ts +13 -0
- package/dist/digest/DigestRequiem.d.ts.map +1 -0
- package/dist/digest/DigestRequiem.js +332 -0
- package/dist/digest/DigestRequiem.js.map +1 -0
- package/dist/digest/digest-rows.d.ts +303 -0
- package/dist/digest/digest-rows.d.ts.map +1 -0
- package/dist/digest/digest-rows.js +2 -0
- package/dist/digest/digest-rows.js.map +1 -0
- package/dist/digest/digest.sql +1 -7
- package/dist/observe/api.d.ts +0 -2
- package/dist/observe/api.d.ts.map +1 -1
- package/dist/observe/api.js +2 -2
- package/dist/observe/api.js.map +1 -1
- package/dist/observe/metrics.d.ts +0 -1
- package/dist/observe/metrics.d.ts.map +1 -1
- package/dist/observe/metrics.js +0 -1
- package/dist/observe/metrics.js.map +1 -1
- package/dist/schemes/Exec.d.ts +4 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +89 -48
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +2 -1
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +3 -3
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +4 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +100 -13
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +4 -5
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +26 -118
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +1 -66
- package/dist/schemes/Prompt.js +1 -1
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +1 -13
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +3 -1
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +18 -3
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts +4 -2
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +79 -10
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts +1 -2
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +2 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +20 -2
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts +1 -0
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +3 -0
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +2 -2
- package/dist/schemes/_entry-send.d.ts +0 -1
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +5 -80
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/exec-runtime.d.ts +7 -0
- package/dist/schemes/exec-runtime.d.ts.map +1 -0
- package/dist/schemes/exec-runtime.js +2 -0
- package/dist/schemes/exec-runtime.js.map +1 -0
- package/dist/server/ClientReads.d.ts +34 -0
- package/dist/server/ClientReads.d.ts.map +1 -0
- package/dist/server/ClientReads.js +210 -0
- package/dist/server/ClientReads.js.map +1 -0
- package/dist/server/Daemon.d.ts +12 -22
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +31 -362
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +6 -5
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +3 -2
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +7 -3
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/Functionality.d.ts +0 -12
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +0 -1
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +3 -3
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +2 -13
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +4 -4
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/SkillsFunctionality.d.ts +1 -7
- package/dist/server/SkillsFunctionality.d.ts.map +1 -1
- package/dist/server/SkillsFunctionality.js +3 -3
- package/dist/server/SkillsFunctionality.js.map +1 -1
- package/dist/server/WorkerModelResolver.d.ts +17 -0
- package/dist/server/WorkerModelResolver.d.ts.map +1 -0
- package/dist/server/WorkerModelResolver.js +166 -0
- package/dist/server/WorkerModelResolver.js.map +1 -0
- package/dist/server/daemon-results.d.ts +5 -0
- package/dist/server/daemon-results.d.ts.map +1 -0
- package/dist/server/daemon-results.js +7 -0
- package/dist/server/daemon-results.js.map +1 -0
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +4 -6
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/logEntry.d.ts +0 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +1 -13
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +1 -5
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +11 -2
- package/dist/server/loopDocs.js.map +1 -1
- package/migrations/001_schema.sql +30 -347
- package/package.json +30 -30
package/dist/core/TurnRunner.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
var _a;
|
|
2
1
|
import { PathSyntax, PlurnkParser, PlurnkParseError, UNKNOWN_POSITION } from "@plurnk/plurnk-contracts";
|
|
3
2
|
import { setTimeout as delay } from "node:timers/promises";
|
|
4
3
|
import { aggregateProviderAccounting } from "@plurnk/plurnk-providers";
|
|
5
|
-
const TERMINAL_SEND_SIGNALS = new Set([102, 200, 202, 499]);
|
|
6
4
|
const comparePosition = (a, b) => a.line - b.line || a.column - b.column;
|
|
7
5
|
import Meta from "@plurnk/plurnk-meta";
|
|
8
6
|
import EntryCrud from "../schemes/_entry-crud.js";
|
|
9
7
|
import GitMembership from "./git-membership.js";
|
|
8
|
+
import { acceptedKinds } from "./attachments.js";
|
|
10
9
|
import GitState from "./git-state.js";
|
|
11
10
|
import WorkspaceSettings from "./workspace-settings.js";
|
|
12
|
-
import {
|
|
13
|
-
import ReadResolve from "../content/read-resolve.js";
|
|
14
|
-
import { authorityParts, generatedPathname, promptPathname, promptLoopPrefix } from "./plurnk-uri.js";
|
|
11
|
+
import { generatedPathname, promptPathname, promptLoopPrefix } from "./plurnk-uri.js";
|
|
15
12
|
import { readFile } from "node:fs/promises";
|
|
16
13
|
// {§grammar-rail-registration} — bare names are the built-in rail namespace;
|
|
17
14
|
// everything else is an import specifier resolved through the Node chain.
|
|
@@ -22,44 +19,22 @@ export const resolveGrammarRailPath = (variant) => variant.startsWith("/") || va
|
|
|
22
19
|
: fileURLToPath(import.meta.resolve(variant)))
|
|
23
20
|
: fileURLToPath(import.meta.resolve(`@plurnk/plurnk-contracts/${variant}`));
|
|
24
21
|
import { fileURLToPath } from "node:url";
|
|
25
|
-
import { randomUUID } from "node:crypto";
|
|
26
22
|
// Shared module imported by both Engine and bin/digest.ts, so wire
|
|
27
23
|
// projection and digest projection are structurally one function — no
|
|
28
24
|
// drift between wire and digest possible.
|
|
29
25
|
import PacketWire from "./packet-wire.js";
|
|
30
26
|
import Results, { OperationFailureError } from "./results.js";
|
|
31
|
-
import TerminalResult from "./TerminalResult.js";
|
|
32
|
-
import LoopLifecycle from "./LoopLifecycle.js";
|
|
33
|
-
import WorkerControlAddress from "./WorkerControlAddress.js";
|
|
34
27
|
import Turn from "./Turn.js";
|
|
35
|
-
import LogBody from "./LogBody.js";
|
|
36
|
-
import LogVisibility from "./LogVisibility.js";
|
|
37
|
-
import StrikeRail from "./StrikeRail.js";
|
|
38
28
|
import StoredPacket from "./StoredPacket.js";
|
|
39
29
|
import { observed, observedSync } from "../observe/spans.js";
|
|
40
|
-
import { GEN_AI_REQUEST_SPAN, genAiRequestOptions, settleGenAiResponse
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { expandSafeUriTargetGroup } from "./operation-target-groups.js";
|
|
44
|
-
import { readOptimisticSettlementMs } from "./optimistic-settlement.js";
|
|
45
|
-
import ModelCall, { ModelCallPersistenceError, ProviderAccountingIntegrityError, } from "./ModelCall.js";
|
|
30
|
+
import { GEN_AI_REQUEST_SPAN, genAiRequestOptions, settleGenAiResponse } from "../observe/genai.js";
|
|
31
|
+
import { PROVIDER_CALLS, recordCounter } from "../observe/metrics.js";
|
|
32
|
+
import ModelCall, { ModelCallPersistenceError, ProviderAccountingIntegrityError } from "./ModelCall.js";
|
|
46
33
|
import OverflowTurn from "./OverflowTurn.js";
|
|
47
34
|
import TurnOps from "./TurnOps.js";
|
|
48
35
|
import CapabilityPolicies from "./CapabilityPolicies.js";
|
|
49
36
|
import CapabilityResolver from "./CapabilityResolver.js";
|
|
50
37
|
import LoopPolicyReader from "./LoopPolicyReader.js";
|
|
51
|
-
const ENGINE_PROBLEMS = Object.freeze({
|
|
52
|
-
max_commands_exceeded: {
|
|
53
|
-
status: 429,
|
|
54
|
-
code: "max-commands-exceeded",
|
|
55
|
-
detail: "Later operations were not executed because the turn exceeded its operation limit.",
|
|
56
|
-
},
|
|
57
|
-
idle_turn: {
|
|
58
|
-
status: 409,
|
|
59
|
-
code: "idle-turn",
|
|
60
|
-
detail: "`## SEND0 [102]` was emitted without an operation to continue from.",
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
38
|
// The prompt entry target - prompt:///<loop>/<N>, self-only ({§prompt-self-only}):
|
|
64
39
|
// the owner rides the owner_id column, the address carries only the loop coordinate.
|
|
65
40
|
const promptTarget = (loopSeq, promptOrdinal) => {
|
|
@@ -139,9 +114,13 @@ const readFilesItems = () => {
|
|
|
139
114
|
return null;
|
|
140
115
|
return normalizeFilesItems(Number.parseInt(raw, 10));
|
|
141
116
|
};
|
|
142
|
-
import { ProviderError, scopeEnvToAlias
|
|
117
|
+
import { ProviderError, scopeEnvToAlias } from "@plurnk/plurnk-providers";
|
|
143
118
|
import { validateGbnf } from "@plurnk/gbnf";
|
|
144
119
|
import ProviderInstantiate from "./ProviderInstantiate.js";
|
|
120
|
+
import TurnMaterialization from "./TurnMaterialization.js";
|
|
121
|
+
import BareBatchRunner from "./BareBatchRunner.js";
|
|
122
|
+
import { TERMINAL_SEND_SIGNALS, TURN_STATUS_IMPLICIT_CONTINUE } from "./turn-signals.js";
|
|
123
|
+
import AdmittedTurnExecutor from "./AdmittedTurnExecutor.js";
|
|
145
124
|
// A generated rail may constrain only the sampled continuation while the chat
|
|
146
125
|
// template contributes a prefix that llama-server preserves in its response.
|
|
147
126
|
// The artifact names the alternate root that composes those bytes for evidence
|
|
@@ -170,10 +149,6 @@ const curationOverflowFailure = (pressure) => Results.failure("engine:context",
|
|
|
170
149
|
ceiling: pressure.budget,
|
|
171
150
|
deficit: pressure.excess,
|
|
172
151
|
});
|
|
173
|
-
// Runtime normalization for a disposition the engine refuses or resolves as a
|
|
174
|
-
// continue after dispatch ({§send}). Every admitted emission itself ends in an
|
|
175
|
-
// explicit disposition SEND ({§emission-admission}).
|
|
176
|
-
const TURN_STATUS_IMPLICIT_CONTINUE = 102;
|
|
177
152
|
const INVALID_EMISSION_RECOVERY_MESSAGE = "Response rejected before dispatch; no operations were performed.";
|
|
178
153
|
// {§output-allowance-notice} — THE single derivation of a ceiling cut: a
|
|
179
154
|
// `length` finish is the engine's own allowance ending the emission, and it
|
|
@@ -205,7 +180,7 @@ const readProviderRecoveryBackoff = () => readMilliseconds("PLURNK_SERVICE_PROVI
|
|
|
205
180
|
const RECOVERABLE_PROVIDER_FAILURES = new Set(["rate_limit", "network_failure", "deadline_exceeded", "resource_interrupted"]);
|
|
206
181
|
// The wall's abort reason — runLoop branches a mid-turn teardown to the 504 terminal on it.
|
|
207
182
|
export const LOOP_TIMEOUT_REASON = "loop_timeout";
|
|
208
|
-
class TurnRunner {
|
|
183
|
+
export default class TurnRunner {
|
|
209
184
|
#db;
|
|
210
185
|
#schemes;
|
|
211
186
|
#mimetypes;
|
|
@@ -228,6 +203,9 @@ class TurnRunner {
|
|
|
228
203
|
#dispatch;
|
|
229
204
|
#resolveWorkerProviderIdentity;
|
|
230
205
|
#gbnfCache = new Map();
|
|
206
|
+
#materialization;
|
|
207
|
+
#bareBatch;
|
|
208
|
+
#admitted;
|
|
231
209
|
constructor({ db, schemes, mimetypes, weigh, notices, problems, strikes, packets, dispatcher, liveSubscriptions, streamEventNotify, reasoningEventNotify, loopPacketNotify, wakeWorkerNotify, executors, loopSignal, interactions, warmWorkspace, dispatch, resolveWorkerProviderIdentity, }) {
|
|
232
210
|
this.#db = db;
|
|
233
211
|
this.#schemes = schemes;
|
|
@@ -250,6 +228,9 @@ class TurnRunner {
|
|
|
250
228
|
this.#warmWorkspace = warmWorkspace;
|
|
251
229
|
this.#dispatch = dispatch;
|
|
252
230
|
this.#resolveWorkerProviderIdentity = resolveWorkerProviderIdentity;
|
|
231
|
+
this.#materialization = new TurnMaterialization({ db: this.#db, schemes: this.#schemes, weighContent: this.#weighContent });
|
|
232
|
+
this.#bareBatch = new BareBatchRunner({ db: this.#db, providerAttributions: this.#providerAttributions.bind(this), providerFailure: TurnRunner.#providerFailure });
|
|
233
|
+
this.#admitted = new AdmittedTurnExecutor({ db: this.#db, schemes: this.#schemes, notices: this.#notices, problems: this.#problems, dispatcher: this.#dispatcher, bareBatch: this.#bareBatch });
|
|
253
234
|
}
|
|
254
235
|
async #recordInference(args) {
|
|
255
236
|
await Turn.recordInference(this.#db, args.turnId, args.evidence);
|
|
@@ -268,9 +249,9 @@ class TurnRunner {
|
|
|
268
249
|
// parse): warn once per message, never per turn; the turn records railsVerdict "unverifiable".
|
|
269
250
|
static #railGapWarned = new Set();
|
|
270
251
|
static #warnRailVerdictGapOnce(message) {
|
|
271
|
-
if (
|
|
252
|
+
if (TurnRunner.#railGapWarned.has(message))
|
|
272
253
|
return;
|
|
273
|
-
|
|
254
|
+
TurnRunner.#railGapWarned.add(message);
|
|
274
255
|
process.stderr.write(`plurnk-engine: rail verdict unavailable — the configured grammar did not parse in @plurnk/gbnf (${message})\n`);
|
|
275
256
|
}
|
|
276
257
|
static #requireGrammarEvidence(response, allowWithheld) {
|
|
@@ -345,93 +326,6 @@ class TurnRunner {
|
|
|
345
326
|
console.error("Provider failed outside its Problem Details contract:", error);
|
|
346
327
|
return Results.failure("engine:provider", "provider-contract-violation", 502, "The provider failed without returning its required Problem Details.", {}, { stage: "provider-request", retryable: false });
|
|
347
328
|
}
|
|
348
|
-
async #runBareBatch({ statements, provider, turnId, workspaceId, workerId, primaryWorkerId, loopSequence, turnSequence, signal, }) {
|
|
349
|
-
const prepared = [];
|
|
350
|
-
for (const statement of statements) {
|
|
351
|
-
const providerWorkerId = randomUUID();
|
|
352
|
-
const attributionContext = Object.freeze({
|
|
353
|
-
workspaceId: String(workspaceId),
|
|
354
|
-
workerId: providerWorkerId,
|
|
355
|
-
primaryWorkerId,
|
|
356
|
-
loop: loopSequence,
|
|
357
|
-
turn: turnSequence,
|
|
358
|
-
attempt: 1,
|
|
359
|
-
});
|
|
360
|
-
const attributions = this.#providerAttributions(provider, attributionContext);
|
|
361
|
-
const modelCall = await ModelCall.open(this.#db, {
|
|
362
|
-
turnId,
|
|
363
|
-
kind: "bare",
|
|
364
|
-
attributions,
|
|
365
|
-
model: provider.model,
|
|
366
|
-
});
|
|
367
|
-
prepared.push({ statement, modelCall, attributions, providerWorkerId });
|
|
368
|
-
}
|
|
369
|
-
const settlements = await Promise.allSettled(prepared.map(async ({ statement, modelCall, attributions, providerWorkerId }) => {
|
|
370
|
-
try {
|
|
371
|
-
const response = await observed(GEN_AI_REQUEST_SPAN, { model: provider.model, attempt: 1, kind: "bare" }, async (span) => {
|
|
372
|
-
try {
|
|
373
|
-
const generated = await provider.generate({
|
|
374
|
-
messages: [{ role: "user", content: statement.body }],
|
|
375
|
-
workerId: providerWorkerId,
|
|
376
|
-
primaryWorkerId,
|
|
377
|
-
signal,
|
|
378
|
-
attributions: attributions.length > 0 ? attributions : undefined,
|
|
379
|
-
workspaceId: String(workspaceId),
|
|
380
|
-
loop: loopSequence,
|
|
381
|
-
turn: turnSequence,
|
|
382
|
-
observeRequest: modelCall.observeRequest,
|
|
383
|
-
callKind: "bare",
|
|
384
|
-
});
|
|
385
|
-
modelCall.assertAccounting(generated.accounting);
|
|
386
|
-
recordCounter(PROVIDER_CALLS, {
|
|
387
|
-
model: provider.model,
|
|
388
|
-
attempt: 1,
|
|
389
|
-
status: "resolved",
|
|
390
|
-
});
|
|
391
|
-
span.setAttribute("status", "resolved");
|
|
392
|
-
settleGenAiResponse(span, generated);
|
|
393
|
-
return generated;
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
if (error instanceof ProviderError) {
|
|
397
|
-
modelCall.assertAccounting(error.accounting);
|
|
398
|
-
}
|
|
399
|
-
throw error;
|
|
400
|
-
}
|
|
401
|
-
}, genAiRequestOptions(ProviderInstantiate.aliasOf(provider) ?? "plurnk", provider.model));
|
|
402
|
-
await modelCall.observeResponse(response);
|
|
403
|
-
return {
|
|
404
|
-
statement,
|
|
405
|
-
modelCallId: modelCall.id,
|
|
406
|
-
result: Results.assert({
|
|
407
|
-
status: 200,
|
|
408
|
-
content: response.assistant.content,
|
|
409
|
-
mimetype: "text/plain",
|
|
410
|
-
}),
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
catch (error) {
|
|
414
|
-
if (error instanceof ModelCallPersistenceError || error instanceof ProviderAccountingIntegrityError) {
|
|
415
|
-
throw error;
|
|
416
|
-
}
|
|
417
|
-
const failure = _a.#providerFailure(error, signal);
|
|
418
|
-
if (error instanceof ProviderError && error.attempt !== undefined) {
|
|
419
|
-
await modelCall.observeResponse(error.attempt, failure);
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
await modelCall.fail(failure);
|
|
423
|
-
}
|
|
424
|
-
return { statement, modelCallId: modelCall.id, result: failure };
|
|
425
|
-
}
|
|
426
|
-
}));
|
|
427
|
-
const internalFailure = settlements.find((settlement) => settlement.status === "rejected");
|
|
428
|
-
if (internalFailure !== undefined)
|
|
429
|
-
throw internalFailure.reason;
|
|
430
|
-
signal?.throwIfAborted();
|
|
431
|
-
return settlements.map((settlement) => settlement.value);
|
|
432
|
-
}
|
|
433
|
-
// {§attribution} — reporting derives from exact provider-request evidence;
|
|
434
|
-
// malformed durable tags fail here instead of being silently filtered.
|
|
435
329
|
#offsetToLineColumn(content, offset) {
|
|
436
330
|
const cps = Array.from(content);
|
|
437
331
|
const clamped = Math.max(0, Math.min(offset, cps.length));
|
|
@@ -448,226 +342,22 @@ class TurnRunner {
|
|
|
448
342
|
}
|
|
449
343
|
return { line, column };
|
|
450
344
|
}
|
|
451
|
-
// {§
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (finalOp?.op !== "SEND") {
|
|
459
|
-
throw new Error("an admitted operation batch must end in a disposition SEND");
|
|
460
|
-
}
|
|
461
|
-
if (source !== null && plan?.op !== "PLAN") {
|
|
462
|
-
throw new Error("an admitted source-backed turnOps program must begin with PLAN");
|
|
463
|
-
}
|
|
464
|
-
const dispositionSignal = finalOp.signal;
|
|
465
|
-
if (typeof dispositionSignal !== "number" || !TERMINAL_SEND_SIGNALS.has(dispositionSignal)) {
|
|
466
|
-
throw new Error("an admitted turnOps program must end in a terminal disposition SEND");
|
|
467
|
-
}
|
|
468
|
-
let sendOp = finalOp;
|
|
469
|
-
let turnStatus = dispositionSignal;
|
|
470
|
-
let steerStruck = false;
|
|
471
|
-
const pendingEngineErrors = [];
|
|
472
|
-
const middleCount = statements.filter((statement) => statement.op !== "PLAN" && statement.op !== "SEND").length
|
|
473
|
-
+ recoverableParseErrors.length;
|
|
474
|
-
if (enforceIdle && turnStatus === TURN_STATUS_IMPLICIT_CONTINUE && middleCount === 0) {
|
|
475
|
-
// {§send-idle-turn} — an empty [102] while the worker holds a live stream or child is a
|
|
476
|
-
// mis-spelled wait, not idleness: it parks as [202] and no strike (#441). The correction
|
|
477
|
-
// rides the SEND row's annotation — a park drops transient notices, the row survives the
|
|
478
|
-
// wake. With nothing in flight the idle-turn 409 stands.
|
|
479
|
-
if (await this.#dispatcher.hasLiveWork(workerId)) {
|
|
480
|
-
const note = "empty [102] while a stream or child is in flight waits like [202] - say [202] to wait on it";
|
|
481
|
-
sendOp = { ...finalOp, signal: 202, annotation: finalOp.annotation === null ? note : `${finalOp.annotation} · ${note}` };
|
|
482
|
-
turnStatus = 202;
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
steerStruck = true;
|
|
486
|
-
pendingEngineErrors.push("idle_turn");
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
const turnStatements = sendOp === finalOp ? statements : statements.map((statement) => statement === finalOp ? sendOp : statement);
|
|
490
|
-
let realCommands = 0;
|
|
491
|
-
const admitted = turnStatements.filter((statement) => statement.op === "PLAN"
|
|
492
|
-
|| statement === sendOp
|
|
493
|
-
|| realCommands++ < maxCommands);
|
|
494
|
-
const scheduled = scheduleTurnOps(admitted.flatMap(expandSafeUriTargetGroup));
|
|
495
|
-
await this.#dispatcher.prepareEditBatches(scheduled.filter((statement) => statement.op === "EDIT"), { workspaceId, workerId, loopId, turnId, origin, onDispatch, onSettled });
|
|
496
|
-
const droppedCount = statements.length - admitted.length;
|
|
497
|
-
const bareStatements = scheduled.filter((statement) => statement.op === "BARE");
|
|
498
|
-
let bareResults = null;
|
|
499
|
-
const outcomes = [];
|
|
500
|
-
let rowSequence = fromSequence;
|
|
501
|
-
let parseErrorsRecorded = false;
|
|
502
|
-
const recordRecoverableParseErrors = async () => {
|
|
503
|
-
if (parseErrorsRecorded)
|
|
504
|
-
return;
|
|
505
|
-
parseErrorsRecorded = true;
|
|
506
|
-
for (const error of recoverableParseErrors) {
|
|
507
|
-
const envelopeDefault = error.message === PlurnkParser.MISSING_PLAN
|
|
508
|
-
|| error.message === PlurnkParser.MISSING_SEND;
|
|
509
|
-
const recorded = await this.#problems.record({
|
|
510
|
-
workerId,
|
|
511
|
-
loopId,
|
|
512
|
-
turnId,
|
|
513
|
-
sequence: rowSequence++,
|
|
514
|
-
origin,
|
|
515
|
-
source: "grammar",
|
|
516
|
-
result: Results.failure("grammar:parser", "invalid-operation-syntax", 400, error.message, {}, {
|
|
517
|
-
line: error.line,
|
|
518
|
-
column: error.column,
|
|
519
|
-
source: error.source,
|
|
520
|
-
stage: "parse",
|
|
521
|
-
...(envelopeDefault ? {} : { siblingsRetained: true }),
|
|
522
|
-
retryable: false,
|
|
523
|
-
}),
|
|
524
|
-
});
|
|
525
|
-
outcomes.push({ op: null, status: recorded.result.status, problemType: recorded.result.problem?.type ?? null });
|
|
526
|
-
onDispatch?.(recorded.id);
|
|
527
|
-
await onSettled?.(recorded.id);
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
for (const statement of scheduled) {
|
|
531
|
-
if (statement === sendOp) {
|
|
532
|
-
await recordRecoverableParseErrors();
|
|
533
|
-
const execHandler = this.#schemes.get("exec");
|
|
534
|
-
await execHandler?.settleTurnSpawns?.(workerId, turnId, readOptimisticSettlementMs(), signal);
|
|
535
|
-
}
|
|
536
|
-
const result = await observed("op.dispatch", { op: statement.op }, async (span) => {
|
|
537
|
-
let dispatchResult;
|
|
538
|
-
if (statement.op === "BARE") {
|
|
539
|
-
if (bare === undefined) {
|
|
540
|
-
throw new Error(`${origin} turnOps cannot execute BARE without provider acquisition context`);
|
|
541
|
-
}
|
|
542
|
-
if (bareResults === null) {
|
|
543
|
-
const batch = await this.#runBareBatch({
|
|
544
|
-
statements: bareStatements,
|
|
545
|
-
provider: bare.provider,
|
|
546
|
-
turnId,
|
|
547
|
-
workspaceId,
|
|
548
|
-
workerId,
|
|
549
|
-
primaryWorkerId: bare.primaryWorkerId,
|
|
550
|
-
loopSequence: bare.loopSequence,
|
|
551
|
-
turnSequence: bare.turnSequence,
|
|
552
|
-
signal: bare.signal,
|
|
553
|
-
});
|
|
554
|
-
bareResults = new Map(batch.map((item) => [item.statement, item]));
|
|
555
|
-
}
|
|
556
|
-
const bareResult = bareResults.get(statement);
|
|
557
|
-
if (bareResult === undefined) {
|
|
558
|
-
throw new Error("BARE statement reached dispatch without its batch result");
|
|
559
|
-
}
|
|
560
|
-
dispatchResult = await this.#dispatcher.recordBareResult({
|
|
561
|
-
statement,
|
|
562
|
-
workspaceId,
|
|
563
|
-
workerId,
|
|
564
|
-
loopId,
|
|
565
|
-
turnId,
|
|
566
|
-
sequence: rowSequence,
|
|
567
|
-
origin,
|
|
568
|
-
onDispatch,
|
|
569
|
-
onSettled,
|
|
570
|
-
}, bareResult.result, bareResult.modelCallId);
|
|
571
|
-
}
|
|
572
|
-
else {
|
|
573
|
-
dispatchResult = await this.#dispatcher.dispatch({
|
|
574
|
-
statement,
|
|
575
|
-
workspaceId,
|
|
576
|
-
workerId,
|
|
577
|
-
loopId,
|
|
578
|
-
turnId,
|
|
579
|
-
sequence: rowSequence,
|
|
580
|
-
origin,
|
|
581
|
-
onDispatch,
|
|
582
|
-
onSettled,
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
span.setAttribute("status", dispatchResult.status);
|
|
586
|
-
recordCounter(OPS_DISPATCHED, { op: statement.op, status: dispatchResult.status });
|
|
587
|
-
return dispatchResult;
|
|
588
|
-
});
|
|
589
|
-
outcomes.push({ op: statement.op, status: result.status, problemType: result.problem?.type ?? null });
|
|
590
|
-
if (failOnOperationError && result.status >= 400)
|
|
591
|
-
throw new OperationFailureError(result);
|
|
592
|
-
for (const normalization of result.scopeNormalizations ?? []) {
|
|
593
|
-
this.#notices.push(workspaceId, workerId, loopId, {
|
|
594
|
-
source: "engine:slicer",
|
|
595
|
-
kind: "scope_normalized",
|
|
596
|
-
level: "warn",
|
|
597
|
-
message: `Scope <${normalization.requested.join(",")}> was normalized to <${normalization.canonical.join(",")}>.`,
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
// {§edit-batch-merges} — every applied resolution is also a notice, so the row's
|
|
601
|
-
// `merged` fact is never the only place it is said.
|
|
602
|
-
for (const merge of result.merged ?? []) {
|
|
603
|
-
this.#notices.push(workspaceId, workerId, loopId, {
|
|
604
|
-
source: "engine:slicer",
|
|
605
|
-
kind: "edit_merged",
|
|
606
|
-
level: "warn",
|
|
607
|
-
message: `EDIT resolution applied: ${merge.rule} - the row's merged fact has the coordinates; verify before building on it.`,
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
if (statement === sendOp && result.status === 409) {
|
|
611
|
-
steerStruck = true;
|
|
612
|
-
turnStatus = TURN_STATUS_IMPLICIT_CONTINUE;
|
|
613
|
-
}
|
|
614
|
-
if (statement === sendOp
|
|
615
|
-
&& result.status !== 409
|
|
616
|
-
&& sendOp.target === null
|
|
617
|
-
&& sendOp.signal === 202
|
|
618
|
-
&& result.status !== 202) {
|
|
619
|
-
turnStatus = result.status;
|
|
620
|
-
}
|
|
621
|
-
rowSequence += result.rowsWritten ?? 1;
|
|
622
|
-
}
|
|
623
|
-
await recordRecoverableParseErrors();
|
|
624
|
-
if (droppedCount > 0)
|
|
625
|
-
pendingEngineErrors.push("max_commands_exceeded");
|
|
626
|
-
for (const kind of pendingEngineErrors) {
|
|
627
|
-
const problem = ENGINE_PROBLEMS[kind];
|
|
628
|
-
const extensions = kind === "max_commands_exceeded"
|
|
629
|
-
? {
|
|
630
|
-
operationLimit: maxCommands,
|
|
631
|
-
omittedOperations: droppedCount,
|
|
632
|
-
stage: "dispatch-admission",
|
|
633
|
-
recovery: "Continue with no more than the configured operation limit.",
|
|
634
|
-
retryable: false,
|
|
635
|
-
}
|
|
636
|
-
: {
|
|
637
|
-
stage: "turn",
|
|
638
|
-
recovery: "Perform an operation before continuing with `## SEND0 [102]`.",
|
|
639
|
-
retryable: false,
|
|
640
|
-
};
|
|
641
|
-
await this.#problems.record({
|
|
642
|
-
workerId,
|
|
643
|
-
loopId,
|
|
644
|
-
turnId,
|
|
645
|
-
sequence: rowSequence++,
|
|
646
|
-
origin: "_plurnk",
|
|
647
|
-
source: "rail",
|
|
648
|
-
result: Results.failure("engine:rail", problem.code, problem.status, problem.detail, {}, extensions),
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
if (source !== null) {
|
|
652
|
-
await this.#dispatcher.writeTurnOps({
|
|
653
|
-
verbatim: source,
|
|
654
|
-
workerId,
|
|
655
|
-
loopId,
|
|
656
|
-
turnId,
|
|
657
|
-
sequence: rowSequence,
|
|
658
|
-
origin,
|
|
659
|
-
folded: sourceFolded,
|
|
660
|
-
modelCallId: sourceModelCallId,
|
|
661
|
-
...(sourceReasoningItems !== undefined ? { reasoningItems: sourceReasoningItems } : {}),
|
|
662
|
-
});
|
|
345
|
+
// {§packet-attachment-parts} — a route receives, as native parts read from the scheme's bytes at
|
|
346
|
+
// request time, the packet's attachments of every kind its model accepts; every other attachment
|
|
347
|
+
// reaches it as the text projection alone.
|
|
348
|
+
async #wireMessages(packet, workspaceId, provider) {
|
|
349
|
+
const accepted = acceptedKinds(provider.inputModalities);
|
|
350
|
+
if (accepted.length === 0 || !(packet.attachments ?? []).some((attachment) => accepted.includes(attachment.kind))) {
|
|
351
|
+
return PacketWire.packetToWireMessages(packet);
|
|
663
352
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
353
|
+
return PacketWire.wireMessages(packet, async (attachment) => {
|
|
354
|
+
const handler = this.#schemes.get(attachment.scheme);
|
|
355
|
+
const source = handler?.byteSource?.(attachment.pathname, { db: this.#db, workspaceId });
|
|
356
|
+
if (source === undefined)
|
|
357
|
+
return null;
|
|
358
|
+
const total = await source.size();
|
|
359
|
+
return total === null || total === 0 ? null : source.read(1, total);
|
|
360
|
+
}, (kind) => accepted.includes(kind));
|
|
671
361
|
}
|
|
672
362
|
async runTurn({ provider, childProvider = provider, messages, recap = "", workspaceId, workerId, loopId, signal, onDispatch, onSettled, turnNumber = 1, maxTurns = 50, invalidEmissionRecoveryEntryId, }) {
|
|
673
363
|
const transientOpenLogEntryId = typeof invalidEmissionRecoveryEntryId === "number"
|
|
@@ -764,10 +454,10 @@ class TurnRunner {
|
|
|
764
454
|
if (initializationTurn !== null) {
|
|
765
455
|
const plan = {
|
|
766
456
|
op: "PLAN", delimiter: "", annotation: null,
|
|
767
|
-
|
|
457
|
+
target: null, metadata: null, lineMarker: null,
|
|
768
458
|
body: [
|
|
769
459
|
{
|
|
770
|
-
content: "
|
|
460
|
+
content: "Determinations and Decisions must be persisted as `memory` items.",
|
|
771
461
|
status: "memory",
|
|
772
462
|
},
|
|
773
463
|
{
|
|
@@ -785,7 +475,7 @@ class TurnRunner {
|
|
|
785
475
|
// ({§op-mode-phases}: Mutate precedes Observe).
|
|
786
476
|
if (promptPublication !== null) {
|
|
787
477
|
const archive = {
|
|
788
|
-
op: "COPY", delimiter: "", annotation: null,
|
|
478
|
+
op: "COPY", delimiter: "", annotation: null,
|
|
789
479
|
source: { target: promptPublication.path, metadata: null, lineMarker: null },
|
|
790
480
|
destination: {
|
|
791
481
|
target: { kind: "url", raw: "worker://~/prompts.md", scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: "/prompts.md", query: null, fragment: null },
|
|
@@ -815,7 +505,7 @@ class TurnRunner {
|
|
|
815
505
|
pathname: generatedPathname("/agents.md"), query: null, fragment: null,
|
|
816
506
|
};
|
|
817
507
|
const agentsRead = {
|
|
818
|
-
op: "READ", delimiter: "", annotation: null,
|
|
508
|
+
op: "READ", delimiter: "", annotation: null, target: agentsTarget,
|
|
819
509
|
metadata: null, lineMarker: null, body: null, position: UNKNOWN_POSITION,
|
|
820
510
|
};
|
|
821
511
|
initializationStatements.push(agentsRead);
|
|
@@ -846,7 +536,7 @@ class TurnRunner {
|
|
|
846
536
|
// {§packet-git-status} — one post-reconciliation snapshot supplies both
|
|
847
537
|
// the compact packet summary and each causal file event's exact XY state.
|
|
848
538
|
const gitStatus = await GitState.status(this.#db, workspaceId, this.#loopSignal(loopId));
|
|
849
|
-
await this.#logFsFictions(workspaceId, fsDivergences, gitStatus);
|
|
539
|
+
await this.#materialization.logFsFictions(workspaceId, fsDivergences, gitStatus);
|
|
850
540
|
// The refresh above may have changed bodies (including model/client edits
|
|
851
541
|
// since the startup warm). Re-derive to completion before packet/model
|
|
852
542
|
// construction. Membership is already current, so this pass does not
|
|
@@ -867,7 +557,7 @@ class TurnRunner {
|
|
|
867
557
|
const fileCap = filesItems > 0 && fileItems > 0 ? Math.min(filesItems, fileItems) : null;
|
|
868
558
|
// {§tools-resource-materialization} — a PLURNK_MCP_EXPANDED server
|
|
869
559
|
// contributes one FIND over its family document matching the
|
|
870
|
-
//
|
|
560
|
+
// `### EXEC0` headings: one row per tool — heading, annotation,
|
|
871
561
|
// signature — paged like every survey. No document is delivered
|
|
872
562
|
// unasked; per-target child documents do not exist.
|
|
873
563
|
const registry = this.#executors();
|
|
@@ -911,13 +601,13 @@ class TurnRunner {
|
|
|
911
601
|
if (admittedTools.length === 0)
|
|
912
602
|
continue;
|
|
913
603
|
const pattern = tools !== null && tools !== undefined && admittedTools.length !== tools.tools.length
|
|
914
|
-
?
|
|
604
|
+
? `^### EXEC0 \\[${regexLiteral(tag)}\\] \\((?:${admittedTools
|
|
915
605
|
.map((tool) => regexLiteral(PathSyntax.escapeTarget(tool.target)))
|
|
916
606
|
.join("|")})\\).*\\n.*$`
|
|
917
|
-
: "
|
|
607
|
+
: "^### EXEC0 .*\\n.*$";
|
|
918
608
|
toolExpansions.push({
|
|
919
609
|
statement: {
|
|
920
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
610
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
921
611
|
target: { kind: "url", raw: `worker://~/_plurnk/tools/${tag}.md`, scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: generatedPathname(`/tools/${tag}.md`), query: null, fragment: null },
|
|
922
612
|
metadata: null,
|
|
923
613
|
body: { dialect: "regex", raw: `/${pattern.replaceAll("/", "\\/")}/m`, pattern, flags: "m" },
|
|
@@ -928,7 +618,7 @@ class TurnRunner {
|
|
|
928
618
|
const surveys = [
|
|
929
619
|
{
|
|
930
620
|
statement: {
|
|
931
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
621
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
932
622
|
target: { kind: "url", raw: "worker://~/_plurnk/skills/*.md", scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: generatedPathname("/skills/*.md"), query: null, fragment: null },
|
|
933
623
|
metadata: null,
|
|
934
624
|
body: null, lineMarker: { marks: [1, -1] }, position: UNKNOWN_POSITION,
|
|
@@ -936,7 +626,7 @@ class TurnRunner {
|
|
|
936
626
|
},
|
|
937
627
|
...(plurnkCatalog === null ? [] : [{
|
|
938
628
|
statement: {
|
|
939
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
629
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
940
630
|
target: plurnkCatalog,
|
|
941
631
|
metadata: null,
|
|
942
632
|
body: null, lineMarker: { marks: [1, -1] }, position: UNKNOWN_POSITION,
|
|
@@ -950,7 +640,7 @@ class TurnRunner {
|
|
|
950
640
|
// PLURNK_MCP_EXPANDED add a second survey of their complete
|
|
951
641
|
// tool tree.
|
|
952
642
|
statement: {
|
|
953
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
643
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
954
644
|
target: toolsCatalog,
|
|
955
645
|
metadata: null,
|
|
956
646
|
body: null, lineMarker: { marks: [1, -1] }, position: UNKNOWN_POSITION,
|
|
@@ -962,7 +652,7 @@ class TurnRunner {
|
|
|
962
652
|
// alias level; each row's summary is the agent's identity line,
|
|
963
653
|
// the exact card stays pullable through READ a2a://<alias>.
|
|
964
654
|
statement: {
|
|
965
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
655
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
966
656
|
target: { kind: "url", raw: "worker://~/_plurnk/agents/*.md", scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: generatedPathname("/agents/*.md"), query: null, fragment: null },
|
|
967
657
|
metadata: null,
|
|
968
658
|
body: null, lineMarker: { marks: [1, -1] }, position: UNKNOWN_POSITION,
|
|
@@ -972,7 +662,7 @@ class TurnRunner {
|
|
|
972
662
|
// {§members-projection} — enabled members definitions survey at alias
|
|
973
663
|
// level; each row's summary is what its glob resolved to.
|
|
974
664
|
statement: {
|
|
975
|
-
op: "FIND", delimiter: "", annotation: null,
|
|
665
|
+
op: "FIND", delimiter: "", annotation: null,
|
|
976
666
|
target: { kind: "url", raw: "worker://~/_plurnk/members/*.md", scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: generatedPathname("/members/*.md"), query: null, fragment: null },
|
|
977
667
|
metadata: null,
|
|
978
668
|
body: null, lineMarker: { marks: [1, -1] }, position: UNKNOWN_POSITION,
|
|
@@ -980,7 +670,7 @@ class TurnRunner {
|
|
|
980
670
|
},
|
|
981
671
|
{
|
|
982
672
|
statement: {
|
|
983
|
-
op: "FIND", delimiter: "", annotation: "workspace files",
|
|
673
|
+
op: "FIND", delimiter: "", annotation: "workspace files",
|
|
984
674
|
target: { kind: "local", raw: "*" },
|
|
985
675
|
metadata: null,
|
|
986
676
|
body: null,
|
|
@@ -990,7 +680,7 @@ class TurnRunner {
|
|
|
990
680
|
},
|
|
991
681
|
{
|
|
992
682
|
statement: {
|
|
993
|
-
op: "FIND", delimiter: "", annotation: "workspace entries",
|
|
683
|
+
op: "FIND", delimiter: "", annotation: "workspace entries",
|
|
994
684
|
target: { kind: "url", raw: "worker:///*", scheme: "worker", username: null, password: null, hostname: null, port: null, pathname: "/*", query: null, fragment: null },
|
|
995
685
|
metadata: null,
|
|
996
686
|
body: null, lineMarker: null, position: UNKNOWN_POSITION,
|
|
@@ -998,7 +688,7 @@ class TurnRunner {
|
|
|
998
688
|
},
|
|
999
689
|
{
|
|
1000
690
|
statement: {
|
|
1001
|
-
op: "FIND", delimiter: "", annotation: "private worker entries",
|
|
691
|
+
op: "FIND", delimiter: "", annotation: "private worker entries",
|
|
1002
692
|
target: { kind: "url", raw: "worker://~/*", scheme: "worker", username: null, password: null, hostname: "~", port: null, pathname: "/*", query: null, fragment: null },
|
|
1003
693
|
metadata: null,
|
|
1004
694
|
body: null, lineMarker: null, position: UNKNOWN_POSITION,
|
|
@@ -1009,7 +699,7 @@ class TurnRunner {
|
|
|
1009
699
|
}
|
|
1010
700
|
const send = {
|
|
1011
701
|
op: "SEND", delimiter: "", annotation: null,
|
|
1012
|
-
|
|
702
|
+
status: 102, target: null, metadata: null, lineMarker: null,
|
|
1013
703
|
body: { raw: "Next: Address the prompt.", json: null },
|
|
1014
704
|
position: UNKNOWN_POSITION,
|
|
1015
705
|
};
|
|
@@ -1053,7 +743,7 @@ class TurnRunner {
|
|
|
1053
743
|
const turnOpenPaths = [];
|
|
1054
744
|
if (promptPublication !== null) { // {§prompt-entry} — one durable publication per loop
|
|
1055
745
|
turnOpenPaths.push(...promptPublication.openPaths);
|
|
1056
|
-
const promptLogId = await this.#writePromptLog({
|
|
746
|
+
const promptLogId = await this.#materialization.writePromptLog({
|
|
1057
747
|
workerId,
|
|
1058
748
|
loopId,
|
|
1059
749
|
turnId,
|
|
@@ -1084,7 +774,7 @@ class TurnRunner {
|
|
|
1084
774
|
turnOpenPaths.push(...assertOpenPaths(attributes.openPaths, `Prompt ${injectedRow.pathname} openPaths`));
|
|
1085
775
|
}
|
|
1086
776
|
const ordinal = Number(injectedRow.pathname.split("/").filter(Boolean).at(-1));
|
|
1087
|
-
const promptLogId = await this.#writePromptLog({
|
|
777
|
+
const promptLogId = await this.#materialization.writePromptLog({
|
|
1088
778
|
workerId,
|
|
1089
779
|
loopId,
|
|
1090
780
|
turnId,
|
|
@@ -1103,7 +793,7 @@ class TurnRunner {
|
|
|
1103
793
|
for (const raw of turnOpenPaths) {
|
|
1104
794
|
const pathname = raw.startsWith("/") ? raw : `/${raw}`;
|
|
1105
795
|
const fileRead = {
|
|
1106
|
-
op: "READ", delimiter: "", annotation: null,
|
|
796
|
+
op: "READ", delimiter: "", annotation: null, lineMarker: null,
|
|
1107
797
|
target: {
|
|
1108
798
|
kind: "url", raw: `file://${pathname}`, scheme: "file",
|
|
1109
799
|
username: null, password: null, hostname: null, port: null,
|
|
@@ -1125,8 +815,8 @@ class TurnRunner {
|
|
|
1125
815
|
// from a prior turn — this runs before the turn's own spawns) so a `<0>` never survives into
|
|
1126
816
|
// the subsequent turn. The terminal output then surfaces born-OPEN via the stream-delta path.
|
|
1127
817
|
await this.#reapTurnScopedStreams(workerId);
|
|
1128
|
-
nextActionIndex += await this.#materializeEnvironmentDeltas({ workspaceId, workerId, loopId, turnId, fromSequence: nextActionIndex });
|
|
1129
|
-
nextActionIndex += await this.#materializeStreamDeltas({ workerId, loopId, turnId, fromSequence: nextActionIndex });
|
|
818
|
+
nextActionIndex += await this.#materialization.materializeEnvironmentDeltas({ workspaceId, workerId, loopId, turnId, fromSequence: nextActionIndex });
|
|
819
|
+
nextActionIndex += await this.#materialization.materializeStreamDeltas({ workerId, loopId, turnId, fromSequence: nextActionIndex });
|
|
1130
820
|
// The post-reconciliation Git snapshot above is threaded into the packet
|
|
1131
821
|
// and every budget rebuild; overflow never shells again.
|
|
1132
822
|
// Notices are non-terminal observations, never operation-failure truth.
|
|
@@ -1205,7 +895,7 @@ class TurnRunner {
|
|
|
1205
895
|
...(curationFailure === undefined ? {} : { curationFailure }),
|
|
1206
896
|
};
|
|
1207
897
|
}
|
|
1208
|
-
let modelMessages =
|
|
898
|
+
let modelMessages = await this.#wireMessages(requestPacket, workspaceId, provider);
|
|
1209
899
|
// Curation pressure and provider generation are independent. The
|
|
1210
900
|
// provider owns its configured total output envelope.
|
|
1211
901
|
let response;
|
|
@@ -1250,7 +940,7 @@ class TurnRunner {
|
|
|
1250
940
|
if (promptProjection === "automatic") {
|
|
1251
941
|
promptProjection = "withheld";
|
|
1252
942
|
const candidate = await buildPacket();
|
|
1253
|
-
const candidateMessages =
|
|
943
|
+
const candidateMessages = await this.#wireMessages(candidate, workspaceId, provider);
|
|
1254
944
|
if (JSON.stringify(candidateMessages) !== JSON.stringify(baselineMessages)) {
|
|
1255
945
|
requestPacket = candidate;
|
|
1256
946
|
modelMessages = candidateMessages;
|
|
@@ -1412,7 +1102,7 @@ class TurnRunner {
|
|
|
1412
1102
|
throw error;
|
|
1413
1103
|
}
|
|
1414
1104
|
recoveryFailures += 1;
|
|
1415
|
-
const failure =
|
|
1105
|
+
const failure = TurnRunner.#providerFailure(error, providerSignal);
|
|
1416
1106
|
if (error.attempt !== undefined) {
|
|
1417
1107
|
// {§provider-interrupted-attempt} — the interrupted response stays durable
|
|
1418
1108
|
// as an unaccepted attempt; it is never admitted or replayed.
|
|
@@ -1452,7 +1142,7 @@ class TurnRunner {
|
|
|
1452
1142
|
|| !await recoverCapacityPacket()) {
|
|
1453
1143
|
throw error;
|
|
1454
1144
|
}
|
|
1455
|
-
const failure =
|
|
1145
|
+
const failure = TurnRunner.#providerFailure(error, providerSignal);
|
|
1456
1146
|
await currentModelCall.fail(failure, error.capacity ?? null);
|
|
1457
1147
|
providerCallInFlight = false;
|
|
1458
1148
|
await this.#problems.record({
|
|
@@ -1467,7 +1157,7 @@ class TurnRunner {
|
|
|
1467
1157
|
// Include the durable recovery signal in the replacement
|
|
1468
1158
|
// request while preserving the selected recovery posture.
|
|
1469
1159
|
requestPacket = await buildPacket();
|
|
1470
|
-
modelMessages =
|
|
1160
|
+
modelMessages = await this.#wireMessages(requestPacket, workspaceId, provider);
|
|
1471
1161
|
continue;
|
|
1472
1162
|
}
|
|
1473
1163
|
finally {
|
|
@@ -1488,7 +1178,7 @@ class TurnRunner {
|
|
|
1488
1178
|
await currentModelCall.observeResponse(completedResponse);
|
|
1489
1179
|
railEvidence = railGrammar === undefined
|
|
1490
1180
|
? undefined
|
|
1491
|
-
:
|
|
1181
|
+
: TurnRunner.#requireGrammarEvidence(completedResponse, railAllowWithheld);
|
|
1492
1182
|
splitResponse = this.#splitResponse(completedResponse);
|
|
1493
1183
|
await classifyProviderAttempt(attemptRow.id, splitResponse, attempt, splitResponse.emissionValid);
|
|
1494
1184
|
if (splitResponse.emissionValid)
|
|
@@ -1526,7 +1216,7 @@ class TurnRunner {
|
|
|
1526
1216
|
if (providerAttemptId === null || providerModelCall === null) {
|
|
1527
1217
|
throw new Error("provider call failed without durable model-call and attempt identities", { cause: err });
|
|
1528
1218
|
}
|
|
1529
|
-
const failure =
|
|
1219
|
+
const failure = TurnRunner.#providerFailure(err, providerSignal);
|
|
1530
1220
|
const capacityFailure = err instanceof ProviderError && err.kind === "capacity_exceeded";
|
|
1531
1221
|
// {§provider-interrupted-attempt} — a provider-declared interruption
|
|
1532
1222
|
// carries response evidence without becoming a completed exchange.
|
|
@@ -1773,7 +1463,7 @@ class TurnRunner {
|
|
|
1773
1463
|
verdict = validateGbnf(railResponseGrammar, railEvidence.input);
|
|
1774
1464
|
}
|
|
1775
1465
|
catch (cause) {
|
|
1776
|
-
|
|
1466
|
+
TurnRunner.#warnRailVerdictGapOnce(cause.message);
|
|
1777
1467
|
}
|
|
1778
1468
|
railKeys = {
|
|
1779
1469
|
railsAttached: railEvidence.transported ? "client" : "withheld",
|
|
@@ -1957,21 +1647,20 @@ class TurnRunner {
|
|
|
1957
1647
|
const plan = ops[0]?.op === "PLAN" ? ops[0] : undefined;
|
|
1958
1648
|
const finalOp = ops.at(-1);
|
|
1959
1649
|
const terminalSend = finalOp?.op === "SEND"
|
|
1960
|
-
&&
|
|
1961
|
-
&& TERMINAL_SEND_SIGNALS.has(finalOp.
|
|
1650
|
+
&& finalOp.status !== null
|
|
1651
|
+
&& TERMINAL_SEND_SIGNALS.has(finalOp.status)
|
|
1962
1652
|
? finalOp
|
|
1963
1653
|
: undefined;
|
|
1964
|
-
const recoveredPlan = plan?.position.line === 0;
|
|
1965
1654
|
const recoveredSend = terminalSend?.position.line === 0;
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1655
|
+
// {§turn-shape} — PLAN is a SHOULD: a turn without one is complete once it ends in a
|
|
1656
|
+
// terminal SEND, and the recoverable window then starts at the turn's first statement.
|
|
1657
|
+
const recoverableParseErrors = terminalSend !== undefined && !hasUnparsedTail
|
|
1658
|
+
? parseErrors.filter((error) => (error.message === PlurnkParser.MISSING_SEND
|
|
1659
|
+
|| ((plan === undefined || comparePosition(error, plan.position) > 0)
|
|
1970
1660
|
&& (recoveredSend || comparePosition(error, terminalSend.position) < 0)))).toSorted(comparePosition)
|
|
1971
1661
|
: [];
|
|
1972
1662
|
const emissionValid = preParsedOps !== undefined
|
|
1973
|
-
|| (
|
|
1974
|
-
&& terminalSend !== undefined
|
|
1663
|
+
|| (terminalSend !== undefined
|
|
1975
1664
|
&& sourceStatementCount > 0
|
|
1976
1665
|
&& !hasUnparsedTail
|
|
1977
1666
|
&& recoverableParseErrors.length === parseErrors.length);
|
|
@@ -1984,7 +1673,7 @@ class TurnRunner {
|
|
|
1984
1673
|
recoverableParseErrors: emissionValid ? recoverableParseErrors : [],
|
|
1985
1674
|
parseNotices,
|
|
1986
1675
|
// The ANTLR model-turn parser is authoritative. At least one source
|
|
1987
|
-
// operation lets omitted
|
|
1676
|
+
// operation lets an omitted terminal SEND default around it; the
|
|
1988
1677
|
// exact defaults and bounded statement failures become durable
|
|
1989
1678
|
// operation results. Boundary loss and an unparsed tail still reject
|
|
1990
1679
|
// wholesale. Pre-parsed ops are Mock's trusted test seam.
|
|
@@ -1993,102 +1682,6 @@ class TurnRunner {
|
|
|
1993
1682
|
}
|
|
1994
1683
|
// #note12 — plugin reference docs are materialized beneath
|
|
1995
1684
|
// worker://~/_plurnk/plurnk/ by LoopDocs.
|
|
1996
|
-
async #materializeEnvironmentDeltas(args) {
|
|
1997
|
-
const { workspaceId, workerId, loopId, turnId, fromSequence } = args;
|
|
1998
|
-
const rows = await this.#db.engine_pull_ambient_events.all({ workspace_id: workspaceId, worker_id: workerId });
|
|
1999
|
-
const window = rows[0];
|
|
2000
|
-
if (window === undefined)
|
|
2001
|
-
throw new Error(`ambient pull: worker ${workerId} has no observation window`);
|
|
2002
|
-
let written = 0;
|
|
2003
|
-
for (const r of rows) {
|
|
2004
|
-
if (r.event_id === null || r.producer_worker_id === null || r.producer_worker_name === null || r.kind === null
|
|
2005
|
-
|| r.at === null || r.op === null || r.delimiter === null || r.tx === null || r.mimetype_tx === null
|
|
2006
|
-
|| r.rx === null || r.mimetype_rx === null || r.status_rx === null || r.state === null)
|
|
2007
|
-
continue;
|
|
2008
|
-
const termination = r.kind === "loop_termination";
|
|
2009
|
-
const terminal = termination
|
|
2010
|
-
? TerminalResult.parse(r.rx, `ambient loop-termination event ${r.event_id}`)
|
|
2011
|
-
: null;
|
|
2012
|
-
if (terminal !== null && terminal.status !== r.status_rx) {
|
|
2013
|
-
throw new Error(`ambient loop-termination event ${r.event_id} status ${r.status_rx} does not match its terminal result status ${terminal.status}`);
|
|
2014
|
-
}
|
|
2015
|
-
let attrs = r.attrs ?? "{}";
|
|
2016
|
-
const parsedTags = JSON.parse(r.tags ?? "[]");
|
|
2017
|
-
if (!Array.isArray(parsedTags) || !parsedTags.every((tag) => typeof tag === "string" && tag.length > 0)) {
|
|
2018
|
-
throw new TypeError(`ambient event ${r.event_id} tags must be an array of nonempty strings`);
|
|
2019
|
-
}
|
|
2020
|
-
const tags = [...new Set(parsedTags)].toSorted();
|
|
2021
|
-
if (tags.length !== parsedTags.length || tags.some((tag, index) => tag !== parsedTags[index])) {
|
|
2022
|
-
throw new TypeError(`ambient event ${r.event_id} tags must be unique and sorted`);
|
|
2023
|
-
}
|
|
2024
|
-
if (terminal !== null) {
|
|
2025
|
-
const inherited = JSON.parse(attrs);
|
|
2026
|
-
if (inherited === null || typeof inherited !== "object" || Array.isArray(inherited)) {
|
|
2027
|
-
throw new TypeError(`ambient loop-termination event ${r.event_id} attrs must be an object`);
|
|
2028
|
-
}
|
|
2029
|
-
attrs = JSON.stringify({
|
|
2030
|
-
...inherited,
|
|
2031
|
-
kind: "loop_termination",
|
|
2032
|
-
...(r.terminated_by === null ? {} : { terminatedBy: r.terminated_by }),
|
|
2033
|
-
});
|
|
2034
|
-
}
|
|
2035
|
-
const inserted = await this.#db.engine_insert_ambient_delta.get({
|
|
2036
|
-
worker_id: workerId, loop_id: loopId, turn_id: turnId, sequence: fromSequence + written,
|
|
2037
|
-
at: r.at,
|
|
2038
|
-
event_id: r.event_id,
|
|
2039
|
-
source: WorkerControlAddress.render(r.producer_worker_name),
|
|
2040
|
-
op: r.op,
|
|
2041
|
-
delimiter: r.delimiter,
|
|
2042
|
-
signal: r.signal,
|
|
2043
|
-
scheme: r.scheme,
|
|
2044
|
-
username: r.username,
|
|
2045
|
-
password: r.password,
|
|
2046
|
-
hostname: r.hostname,
|
|
2047
|
-
port: r.port,
|
|
2048
|
-
pathname: r.pathname,
|
|
2049
|
-
query: r.query,
|
|
2050
|
-
fragment: r.fragment,
|
|
2051
|
-
line_marker: r.line_marker,
|
|
2052
|
-
tx: r.tx,
|
|
2053
|
-
mimetype_tx: r.mimetype_tx,
|
|
2054
|
-
rx: r.rx,
|
|
2055
|
-
mimetype_rx: r.mimetype_rx,
|
|
2056
|
-
status: r.status_rx,
|
|
2057
|
-
weight: LogBody.weight({
|
|
2058
|
-
op: r.op,
|
|
2059
|
-
attrs,
|
|
2060
|
-
tx: r.tx,
|
|
2061
|
-
rx: r.rx,
|
|
2062
|
-
mimetypeTx: r.mimetype_tx,
|
|
2063
|
-
mimetypeRx: r.mimetype_rx,
|
|
2064
|
-
}, this.#weighContent),
|
|
2065
|
-
state: r.state,
|
|
2066
|
-
outcome: r.outcome,
|
|
2067
|
-
folded: LogVisibility.serialize(terminal !== null && terminal.status >= 200 && terminal.status < 300
|
|
2068
|
-
? LogVisibility.OPEN
|
|
2069
|
-
: LogVisibility.FOLDED),
|
|
2070
|
-
attrs,
|
|
2071
|
-
});
|
|
2072
|
-
const materialized = inserted ?? await this.#db.engine_ambient_delta_id.get({
|
|
2073
|
-
worker_id: workerId,
|
|
2074
|
-
event_id: r.event_id,
|
|
2075
|
-
});
|
|
2076
|
-
if (materialized === undefined)
|
|
2077
|
-
throw new Error(`ambient event ${r.event_id} has no observer log row after materialization`);
|
|
2078
|
-
for (const tag of tags) {
|
|
2079
|
-
await this.#db.log_write_tag.run({ log_entry_id: materialized.id, tag });
|
|
2080
|
-
}
|
|
2081
|
-
if (inserted !== undefined)
|
|
2082
|
-
written++;
|
|
2083
|
-
}
|
|
2084
|
-
await this.#db.engine_advance_ambient_cursor.get({
|
|
2085
|
-
workspace_id: workspaceId,
|
|
2086
|
-
worker_id: workerId,
|
|
2087
|
-
cursor: window.cursor,
|
|
2088
|
-
boundary: window.boundary,
|
|
2089
|
-
});
|
|
2090
|
-
return written;
|
|
2091
|
-
}
|
|
2092
1685
|
// {§exec-poll} — EXEC `<0>` is turn-scoped: abort the worker's open turn-scoped streams via their
|
|
2093
1686
|
// owning scheme (the same registry-routed abort the total reap uses). Called at each pre-turn
|
|
2094
1687
|
// before the turn's own spawns, so every open turn-scoped sub here is from a prior turn — it
|
|
@@ -2098,195 +1691,8 @@ class TurnRunner {
|
|
|
2098
1691
|
const open = await this.#db.find_open_turn_scoped_subscriptions_for_worker.all({ worker_id: workerId });
|
|
2099
1692
|
await Promise.all(open.map(({ id }) => this.#liveSubscriptions.cancel(id)));
|
|
2100
1693
|
}
|
|
2101
|
-
async
|
|
2102
|
-
|
|
2103
|
-
const channels = await this.#db.engine_worker_stream_channels.all({ worker_id: workerId });
|
|
2104
|
-
let written = 0;
|
|
2105
|
-
for (const ch of channels) {
|
|
2106
|
-
// Default channels are an implementation detail. Preserve the
|
|
2107
|
-
// channel internally on the entry/subscription, but present the
|
|
2108
|
-
// ordinary address to the model; only an explicitly non-default
|
|
2109
|
-
// channel earns a fragment in the log.
|
|
2110
|
-
const visibleFragment = ch.published_channel !== null
|
|
2111
|
-
&& ch.channel === this.#schemes.defaultChannelFor(ch.runtime, workerId)
|
|
2112
|
-
? null
|
|
2113
|
-
: ch.channel;
|
|
2114
|
-
const targetParts = authorityParts(ch.authority);
|
|
2115
|
-
// {§exec-stream} — nothing publishes while a stream is active: the Child Streams
|
|
2116
|
-
// section reports its size and growth ({§child-orientation}); the model READs any
|
|
2117
|
-
// range it wants. At close, ONE foisted READ that is exactly a markerless READ —
|
|
2118
|
-
// the first page, the extent, the terminal status and Problem — born OPEN. {§exec-stream-page}
|
|
2119
|
-
if (ch.state !== "closed" && ch.state !== "errored")
|
|
2120
|
-
continue;
|
|
2121
|
-
const terminal = Results.assert(JSON.parse(ch.producer_result ?? "null"));
|
|
2122
|
-
const sequence = fromSequence + written;
|
|
2123
|
-
const source = this.#schemes.isRuntimeScheme(ch.runtime, workerId)
|
|
2124
|
-
&& /^\/[1-9]\d*\/[1-9]\d*\/[1-9]\d*$/.test(ch.coord)
|
|
2125
|
-
? `log://${ch.coord}/EXEC`
|
|
2126
|
-
: null;
|
|
2127
|
-
const page = await ReadResolve.resolve({ content: ch.content, mimetype: ch.mimetype, lineMarker: null });
|
|
2128
|
-
const result = Results.assert({
|
|
2129
|
-
...terminal,
|
|
2130
|
-
...(terminal.problem === undefined ? {} : { problem: { ...terminal.problem } }),
|
|
2131
|
-
content: page.content ?? "",
|
|
2132
|
-
mimetype: page.mimetype,
|
|
2133
|
-
...(page.startLine === undefined || page.startLine === null ? {} : { startLine: page.startLine }),
|
|
2134
|
-
...(page.range === undefined ? {} : { range: page.range }),
|
|
2135
|
-
});
|
|
2136
|
-
if (result.problem !== undefined) {
|
|
2137
|
-
const seqs = await this.#db.engine_loop_turn_seqs.get({
|
|
2138
|
-
loop_id: loopId,
|
|
2139
|
-
turn_id: turnId,
|
|
2140
|
-
});
|
|
2141
|
-
if (seqs === undefined)
|
|
2142
|
-
throw new Error(`stream delta has no log coordinate for loop=${loopId} turn=${turnId}`);
|
|
2143
|
-
Results.attachInstance(result, `log:///${seqs.loop_seq}/${seqs.turn_seq}/${sequence}/READ`);
|
|
2144
|
-
}
|
|
2145
|
-
const rx = JSON.stringify(result);
|
|
2146
|
-
await this.#db.engine_insert_stream_delta.run({
|
|
2147
|
-
worker_id: workerId, loop_id: loopId, turn_id: turnId, sequence,
|
|
2148
|
-
subscription_publication_id: ch.publication_id,
|
|
2149
|
-
source,
|
|
2150
|
-
scheme: ch.runtime, hostname: targetParts.hostname, port: targetParts.port,
|
|
2151
|
-
pathname: ch.coord, fragment: visibleFragment,
|
|
2152
|
-
rx,
|
|
2153
|
-
weight: LogBody.weight({
|
|
2154
|
-
op: "READ",
|
|
2155
|
-
attrs: {},
|
|
2156
|
-
tx: "",
|
|
2157
|
-
rx,
|
|
2158
|
-
mimetypeTx: "text/plain",
|
|
2159
|
-
mimetypeRx: "application/json",
|
|
2160
|
-
}, this.#weighContent),
|
|
2161
|
-
status: terminal.status,
|
|
2162
|
-
attrs: JSON.stringify({ streamEnd: ch.content.length, terminal: true }),
|
|
2163
|
-
folded: LogVisibility.serialize(LogVisibility.OPEN), // {§exec-stream} — the conclusion is born OPEN
|
|
2164
|
-
});
|
|
2165
|
-
written++;
|
|
2166
|
-
}
|
|
2167
|
-
return written;
|
|
2168
|
-
}
|
|
2169
|
-
// {§env-delta-filesystem-narration} {§membership-emi-divergence-signal}
|
|
2170
|
-
// — record project-file divergence once through the reserved actor.
|
|
2171
|
-
async #logFsFictions(workspaceId, divergences, gitStatus) {
|
|
2172
|
-
if (divergences.length === 0)
|
|
2173
|
-
return;
|
|
2174
|
-
const gitByPath = new Map(gitStatus?.files.map(({ path, status }) => [path, status]) ?? []);
|
|
2175
|
-
const worker = await this.#db.envelope_get_worker_by_name.get({ workspace_id: workspaceId, name: "plurnk" })
|
|
2176
|
-
?? await this.#db.envelope_insert_worker.get({ workspace_id: workspaceId, name: "plurnk", origin: "_plurnk" });
|
|
2177
|
-
if (worker === undefined)
|
|
2178
|
-
throw new Error("logFsFictions: plurnk worker resolution returned no row");
|
|
2179
|
-
const loop = await this.#db.envelope_insert_client_loop.get({ worker_id: worker.id });
|
|
2180
|
-
if (loop === undefined)
|
|
2181
|
-
throw new Error("logFsFictions: loop insert returned no row");
|
|
2182
|
-
const turn = await Turn.open(this.#db, { loopId: loop.id, producer: "_plurnk", kind: "operation" });
|
|
2183
|
-
let turnOpen = true;
|
|
2184
|
-
try {
|
|
2185
|
-
let sequence = 1;
|
|
2186
|
-
for (const d of divergences) {
|
|
2187
|
-
const span = editedSpan(d.before, d.after);
|
|
2188
|
-
const rx = JSON.stringify({ status: 200, entryId: d.entryId, channel: d.channel, span });
|
|
2189
|
-
const attrs = gitByPath.has(d.pathname)
|
|
2190
|
-
? JSON.stringify({ git: gitByPath.get(d.pathname) })
|
|
2191
|
-
: "{}";
|
|
2192
|
-
await this.#db.engine_insert_log_entry.get({
|
|
2193
|
-
worker_id: worker.id, loop_id: loop.id, turn_id: turn.id, sequence: sequence++,
|
|
2194
|
-
origin: "_plurnk", source: "file", model_call_id: null,
|
|
2195
|
-
op: "EDIT", delimiter: "", signal: null,
|
|
2196
|
-
// Match Dispatcher.#extractTarget: a bare file address has NULL scheme
|
|
2197
|
-
// only in log target metadata; its entry identity remains `file`.
|
|
2198
|
-
scheme: null, username: null, password: null, hostname: null, port: null,
|
|
2199
|
-
pathname: d.pathname, query: null, fragment: null, lineMarker: null,
|
|
2200
|
-
tx: "", mimetype_tx: "text/plain",
|
|
2201
|
-
rx, mimetype_rx: "application/json",
|
|
2202
|
-
status_rx: 200,
|
|
2203
|
-
weight: LogBody.weight({
|
|
2204
|
-
op: "EDIT",
|
|
2205
|
-
attrs,
|
|
2206
|
-
tx: "",
|
|
2207
|
-
rx,
|
|
2208
|
-
mimetypeTx: "text/plain",
|
|
2209
|
-
mimetypeRx: "application/json",
|
|
2210
|
-
}, this.#weighContent),
|
|
2211
|
-
state: "resolved", outcome: null,
|
|
2212
|
-
attrs,
|
|
2213
|
-
initial_folded: LogVisibility.serialize(LogVisibility.OPEN),
|
|
2214
|
-
});
|
|
2215
|
-
}
|
|
2216
|
-
await Turn.complete(this.#db, turn.id, 200);
|
|
2217
|
-
turnOpen = false;
|
|
2218
|
-
const closed = await new LoopLifecycle(this.#db).finish(loop.id, { status: 200 });
|
|
2219
|
-
if (closed === null)
|
|
2220
|
-
throw new Error(`logFsFictions: narration loop ${loop.id} was not open at completion`);
|
|
2221
|
-
}
|
|
2222
|
-
catch (cause) {
|
|
2223
|
-
const settlementFailures = [];
|
|
2224
|
-
const failure = Results.failure("engine:filesystem-narration", "narration-failed", 500, "Filesystem divergence narration failed before its operation turn settled.", {}, { stage: "filesystem-narration", retryable: false });
|
|
2225
|
-
if (turnOpen) {
|
|
2226
|
-
try {
|
|
2227
|
-
await Turn.complete(this.#db, turn.id, failure.status);
|
|
2228
|
-
}
|
|
2229
|
-
catch (turnCause) {
|
|
2230
|
-
settlementFailures.push(turnCause);
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
try {
|
|
2234
|
-
await new LoopLifecycle(this.#db).finish(loop.id, failure);
|
|
2235
|
-
}
|
|
2236
|
-
catch (loopCause) {
|
|
2237
|
-
settlementFailures.push(loopCause);
|
|
2238
|
-
}
|
|
2239
|
-
if (settlementFailures.length > 0) {
|
|
2240
|
-
throw new AggregateError([cause, ...settlementFailures], `filesystem narration ${turn.id} failed to settle`);
|
|
2241
|
-
}
|
|
2242
|
-
throw cause;
|
|
2243
|
-
}
|
|
2244
|
-
}
|
|
2245
|
-
async #writePromptLog({ workerId, loopId, turnId, sequence, target, content, source, }) {
|
|
2246
|
-
const rx = JSON.stringify({ content, mimetype: "text/markdown" });
|
|
2247
|
-
const row = await this.#db.engine_insert_log_entry.get({
|
|
2248
|
-
worker_id: workerId,
|
|
2249
|
-
loop_id: loopId,
|
|
2250
|
-
turn_id: turnId,
|
|
2251
|
-
sequence,
|
|
2252
|
-
origin: "_plurnk",
|
|
2253
|
-
source,
|
|
2254
|
-
model_call_id: null,
|
|
2255
|
-
op: "prompt",
|
|
2256
|
-
delimiter: "",
|
|
2257
|
-
signal: null,
|
|
2258
|
-
scheme: target.scheme,
|
|
2259
|
-
username: target.username,
|
|
2260
|
-
password: target.password,
|
|
2261
|
-
hostname: target.hostname,
|
|
2262
|
-
port: target.port,
|
|
2263
|
-
pathname: target.pathname,
|
|
2264
|
-
query: target.query,
|
|
2265
|
-
fragment: target.fragment,
|
|
2266
|
-
lineMarker: null,
|
|
2267
|
-
tx: "",
|
|
2268
|
-
mimetype_tx: "text/plain",
|
|
2269
|
-
rx,
|
|
2270
|
-
mimetype_rx: "application/json",
|
|
2271
|
-
status_rx: 200,
|
|
2272
|
-
weight: LogBody.weight({
|
|
2273
|
-
op: "prompt",
|
|
2274
|
-
attrs: {},
|
|
2275
|
-
tx: "",
|
|
2276
|
-
rx,
|
|
2277
|
-
mimetypeTx: "text/plain",
|
|
2278
|
-
mimetypeRx: "application/json",
|
|
2279
|
-
}, this.#weighContent),
|
|
2280
|
-
state: "resolved",
|
|
2281
|
-
outcome: null,
|
|
2282
|
-
attrs: "{}",
|
|
2283
|
-
initial_folded: LogVisibility.serialize(LogVisibility.OPEN),
|
|
2284
|
-
});
|
|
2285
|
-
if (row === undefined)
|
|
2286
|
-
throw new Error("TurnRunner.#writePromptLog: INSERT ... RETURNING produced no row");
|
|
2287
|
-
return row.id;
|
|
1694
|
+
async executeAdmittedTurn(...args) {
|
|
1695
|
+
return this.#admitted.executeAdmittedTurn(...args);
|
|
2288
1696
|
}
|
|
2289
1697
|
}
|
|
2290
|
-
_a = TurnRunner;
|
|
2291
|
-
export default TurnRunner;
|
|
2292
1698
|
//# sourceMappingURL=TurnRunner.js.map
|