@plurnk/plurnk-service 2.0.0 → 3.1.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 +27 -19
- package/INSTALL.md +21 -2
- package/README.md +4 -2
- package/SPEC.md +644 -467
- package/dist/build-info.json +1 -1
- package/dist/completions/_plurnk-service +13 -0
- package/dist/completions/plurnk-service.bash +19 -0
- package/dist/completions/plurnk-service.fish +93 -0
- package/dist/content/edit-receipt.d.ts +1 -1
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +1 -1
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +3 -12
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/AdministrativeLoop.d.ts +1 -1
- package/dist/core/AdministrativeLoop.d.ts.map +1 -1
- package/dist/core/AdministrativeLoop.js +2 -6
- package/dist/core/AdministrativeLoop.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +2 -2
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +16 -24
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +8 -2
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +48 -5
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +2 -4
- package/dist/core/CapabilityPolicies.d.ts.map +1 -1
- package/dist/core/CapabilityPolicies.js +3 -23
- package/dist/core/CapabilityPolicies.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +9 -2
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +34 -5
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +0 -2
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ClientInteractions.d.ts +3 -2
- package/dist/core/ClientInteractions.d.ts.map +1 -1
- package/dist/core/ClientInteractions.js +21 -12
- package/dist/core/ClientInteractions.js.map +1 -1
- package/dist/core/ClientInteractions.sql +8 -2
- package/dist/core/CoreSchemeServices.d.ts +1 -0
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +1 -0
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/DataStatementRunner.js +1 -1
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +3 -2
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +55 -52
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +4 -6
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/EnvFlags.d.ts.map +1 -1
- package/dist/core/EnvFlags.js +5 -4
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/FabricatedLog.d.ts +1 -0
- package/dist/core/FabricatedLog.d.ts.map +1 -1
- package/dist/core/FabricatedLog.js +9 -1
- package/dist/core/FabricatedLog.js.map +1 -1
- package/dist/core/HostPaths.d.ts +0 -1
- package/dist/core/HostPaths.d.ts.map +1 -1
- package/dist/core/HostPaths.js +0 -2
- package/dist/core/HostPaths.js.map +1 -1
- package/dist/core/KillHandler.d.ts.map +1 -1
- package/dist/core/KillHandler.js +3 -1
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/LiveSubscription.d.ts.map +1 -1
- package/dist/core/LiveSubscription.js +14 -2
- package/dist/core/LiveSubscription.js.map +1 -1
- package/dist/core/LiveSubscriptions.d.ts +3 -1
- package/dist/core/LiveSubscriptions.d.ts.map +1 -1
- package/dist/core/LiveSubscriptions.js +16 -1
- package/dist/core/LiveSubscriptions.js.map +1 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +3 -1
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +8 -17
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LoopDriver.js +7 -6
- package/dist/core/LoopDriver.js.map +1 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +4 -9
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +7 -6
- package/dist/core/MessageResources.sql +31 -0
- package/dist/core/OperatorConfig.d.ts +1 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -1
- package/dist/core/OperatorConfig.js +10 -2
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +5 -7
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +160 -158
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +20 -6
- package/dist/core/ProposalLifecycle.d.ts +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +18 -20
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProposalPolicies.d.ts +6 -0
- package/dist/core/ProposalPolicies.d.ts.map +1 -0
- package/dist/core/ProposalPolicies.js +28 -0
- package/dist/core/ProposalPolicies.js.map +1 -0
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +3 -4
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ReplyMetadata.d.ts +10 -0
- package/dist/core/ReplyMetadata.d.ts.map +1 -0
- package/dist/core/ReplyMetadata.js +20 -0
- package/dist/core/ReplyMetadata.js.map +1 -0
- package/dist/core/ResourceSelector.js +2 -2
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.js +3 -3
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/RuntimeWorker.sql +1 -2
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +4 -5
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ServiceHelp.d.ts +6 -0
- package/dist/core/ServiceHelp.d.ts.map +1 -0
- package/dist/core/ServiceHelp.js +35 -0
- package/dist/core/ServiceHelp.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +1 -0
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +4 -1
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +2 -2
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TokenCalibration.d.ts +2 -2
- package/dist/core/TokenCalibration.d.ts.map +1 -1
- package/dist/core/TokenCalibration.js +12 -16
- package/dist/core/TokenCalibration.js.map +1 -1
- package/dist/core/TokenCalibration.sql +29 -6
- package/dist/core/ToolInputSchema.d.ts +1 -0
- package/dist/core/ToolInputSchema.d.ts.map +1 -1
- package/dist/core/ToolInputSchema.js +8 -2
- package/dist/core/ToolInputSchema.js.map +1 -1
- package/dist/core/ToolResources.d.ts +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +7 -1
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/TurnDispositionHandler.d.ts +1 -2
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
- package/dist/core/TurnDispositionHandler.js +31 -33
- package/dist/core/TurnDispositionHandler.js.map +1 -1
- package/dist/core/TurnMaterialization.d.ts.map +1 -1
- package/dist/core/TurnMaterialization.js +12 -2
- package/dist/core/TurnMaterialization.js.map +1 -1
- package/dist/core/TurnOps.d.ts +5 -1
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +29 -2
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +184 -103
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/TurnSources.sql +2 -2
- package/dist/core/WorkerControlHandler.d.ts.map +1 -1
- package/dist/core/WorkerControlHandler.js +1 -8
- package/dist/core/WorkerControlHandler.js.map +1 -1
- package/dist/core/WorkerName.d.ts +1 -0
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +2 -0
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +2 -2
- package/dist/core/WorkerOwners.d.ts +13 -0
- package/dist/core/WorkerOwners.d.ts.map +1 -0
- package/dist/core/WorkerOwners.js +44 -0
- package/dist/core/WorkerOwners.js.map +1 -0
- package/dist/core/WorkerOwners.sql +55 -0
- package/dist/core/env-catalog.d.ts +3 -0
- package/dist/core/env-catalog.d.ts.map +1 -1
- package/dist/core/env-catalog.js +44 -9
- package/dist/core/env-catalog.js.map +1 -1
- package/dist/core/fork.sql +3 -4
- package/dist/core/packet-inject.js +0 -2
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +9 -11
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +103 -126
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +4 -4
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/recap-lines.d.ts +4 -0
- package/dist/core/recap-lines.d.ts.map +1 -0
- package/dist/core/recap-lines.js +11 -0
- package/dist/core/recap-lines.js.map +1 -0
- package/dist/core/scheme-types.d.ts +2 -1
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/sql-functions.d.ts +2 -0
- package/dist/core/sql-functions.d.ts.map +1 -0
- package/dist/core/sql-functions.js +5 -0
- package/dist/core/sql-functions.js.map +1 -0
- 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/types.d.ts +0 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.d.ts +1 -3
- package/dist/core/unregistered-scheme.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.js +3 -11
- package/dist/core/unregistered-scheme.js.map +1 -1
- package/dist/evidence/EvidenceReader.d.ts.map +1 -1
- package/dist/evidence/EvidenceReader.js +18 -2
- package/dist/evidence/EvidenceReader.js.map +1 -1
- package/dist/evidence/digest.sql +2 -2
- package/dist/man/plurnk-service.1 +488 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +1 -10
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Env.d.ts +26 -0
- package/dist/schemes/Env.d.ts.map +1 -0
- package/dist/schemes/Env.js +133 -0
- package/dist/schemes/Env.js.map +1 -0
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +30 -37
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +3 -2
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +9 -0
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +10 -16
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +33 -10
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +9 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +1 -3
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +6 -8
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts +1 -1
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +16 -9
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-fts.d.ts.map +1 -1
- package/dist/schemes/_entry-fts.js +3 -9
- package/dist/schemes/_entry-fts.js.map +1 -1
- package/dist/schemes/_entry-manifest.js +3 -3
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.js +1 -1
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/exec-abort.js +2 -2
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/server/ConfigurationDiagnostics.d.ts +1 -0
- package/dist/server/ConfigurationDiagnostics.d.ts.map +1 -1
- package/dist/server/ConfigurationDiagnostics.js +9 -0
- package/dist/server/ConfigurationDiagnostics.js.map +1 -1
- package/dist/server/Daemon.d.ts +13 -8
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +57 -53
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +2 -4
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +5 -12
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/EnvFunctionality.d.ts +6 -6
- package/dist/server/EnvFunctionality.d.ts.map +1 -1
- package/dist/server/EnvFunctionality.js +7 -6
- package/dist/server/EnvFunctionality.js.map +1 -1
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +42 -13
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +3 -4
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +17 -9
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/HttpListener.d.ts.map +1 -1
- package/dist/server/HttpListener.js +9 -3
- package/dist/server/HttpListener.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +2 -5
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +5 -3
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/WorkspaceStorage.d.ts +0 -1
- package/dist/server/WorkspaceStorage.d.ts.map +1 -1
- package/dist/server/WorkspaceStorage.js +1 -24
- package/dist/server/WorkspaceStorage.js.map +1 -1
- package/dist/server/client-input.d.ts +1 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +13 -15
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +1 -1
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +16 -15
- package/dist/server/envelope.d.ts +2 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +7 -17
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +5 -5
- package/dist/server/seam-proposal-list.sql +6 -4
- package/dist/server/workspace-storage.sql +0 -5
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +28 -64
- package/dist/service.js.map +1 -1
- package/docs/env.md +22 -0
- package/migrations/003_loops.sql +2 -2
- package/migrations/006_log.sql +1 -1
- package/migrations/016_selection_statements.sql +1 -0
- package/migrations/017_skills_module.sql +1 -0
- package/migrations/018_worker_owners.sql +103 -0
- package/migrations/019_interactive_owners.sql +7 -0
- package/migrations/020_log_projection.sql +144 -0
- package/migrations/021_packet_roles.sql +86 -0
- package/migrations/022_message_completion.sql +24 -0
- package/package.json +41 -43
- package/dist/core/LegacyHome.d.ts +0 -10
- package/dist/core/LegacyHome.d.ts.map +0 -1
- package/dist/core/LegacyHome.js +0 -170
- package/dist/core/LegacyHome.js.map +0 -1
- package/dist/core/LoopPolicies.d.ts +0 -7
- package/dist/core/LoopPolicies.d.ts.map +0 -1
- package/dist/core/LoopPolicies.js +0 -42
- package/dist/core/LoopPolicies.js.map +0 -1
- package/dist/core/LoopPolicyReader.d.ts +0 -7
- package/dist/core/LoopPolicyReader.d.ts.map +0 -1
- package/dist/core/LoopPolicyReader.js +0 -33
- package/dist/core/LoopPolicyReader.js.map +0 -1
- package/dist/core/LoopPolicyReader.sql +0 -6
- package/dist/index.d.ts +0 -14
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -21
- package/dist/index.js.map +0 -1
package/dist/core/TurnRunner.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var _a;
|
|
2
2
|
import NativeContent from "./NativeContent.js";
|
|
3
|
-
import { PlurnkParser } from "@plurnk/plurnk-parser";
|
|
4
|
-
import { PathSyntax, PlurnkParseError,
|
|
5
|
-
import
|
|
3
|
+
import { PlurnkParser, parsePath } from "@plurnk/plurnk-parser";
|
|
4
|
+
import { PathSyntax, PlurnkParseError, UNKNOWN_POSITION } from "@plurnk/plurnk-contracts";
|
|
5
|
+
import WorkerOwners from "./WorkerOwners.js";
|
|
6
6
|
import { setTimeout as delay } from "node:timers/promises";
|
|
7
7
|
import { aggregateProviderAccounting } from "@plurnk/plurnk-providers";
|
|
8
8
|
const comparePosition = (a, b) => a.line - b.line || a.column - b.column;
|
|
@@ -12,20 +12,16 @@ import GitMembership from "./git-membership.js";
|
|
|
12
12
|
import { acceptedKinds } from "./attachments.js";
|
|
13
13
|
import GitState from "./git-state.js";
|
|
14
14
|
import WorkspaceSettings from "./workspace-settings.js";
|
|
15
|
-
import { contentWeight } from "./content-weight.js";
|
|
16
15
|
import { generatedPathname } from "./plurnk-uri.js";
|
|
16
|
+
import { contentWeight } from "./content-weight.js";
|
|
17
17
|
import { readFile } from "node:fs/promises";
|
|
18
18
|
import { resolve as resolvePath } from "node:path";
|
|
19
19
|
import { homedir } from "node:os";
|
|
20
|
-
// {§operator-grammar}
|
|
21
|
-
// relative to the daemon's working directory. The service ships no grammar profile, so a bare
|
|
22
|
-
// name (no separator) is refused by name rather than resolved against anything.
|
|
20
|
+
// {§operator-grammar}
|
|
23
21
|
export const resolveOperatorGrammarPath = (value) => {
|
|
24
22
|
if (value === "~" || value.startsWith("~/"))
|
|
25
23
|
return resolvePath(homedir(), value.slice(2));
|
|
26
|
-
|
|
27
|
-
return resolvePath(value);
|
|
28
|
-
throw new Error(`PLURNK_PROVIDERS_GBNF=${value} names a bundled grammar profile; the service ships none (#588). Give the path of a grammar file you wrote.`);
|
|
24
|
+
return resolvePath(value);
|
|
29
25
|
};
|
|
30
26
|
// Shared module imported by both Engine and the digest, so wire
|
|
31
27
|
// projection and digest projection are structurally one function — no
|
|
@@ -35,7 +31,6 @@ import { RECEIPT_RESERVE, reserved } from "./ContextFit.js";
|
|
|
35
31
|
import Results, { OperationFailureError } from "./results.js";
|
|
36
32
|
import Turn from "./Turn.js";
|
|
37
33
|
import ProviderRecovery from "./ProviderRecovery.js";
|
|
38
|
-
import PacketBuilder from "./PacketBuilder.js";
|
|
39
34
|
import StoredPacket from "./StoredPacket.js";
|
|
40
35
|
import { observed, observedSync } from "../observe/spans.js";
|
|
41
36
|
import { genAiRequestName, genAiRequestOptions, settleGenAiResponse } from "../observe/genai.js";
|
|
@@ -43,7 +38,6 @@ import { PROVIDER_CALLS, recordCounter } from "../observe/metrics.js";
|
|
|
43
38
|
import ModelCall, { ModelCallPersistenceError, ProviderAccountingIntegrityError } from "./ModelCall.js";
|
|
44
39
|
import WorkerName from "./WorkerName.js";
|
|
45
40
|
import TurnOps from "./TurnOps.js";
|
|
46
|
-
import CapabilityPolicies from "./CapabilityPolicies.js";
|
|
47
41
|
import CapabilityResolver from "./CapabilityResolver.js";
|
|
48
42
|
const regexLiteral = (value) => value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
49
43
|
const workerCatalogTarget = (namespace) => {
|
|
@@ -103,6 +97,24 @@ const windowOverflowFailure = (overflow) => Results.failure("engine:context", "w
|
|
|
103
97
|
// {§context-over-budget-row} — the row is the mandate; the gauge is the one home for the numbers
|
|
104
98
|
// ({§context-gauge}), which the row's own charge would otherwise put out of agreement.
|
|
105
99
|
const OVER_BUDGET_DETAIL = "Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn.";
|
|
100
|
+
// {§worker-initialization-entry} — the one NOTE that leads the initialization surveys.
|
|
101
|
+
const INITIALIZATION_NOTE = {
|
|
102
|
+
op: "NOTE", aside: null, metadata: null, target: null, lineMarker: null,
|
|
103
|
+
body: "Surveyed tooling, documentation, extended context, and project root.", position: UNKNOWN_POSITION,
|
|
104
|
+
};
|
|
105
|
+
// {§continued-without-note} — said once, in the next packet, of a continuing turn that carried no NOTE.
|
|
106
|
+
const CONTINUED_WITHOUT_NOTE = "The turn continued without a NOTE.";
|
|
107
|
+
// Trial (#1073): a continuing turn that carried NOTEs and no other operation is told so under the same
|
|
108
|
+
// per-turn rule; it is a notice, never a strike.
|
|
109
|
+
const NOTED_WITHOUT_OPERATION = "The turn carried NOTEs and no other operation.";
|
|
110
|
+
// {§notice-directive} — what each notice of the model's own output asks of it: MUST where the card says MUST
|
|
111
|
+
// or the output was refused, SHOULD where a near-miss was accepted.
|
|
112
|
+
const DIRECTIVE = Object.freeze({
|
|
113
|
+
note: "YOU MUST emit at least one NOTE operation with a complete status summary and at least one other operation per turn.",
|
|
114
|
+
emission: "YOU MUST ONLY emit fenced operations; with the parameters, pattern, and terse aside on the fenced Operation line.",
|
|
115
|
+
advisory: "YOU SHOULD write the canonical form.",
|
|
116
|
+
output: "YOU SHOULD emit fewer or shorter operations per turn.",
|
|
117
|
+
});
|
|
106
118
|
const overBudgetFailure = () => Results.failure("engine:context", "packet-exceeds-budget", 413, OVER_BUDGET_DETAIL);
|
|
107
119
|
const INVALID_EMISSION_RECOVERY_MESSAGE = "Response rejected before dispatch; no operations were performed.";
|
|
108
120
|
// {§output-allowance-notice} — THE single derivation of a ceiling cut: a
|
|
@@ -111,7 +123,7 @@ const INVALID_EMISSION_RECOVERY_MESSAGE = "Response rejected before dispatch; no
|
|
|
111
123
|
// path. Null means the emission was not cut by the allowance.
|
|
112
124
|
const allowanceCutMessage = (finishReason, grant) => finishReason !== "length"
|
|
113
125
|
? null
|
|
114
|
-
: `
|
|
126
|
+
: `Emission truncated at the output allowance${grant === null ? "" : ` (${grant} tokens)`}`;
|
|
115
127
|
const readEmissionAttempts = () => Knob.integer("PLURNK_SERVICE_EMISSION_ATTEMPTS", 1);
|
|
116
128
|
// The wall's abort reason — runLoop branches a mid-turn teardown to the 504 terminal on it.
|
|
117
129
|
export const LOOP_TIMEOUT_REASON = "loop_timeout";
|
|
@@ -270,18 +282,15 @@ class TurnRunner {
|
|
|
270
282
|
// {§packet-attachment-parts}: native parts come from the READ's immutable snapshot,
|
|
271
283
|
// never from a source that may have changed since the observation.
|
|
272
284
|
async #wireMessages(packet, ctx, provider) {
|
|
273
|
-
// {§packet-wire-envelope} — each emission row the packet placed carries its emission as the
|
|
274
|
-
// worker's own assistant message.
|
|
275
|
-
const emissions = this.#packets.emissionsFor(packet);
|
|
276
285
|
const accepted = acceptedKinds(provider.inputModalities);
|
|
277
286
|
if (accepted.length === 0 || !(packet.attachments ?? []).some((attachment) => accepted.includes(attachment.kind))) {
|
|
278
287
|
return {
|
|
279
|
-
messages: PacketWire.packetToWireMessages(packet
|
|
288
|
+
messages: PacketWire.packetToWireMessages(packet),
|
|
280
289
|
nativeInputs: [],
|
|
281
290
|
};
|
|
282
291
|
}
|
|
283
292
|
const nativeInputs = new Set();
|
|
284
|
-
const messages = await PacketWire.wireMessages(packet,
|
|
293
|
+
const messages = await PacketWire.wireMessages(packet, async (attachment) => {
|
|
285
294
|
const bytes = await NativeContent.read(ctx.db, attachment.contentHash);
|
|
286
295
|
nativeInputs.add(attachment.coordinate);
|
|
287
296
|
return bytes;
|
|
@@ -300,8 +309,6 @@ class TurnRunner {
|
|
|
300
309
|
const createdTurnIds = [];
|
|
301
310
|
const turnSignal = this.#loopSignal(loopId) ?? signal;
|
|
302
311
|
try {
|
|
303
|
-
// {§configuration-repair-path} — a retired packet knob refuses inference before any turn opens.
|
|
304
|
-
PacketBuilder.assertConfiguration();
|
|
305
312
|
const container = await this.#openTurnContainer(args, createdTurnIds);
|
|
306
313
|
const gitStatus = await this.#deriveWorkspace(args, container.systemCtx);
|
|
307
314
|
if (container.initializationTurn !== null)
|
|
@@ -312,7 +319,7 @@ class TurnRunner {
|
|
|
312
319
|
if (admitted.overflow !== null)
|
|
313
320
|
return await this.#failCuration(admitted.request, admitted.overflow);
|
|
314
321
|
const request = admitted.request;
|
|
315
|
-
const attempts = await this.#prepareProviderAttempts(args, request);
|
|
322
|
+
const attempts = await this.#prepareProviderAttempts(args, request, admitted.wire);
|
|
316
323
|
let emission;
|
|
317
324
|
try {
|
|
318
325
|
emission = await this.#attemptProvider(args, request, attempts);
|
|
@@ -376,7 +383,7 @@ class TurnRunner {
|
|
|
376
383
|
createdTurnIds.push(initializationTurn.id);
|
|
377
384
|
const initializationPolicies = initializationTurn === null
|
|
378
385
|
? []
|
|
379
|
-
: (await
|
|
386
|
+
: (await this.#capabilities.layers(workspaceId, workerId)).map((layer) => layer.policy);
|
|
380
387
|
const modelTurn = initializationTurn === null
|
|
381
388
|
? await Turn.open(this.#db, { loopId, producer: "model", kind: "inference" })
|
|
382
389
|
: null;
|
|
@@ -495,9 +502,14 @@ class TurnRunner {
|
|
|
495
502
|
await Turn.complete(this.#db, initializationTurn.id, 200);
|
|
496
503
|
return;
|
|
497
504
|
}
|
|
498
|
-
|
|
505
|
+
// {§worker-initialization-entry} — the example turn keeps the NOTE contract the card teaches:
|
|
506
|
+
// when the surveys run, one NOTE leads them.
|
|
507
|
+
const programStatements = admittedInitializationStatements.some((statement) => statement.op === "FIND")
|
|
508
|
+
? [INITIALIZATION_NOTE, ...admittedInitializationStatements]
|
|
509
|
+
: admittedInitializationStatements;
|
|
510
|
+
const program = TurnOps.renderInternal(programStatements);
|
|
499
511
|
const admitted = PlurnkParser.parseStatements(program).items.flatMap((item) => item.kind === "statement" ? [item.statement] : []);
|
|
500
|
-
if (admitted.length !==
|
|
512
|
+
if (admitted.length !== programStatements.length) {
|
|
501
513
|
throw new Error("initialization program did not preserve every authored operation");
|
|
502
514
|
}
|
|
503
515
|
await Turn.recordSource(this.#db, initializationTurn.id, "ops", program);
|
|
@@ -512,7 +524,7 @@ class TurnRunner {
|
|
|
512
524
|
turnId: initializationTurn.id,
|
|
513
525
|
fromSequence: 1,
|
|
514
526
|
failOnOperationError: true,
|
|
515
|
-
fit: this.#fitFor(args, { turnId: initializationTurn.id, seq: initializationTurn.sequence, gitStatus, notices: [], transientOpenLogEntryId: container.transientOpenLogEntryId, bodiless: new Set() }),
|
|
527
|
+
fit: this.#fitFor(args, { turnId: initializationTurn.id, seq: initializationTurn.sequence, gitStatus, notices: [], transientOpenLogEntryId: container.transientOpenLogEntryId, projection: { bodiless: new Set(), omitEmissionHistory: false } }),
|
|
516
528
|
signal: this.#loopSignal(loopId),
|
|
517
529
|
onDispatch,
|
|
518
530
|
onSettled,
|
|
@@ -524,11 +536,18 @@ class TurnRunner {
|
|
|
524
536
|
// {§actor-boundary-catalog-preview} — the opening surveys, each admitted only when
|
|
525
537
|
// its scheme is registered for the workspace. A positive filesItems caps the
|
|
526
538
|
// project rows.
|
|
527
|
-
async #catalogSurveys({ workspaceId }, { workerName, initializationPolicies }, filesItems) {
|
|
539
|
+
async #catalogSurveys({ workspaceId }, { workerName, initializationPolicies, loopSequence }, filesItems) {
|
|
528
540
|
const catalogSchemes = await this.#db.engine_scheme_catalog_summary.all({ workspace_id: workspaceId });
|
|
529
541
|
const fileItems = catalogSchemes.find(({ scheme }) => scheme === "file")?.shallow_items ?? 0;
|
|
530
542
|
const fileCap = filesItems > 0 && fileItems > 0 ? Math.min(filesItems, fileItems) : null;
|
|
531
543
|
const surveys = [
|
|
544
|
+
{
|
|
545
|
+
// Trial (#1073): the survey reads its own program, so the log carries one program verbatim
|
|
546
|
+
// and shows that every ops:// turn is readable.
|
|
547
|
+
op: "READ", aside: "this program",
|
|
548
|
+
target: { kind: "url", raw: `ops://${workerName}/${loopSequence}/1`, scheme: "ops", username: null, password: null, hostname: workerName, port: null, pathname: `/${loopSequence}/1`, query: null, fragment: null },
|
|
549
|
+
metadata: null, lineMarker: null, matcher: null, body: null, position: UNKNOWN_POSITION,
|
|
550
|
+
},
|
|
532
551
|
{
|
|
533
552
|
op: "FIND", aside: null,
|
|
534
553
|
target: { kind: "url", raw: "skill://*/SKILL.md", scheme: "skill", username: null, password: null, hostname: "*", port: null, pathname: "/SKILL.md", query: null, fragment: null },
|
|
@@ -638,7 +657,7 @@ class TurnRunner {
|
|
|
638
657
|
const systemCtx = this.#schemeContext(args, turnId);
|
|
639
658
|
// {§context-fit} — one measure for everything this turn lands: the budget less the packet as it
|
|
640
659
|
// would render now. The drained notices join the same facts below.
|
|
641
|
-
const facts = { turnId, seq, gitStatus, notices: [], transientOpenLogEntryId: container.transientOpenLogEntryId, bodiless: new Set() };
|
|
660
|
+
const facts = { turnId, seq, gitStatus, notices: [], transientOpenLogEntryId: container.transientOpenLogEntryId, projection: { bodiless: new Set(), omitEmissionHistory: false } };
|
|
642
661
|
const fit = this.#fitFor(args, facts);
|
|
643
662
|
const messages = await this.#publishMessages(args, turnId, fit);
|
|
644
663
|
let nextActionIndex = await this.#readOpenPaths(args, turnId, messages.openPaths, messages.nextActionIndex, fit);
|
|
@@ -699,20 +718,20 @@ class TurnRunner {
|
|
|
699
718
|
}
|
|
700
719
|
return { nextActionIndex, openPaths };
|
|
701
720
|
}
|
|
702
|
-
// {§methods-loop-run-open-paths}: selected
|
|
721
|
+
// {§methods-loop-run-open-paths}: selected resources belong to the message.
|
|
703
722
|
// Publish it, then dispatch ordinary core READs in that same turn;
|
|
704
723
|
// missing/non-member paths retain their normal 4xx. Returns the next action index.
|
|
705
724
|
async #readOpenPaths({ workspaceId, workerId, loopId, onDispatch, onSettled }, turnId, openPaths, fromSequence, fit) {
|
|
706
725
|
let nextActionIndex = fromSequence;
|
|
707
726
|
for (const [index, raw] of openPaths.entries()) {
|
|
708
|
-
const
|
|
727
|
+
const resourceRead = {
|
|
709
728
|
op: "READ", aside: null, lineMarker: null, matcher: null,
|
|
710
|
-
target:
|
|
729
|
+
target: parsePath(PathSyntax.escapeTarget(raw)),
|
|
711
730
|
metadata: null,
|
|
712
731
|
body: null, position: UNKNOWN_POSITION,
|
|
713
732
|
};
|
|
714
733
|
await this.#dispatch({
|
|
715
|
-
statement:
|
|
734
|
+
statement: resourceRead, workspaceId, workerId, loopId, turnId,
|
|
716
735
|
sequence: nextActionIndex, origin: "_plurnk", onDispatch, onSettled,
|
|
717
736
|
fit: reserved(fit, openPaths.length - index - 1),
|
|
718
737
|
});
|
|
@@ -720,8 +739,9 @@ class TurnRunner {
|
|
|
720
739
|
}
|
|
721
740
|
return nextActionIndex;
|
|
722
741
|
}
|
|
723
|
-
#buildPacket(
|
|
724
|
-
|
|
742
|
+
async #buildPacket(args, facts) {
|
|
743
|
+
const { messages, recap, workspaceId, workerId, loopId, provider } = args;
|
|
744
|
+
const packet = await this.#packets.buildRequestPacket({
|
|
725
745
|
initialMessages: messages,
|
|
726
746
|
recap,
|
|
727
747
|
workspaceId,
|
|
@@ -733,8 +753,16 @@ class TurnRunner {
|
|
|
733
753
|
notices: facts.notices,
|
|
734
754
|
transientOpenLogEntryId: facts.transientOpenLogEntryId,
|
|
735
755
|
turnId: facts.turnId,
|
|
736
|
-
bodiless: facts.bodiless,
|
|
756
|
+
bodiless: facts.projection.bodiless,
|
|
757
|
+
omitEmissionHistory: facts.projection.omitEmissionHistory,
|
|
737
758
|
});
|
|
759
|
+
// {§emission-history}: all builds, including result-admission probes, shed the optional
|
|
760
|
+
// replay before taking result bodies. Share the decision across this request's rebuilds.
|
|
761
|
+
if (PacketWire.sectionContent(packet, "emission-history").length > 0 && this.#packets.windowOverflow(packet, provider) !== null) {
|
|
762
|
+
facts.projection.omitEmissionHistory = true;
|
|
763
|
+
return this.#buildPacket(args, facts);
|
|
764
|
+
}
|
|
765
|
+
return packet;
|
|
738
766
|
}
|
|
739
767
|
// {§context-fit} — the budget left for one more row, measured by building the packet as it would
|
|
740
768
|
// render now: every row landed so far, every KILL already honoured. Null without a budget.
|
|
@@ -760,41 +788,61 @@ class TurnRunner {
|
|
|
760
788
|
const packet = await this.#buildPacket(args, request);
|
|
761
789
|
return { ...request, nextActionIndex: request.nextActionIndex + 1, packet };
|
|
762
790
|
}
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
//
|
|
766
|
-
// as receipts.
|
|
791
|
+
// {§context-admission} — one request through the room: over the wall by the estimate, it sheds; over
|
|
792
|
+
// budget, it carries one row whose own weight takes the same wall ({§context-over-budget-row}); then the
|
|
793
|
+
// provider assesses the exact wire request, and an exact refusal sheds by its excess
|
|
794
|
+
// ({§context-wall-measure}). Only a packet that cannot fit even as receipts returns its overflow.
|
|
767
795
|
async #admitPacket(args, request) {
|
|
768
|
-
const
|
|
769
|
-
if (fitted.overflow !== null)
|
|
770
|
-
return fitted;
|
|
771
|
-
if (this.#packets.curationOverflow(fitted.request.packet) === null)
|
|
772
|
-
return fitted;
|
|
773
|
-
return await this.#fitOwnRows(args, await this.#noteOverBudget(args, fitted.request));
|
|
774
|
-
}
|
|
775
|
-
// {§context-own-rows-fit} — while the packet is over the wall ({§context-wall}), the newest rows still
|
|
776
|
-
// carrying a body are taken, enough of them by their rendered tokens to shed the excess, and the packet
|
|
777
|
-
// is rebuilt with them bodiless; every body stays stored. The rebuilt packet is measured again until
|
|
778
|
-
// it fits, or until no row is left to take.
|
|
779
|
-
async #fitOwnRows(args, request) {
|
|
796
|
+
const { provider, loopId, signal } = args;
|
|
780
797
|
let current = request;
|
|
798
|
+
let noted = false;
|
|
781
799
|
for (;;) {
|
|
782
|
-
const
|
|
783
|
-
if (
|
|
784
|
-
|
|
800
|
+
const estimated = this.#packets.windowOverflow(current.packet, provider);
|
|
801
|
+
if (estimated !== null) {
|
|
802
|
+
const shed = await this.#shed(args, current, estimated);
|
|
803
|
+
if (shed === null)
|
|
804
|
+
return { request: current, wire: null, overflow: estimated };
|
|
805
|
+
current = shed;
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
if (!noted && this.#packets.curationOverflow(current.packet) !== null) {
|
|
809
|
+
current = await this.#noteOverBudget(args, current);
|
|
810
|
+
noted = true;
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
const wire = await this.#wireMessages(current.packet, current.systemCtx, provider);
|
|
814
|
+
const capacity = await provider.assessRequestCapacity(wire.messages, undefined, this.#loopSignal(loopId) ?? signal);
|
|
815
|
+
const refused = this.#packets.exactOverflow(current.packet, capacity);
|
|
816
|
+
if (refused === null)
|
|
817
|
+
return { request: current, wire, overflow: null };
|
|
818
|
+
const shed = await this.#shed(args, current, refused);
|
|
819
|
+
if (shed === null)
|
|
820
|
+
return { request: current, wire: null, overflow: refused };
|
|
821
|
+
current = shed;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
// {§context-own-rows-fit} — one shedding step for whichever measure found the request over the wall: the
|
|
825
|
+
// previous program goes whole first ({§emission-history}), then the newest rows still carrying a body,
|
|
826
|
+
// enough of them by their rendered tokens to shed the excess; every body stays stored. Null when nothing
|
|
827
|
+
// is left to take.
|
|
828
|
+
async #shed(args, request, overflow) {
|
|
829
|
+
if (!request.projection.omitEmissionHistory && PacketWire.sectionContent(request.packet, "emission-history").length > 0) {
|
|
830
|
+
request.projection.omitEmissionHistory = true;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
785
833
|
let shed = 0;
|
|
786
834
|
let taken = 0;
|
|
787
|
-
for (const { id, tokens } of this.#packets.bodiedRowsOf(
|
|
835
|
+
for (const { id, tokens } of this.#packets.bodiedRowsOf(request.packet).toReversed()) {
|
|
788
836
|
if (shed >= overflow.excessWeight)
|
|
789
837
|
break;
|
|
790
|
-
|
|
838
|
+
request.projection.bodiless.add(id);
|
|
791
839
|
shed += tokens;
|
|
792
840
|
taken += 1;
|
|
793
841
|
}
|
|
794
842
|
if (taken === 0)
|
|
795
|
-
return
|
|
796
|
-
current = { ...current, packet: await this.#buildPacket(args, current) };
|
|
843
|
+
return null;
|
|
797
844
|
}
|
|
845
|
+
return { ...request, packet: await this.#buildPacket(args, request) };
|
|
798
846
|
}
|
|
799
847
|
// {§context-wall} — the packet cannot fit the window even as receipts: the turn completes on the
|
|
800
848
|
// overflow and the loop rules the terminal; no provider I/O.
|
|
@@ -805,8 +853,7 @@ class TurnRunner {
|
|
|
805
853
|
}
|
|
806
854
|
// Phase 4's bookkeeping: the wire request, the recovery knobs, the signal the
|
|
807
855
|
// provider sees, the client id and the worker's provider identity.
|
|
808
|
-
async #prepareProviderAttempts({
|
|
809
|
-
const wire = await this.#wireMessages(request.packet, request.systemCtx, provider);
|
|
856
|
+
async #prepareProviderAttempts({ workerId, loopId, signal }, request, wire) {
|
|
810
857
|
// {§provider-recovery} — this turn's recovery clock: the first recoverable provider
|
|
811
858
|
// failure starts it; the budget and backoff are the operator's.
|
|
812
859
|
const recoveryBudget = ProviderRecovery.budget();
|
|
@@ -838,9 +885,8 @@ class TurnRunner {
|
|
|
838
885
|
};
|
|
839
886
|
}
|
|
840
887
|
// Phase 4 — the provider attempt loop. Each iteration is one logical call: a
|
|
841
|
-
// recoverable failure
|
|
842
|
-
//
|
|
843
|
-
// ({§invalid-emission-attempts}).
|
|
888
|
+
// recoverable failure re-issues the same emission attempt, an invalid emission
|
|
889
|
+
// spends one, and a valid emission ends the loop ({§invalid-emission-attempts}).
|
|
844
890
|
async #attemptProvider(args, request, attempts) {
|
|
845
891
|
const { provider, workspaceId, workerId, loopId, signal } = args;
|
|
846
892
|
// {§turn-lifecycle}: bracket the complete provider-attempt window with liveness notices.
|
|
@@ -899,14 +945,13 @@ class TurnRunner {
|
|
|
899
945
|
return emission;
|
|
900
946
|
}
|
|
901
947
|
// One logical provider call: its durable model call and attempt row, the exchange
|
|
902
|
-
// under the reasoning observer, and its classification.
|
|
903
|
-
//
|
|
904
|
-
//
|
|
948
|
+
// under the reasoning observer, and its classification. {§provider-recovery}
|
|
949
|
+
// re-issues the same emission attempt; the parser's admission is the one verdict
|
|
950
|
+
// on a completed exchange.
|
|
905
951
|
async #issueProviderCall(args, request, attempts, attempt, strikeStreak) {
|
|
906
952
|
const { provider, workspaceId, workerId, loopId } = args;
|
|
907
|
-
//
|
|
908
|
-
//
|
|
909
|
-
// call still receives its own durable sequence and accounting.
|
|
953
|
+
// A recovery re-issue does not consume a grammar-emission attempt. Every
|
|
954
|
+
// logical provider call still receives its own durable sequence and accounting.
|
|
910
955
|
attempts.currentEmissionAttempt = attempt;
|
|
911
956
|
attempts.modelCallSequence++;
|
|
912
957
|
const attributionContext = Object.freeze({
|
|
@@ -945,8 +990,8 @@ class TurnRunner {
|
|
|
945
990
|
await this.#recoverProviderFailure(args, request, attempts, modelCall, attemptRow.id, error);
|
|
946
991
|
return "reissued";
|
|
947
992
|
}
|
|
948
|
-
// {§context-wall} —
|
|
949
|
-
//
|
|
993
|
+
// {§context-wall-measure} — admission already shed for an exact refusal of this wire request;
|
|
994
|
+
// an upstream refusal is the provider's own 413.
|
|
950
995
|
throw error;
|
|
951
996
|
}
|
|
952
997
|
finally {
|
|
@@ -1181,14 +1226,12 @@ class TurnRunner {
|
|
|
1181
1226
|
if (attempts.parked) {
|
|
1182
1227
|
// {§provider-recovery} — the recovery budget is spent: the loop parks exactly like a
|
|
1183
1228
|
// [202] wait and resumes on the next prompt or wake; the failure stays durable.
|
|
1184
|
-
|
|
1185
|
-
// and the notice says that rather than promising a resumption nobody can deliver.
|
|
1186
|
-
const { attended } = await LoopPolicyReader.read(this.#db, loopId);
|
|
1229
|
+
const recoverable = await WorkerOwners.interactive(this.#db, loopId);
|
|
1187
1230
|
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1188
1231
|
source: "engine:provider",
|
|
1189
1232
|
kind: "provider_unavailable",
|
|
1190
1233
|
level: "error",
|
|
1191
|
-
message: `${recorded.result.problem?.title ?? "Provider failure"}: the ${Math.round(attempts.recoveryBudget / 1000)}s recovery budget is spent; ${
|
|
1234
|
+
message: `${recorded.result.problem?.title ?? "Provider failure"}: the ${Math.round(attempts.recoveryBudget / 1000)}s recovery budget is spent; ${recoverable ? "the loop is parked and resumes on the next prompt or wake" : "nobody attends the worker's owner, so the loop ends here"}.`,
|
|
1192
1235
|
});
|
|
1193
1236
|
return turnResult(request, 202, { providerParked: true, providerFailure: recorded.result, emissionAttempts });
|
|
1194
1237
|
}
|
|
@@ -1243,7 +1286,8 @@ class TurnRunner {
|
|
|
1243
1286
|
source: "engine:capacity",
|
|
1244
1287
|
kind: "output_truncated",
|
|
1245
1288
|
level: "error",
|
|
1246
|
-
|
|
1289
|
+
directive: DIRECTIVE.output,
|
|
1290
|
+
message: `${cut}; no operations were performed.`,
|
|
1247
1291
|
});
|
|
1248
1292
|
}
|
|
1249
1293
|
else {
|
|
@@ -1251,6 +1295,7 @@ class TurnRunner {
|
|
|
1251
1295
|
source: "engine:grammar",
|
|
1252
1296
|
kind: "invalid_emission",
|
|
1253
1297
|
level: "error",
|
|
1298
|
+
directive: DIRECTIVE.emission,
|
|
1254
1299
|
message: diagnostic === undefined
|
|
1255
1300
|
? INVALID_EMISSION_RECOVERY_MESSAGE
|
|
1256
1301
|
: `${INVALID_EMISSION_RECOVERY_MESSAGE} Parser: ${diagnostic.message}`,
|
|
@@ -1286,7 +1331,8 @@ class TurnRunner {
|
|
|
1286
1331
|
source: "engine:turn",
|
|
1287
1332
|
kind: "output_truncated",
|
|
1288
1333
|
level: "warn",
|
|
1289
|
-
|
|
1334
|
+
directive: DIRECTIVE.output,
|
|
1335
|
+
message: `${allowanceCut}; no authored operations were performed.`,
|
|
1290
1336
|
});
|
|
1291
1337
|
}
|
|
1292
1338
|
// Non-fatal provider transport notices on an accepted turn. Forward each
|
|
@@ -1300,6 +1346,7 @@ class TurnRunner {
|
|
|
1300
1346
|
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1301
1347
|
source: notice.source,
|
|
1302
1348
|
kind: notice.kind,
|
|
1349
|
+
...(notice.directive === undefined ? {} : { directive: notice.directive }),
|
|
1303
1350
|
message: notice.message ?? "",
|
|
1304
1351
|
level: notice.level,
|
|
1305
1352
|
...(located !== null
|
|
@@ -1311,27 +1358,19 @@ class TurnRunner {
|
|
|
1311
1358
|
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1312
1359
|
source: "engine:capacity",
|
|
1313
1360
|
kind: "output_truncated",
|
|
1314
|
-
|
|
1361
|
+
directive: DIRECTIVE.output,
|
|
1362
|
+
message: `${allowanceCut}.`,
|
|
1315
1363
|
level: "warn",
|
|
1316
1364
|
});
|
|
1317
1365
|
}
|
|
1318
|
-
// {§outside-text} —
|
|
1319
|
-
//
|
|
1366
|
+
// {§outside-text} — a turn that fenced no operation keeps its text as its outside source: the
|
|
1367
|
+
// evidence behind the empty turn's strike and a terminal's citation; no row, notice or NOTE.
|
|
1320
1368
|
if (split.outside !== null) {
|
|
1321
|
-
await Turn.recordSource(this.#db, request.turnId, "outside", split.outside
|
|
1322
|
-
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1323
|
-
source: "engine:turn",
|
|
1324
|
-
kind: "outside_text",
|
|
1325
|
-
level: "warn",
|
|
1326
|
-
message: `${split.outside.tokens} tokens emitted outside OPs. Discarded.`,
|
|
1327
|
-
});
|
|
1369
|
+
await Turn.recordSource(this.#db, request.turnId, "outside", split.outside, { modelCallId: emission.modelCallId });
|
|
1328
1370
|
this.#notify.outsideEventNotify?.(workspaceId, {
|
|
1329
|
-
workerId,
|
|
1330
|
-
loopId,
|
|
1331
|
-
turnId: request.turnId,
|
|
1371
|
+
workerId, loopId, turnId: request.turnId,
|
|
1332
1372
|
coordinate: `${request.workerName}-${request.loopSeq}-${request.seq}`,
|
|
1333
|
-
text: split.outside.
|
|
1334
|
-
tokens: split.outside.tokens,
|
|
1373
|
+
text: split.outside, tokens: contentWeight(split.outside),
|
|
1335
1374
|
});
|
|
1336
1375
|
}
|
|
1337
1376
|
// {§operator-grammar} — transport evidence only: the turn records whether the operator's
|
|
@@ -1387,7 +1426,7 @@ class TurnRunner {
|
|
|
1387
1426
|
fit: request.fit,
|
|
1388
1427
|
recoverableParseErrors: split.recoverableParseErrors,
|
|
1389
1428
|
emptyTurn: split.emptyTurn,
|
|
1390
|
-
|
|
1429
|
+
completionAllowed: split.completionAllowed,
|
|
1391
1430
|
bare: {
|
|
1392
1431
|
provider: childProvider,
|
|
1393
1432
|
loopSequence: request.loopSeq,
|
|
@@ -1398,6 +1437,22 @@ class TurnRunner {
|
|
|
1398
1437
|
onDispatch,
|
|
1399
1438
|
onSettled,
|
|
1400
1439
|
});
|
|
1440
|
+
// {§continued-without-note} — a turn the loop continues past or parks on, having carried no NOTE
|
|
1441
|
+
// forward in its program or from its reasoning, is told so in the next packet. An empty turn has
|
|
1442
|
+
// its own no-operation row instead.
|
|
1443
|
+
const ops = split.packetAssistant.ops;
|
|
1444
|
+
if ((executed.status === 102 || executed.status === 202) && ops.length > 0
|
|
1445
|
+
&& !ops.some((statement) => "op" in statement && statement.op === "NOTE")) {
|
|
1446
|
+
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1447
|
+
source: "engine:turn", kind: "continued_without_note", level: "warn", directive: DIRECTIVE.note, message: CONTINUED_WITHOUT_NOTE,
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
const annotationOnly = ops.length > 0 && ops.every((statement) => "op" in statement && statement.op === "NOTE");
|
|
1451
|
+
if ((executed.status === 102 || executed.status === 202) && annotationOnly) {
|
|
1452
|
+
this.#notices.push(workspaceId, workerId, loopId, {
|
|
1453
|
+
source: "engine:turn", kind: "noted_without_operation", level: "warn", directive: DIRECTIVE.note, message: NOTED_WITHOUT_OPERATION,
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1401
1456
|
return turnResult(request, executed.status, {
|
|
1402
1457
|
outcomes: executed.outcomes,
|
|
1403
1458
|
progressed: executed.progressed,
|
|
@@ -1460,10 +1515,9 @@ class TurnRunner {
|
|
|
1460
1515
|
const parseErrors = [];
|
|
1461
1516
|
let contentStatementCount = 0;
|
|
1462
1517
|
let hasUnparsedTail = false;
|
|
1518
|
+
let operationOmitted = false;
|
|
1463
1519
|
const parseNotices = [];
|
|
1464
1520
|
const fabrications = [];
|
|
1465
|
-
// {§outside-text}: every span outside an operation, verbatim and in source order; never an
|
|
1466
|
-
// operation of its own, so a repetitive or length-cut response stays one source.
|
|
1467
1521
|
const outside = [];
|
|
1468
1522
|
if (preParsedOps !== undefined) {
|
|
1469
1523
|
ops.push(...preParsedOps);
|
|
@@ -1479,13 +1533,33 @@ class TurnRunner {
|
|
|
1479
1533
|
span.setAttribute("statements", result.items.filter((item) => item.kind === "statement").length);
|
|
1480
1534
|
return result;
|
|
1481
1535
|
});
|
|
1536
|
+
// {§outside-text}: beside a fenced operation, the text between two operations is one NOTE at its
|
|
1537
|
+
// position, annotation the model wrote without its fence; a turn that fenced no operation keeps
|
|
1538
|
+
// its text as its outside source and stays an empty turn ({§empty-turn}). Echoed emission
|
|
1539
|
+
// headings are announcements, not annotation, and are dropped ({§fabricated-log-entry}).
|
|
1540
|
+
const fenced = parsed.items.filter((item) => item.kind === "statement").length;
|
|
1541
|
+
let span = null;
|
|
1542
|
+
const flushSpan = () => {
|
|
1543
|
+
if (span === null)
|
|
1544
|
+
return;
|
|
1545
|
+
const body = span.body.join("\n\n");
|
|
1546
|
+
if (body.length > 0) {
|
|
1547
|
+
if (fenced > 0) {
|
|
1548
|
+
ops.push({ op: "NOTE", aside: null, metadata: null, target: null, lineMarker: null, body, position: span.position });
|
|
1549
|
+
contentStatementCount += 1;
|
|
1550
|
+
}
|
|
1551
|
+
else
|
|
1552
|
+
outside.push(body);
|
|
1553
|
+
}
|
|
1554
|
+
span = null;
|
|
1555
|
+
};
|
|
1482
1556
|
for (const item of parsed.items) {
|
|
1557
|
+
if (item.kind !== "text")
|
|
1558
|
+
flushSpan();
|
|
1483
1559
|
if (item.kind === "statement") {
|
|
1484
1560
|
ops.push(item.statement);
|
|
1485
1561
|
contentStatementCount += 1;
|
|
1486
1562
|
}
|
|
1487
|
-
// Operation boundaries stay the parser's responsibility; what falls outside them is
|
|
1488
|
-
// stored as the turn's outside source and counted as nothing.
|
|
1489
1563
|
else if (item.kind === "text") {
|
|
1490
1564
|
// {§fabricated-log-entry}: a log-entry heading in outside text rejects the attempt.
|
|
1491
1565
|
const fabricated = FabricatedLog.find(item.content);
|
|
@@ -1493,16 +1567,22 @@ class TurnRunner {
|
|
|
1493
1567
|
fabrications.push({ message: FabricatedLog.message(fabricated.heading), line: item.position.line + fabricated.line, column: 1, source: "harness" });
|
|
1494
1568
|
continue;
|
|
1495
1569
|
}
|
|
1496
|
-
|
|
1570
|
+
const body = FabricatedLog.stripEchoes(item.content);
|
|
1571
|
+
if (body.length === 0)
|
|
1572
|
+
continue;
|
|
1573
|
+
span ??= { body: [], position: item.position };
|
|
1574
|
+
span.body.push(body);
|
|
1497
1575
|
}
|
|
1498
1576
|
else if (item.kind === "error") {
|
|
1499
1577
|
const err = item.error;
|
|
1500
1578
|
if (err instanceof PlurnkParseError) {
|
|
1579
|
+
operationOmitted ||= err.operationOmitted;
|
|
1501
1580
|
if (err.severity === "warning") {
|
|
1502
1581
|
parseNotices.push({
|
|
1503
1582
|
source: "grammar",
|
|
1504
1583
|
kind: "parse_advisory",
|
|
1505
1584
|
level: "warn",
|
|
1585
|
+
directive: DIRECTIVE.advisory,
|
|
1506
1586
|
message: err.message,
|
|
1507
1587
|
position: {
|
|
1508
1588
|
type: "content-offset",
|
|
@@ -1522,6 +1602,7 @@ class TurnRunner {
|
|
|
1522
1602
|
}
|
|
1523
1603
|
}
|
|
1524
1604
|
}
|
|
1605
|
+
flushSpan();
|
|
1525
1606
|
// {§unparsed-tail-boundary} — the lexer's one boundary fact: from `unparsedTail.from` on,
|
|
1526
1607
|
// nothing was read. The statements that closed before it are ordinary facts and run; the
|
|
1527
1608
|
// loss itself is one more hard diagnostic, a failed row the model sees. An emission that
|
|
@@ -1538,6 +1619,7 @@ class TurnRunner {
|
|
|
1538
1619
|
source: "grammar:reasoning",
|
|
1539
1620
|
kind: "parse_advisory",
|
|
1540
1621
|
level: "warn",
|
|
1622
|
+
directive: DIRECTIVE.advisory,
|
|
1541
1623
|
message: warning.message,
|
|
1542
1624
|
parserSource: warning.source,
|
|
1543
1625
|
});
|
|
@@ -1554,9 +1636,9 @@ class TurnRunner {
|
|
|
1554
1636
|
parseErrors.unshift(...fabrications.slice(0, 1));
|
|
1555
1637
|
const emissionStatements = preParsedOps === undefined && contentStatementCount > 0 ? [...ops] : null;
|
|
1556
1638
|
ops.unshift(...reasoningOps);
|
|
1557
|
-
const
|
|
1558
|
-
&&
|
|
1559
|
-
&& assistant.finishReason
|
|
1639
|
+
const completionAllowed = !hasUnparsedTail && !operationOmitted && !assistant.nativeToolCalls
|
|
1640
|
+
&& parseErrors.every((error) => error.message === PlurnkParser.NO_VALID_OPERATION)
|
|
1641
|
+
&& !["length", "content_filter", "tool_calls"].includes(assistant.finishReason ?? "");
|
|
1560
1642
|
const emptyTurn = preParsedOps === undefined && operationCount === 0 && !hasUnparsedTail;
|
|
1561
1643
|
// {§unparsed-tail-boundary}: outside text is not operational work.
|
|
1562
1644
|
const emissionValid = fabrications.length === 0 && (preParsedOps !== undefined
|
|
@@ -1565,7 +1647,6 @@ class TurnRunner {
|
|
|
1565
1647
|
const recoverableParseErrors = parseErrors
|
|
1566
1648
|
.filter((error) => error.message !== PlurnkParser.NO_VALID_OPERATION)
|
|
1567
1649
|
.toSorted(comparePosition);
|
|
1568
|
-
const outsideText = outside.join("\n\n");
|
|
1569
1650
|
return {
|
|
1570
1651
|
packetAssistant: { content: assistant.content, ops, reasoning },
|
|
1571
1652
|
sourceBacked: preParsedOps === undefined,
|
|
@@ -1573,10 +1654,10 @@ class TurnRunner {
|
|
|
1573
1654
|
parseErrors,
|
|
1574
1655
|
recoverableParseErrors: emissionValid ? recoverableParseErrors : [],
|
|
1575
1656
|
emptyTurn,
|
|
1576
|
-
|
|
1657
|
+
completionAllowed,
|
|
1577
1658
|
parseNotices,
|
|
1578
1659
|
emissionValid,
|
|
1579
|
-
outside: outside.length === 0 ? null :
|
|
1660
|
+
outside: outside.length === 0 ? null : outside.join("\n\n"),
|
|
1580
1661
|
emissionStatements,
|
|
1581
1662
|
};
|
|
1582
1663
|
}
|