@plurnk/plurnk-service 0.42.0 → 0.43.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.example +21 -3
- package/SPEC.md +1 -0
- package/bin/plurnk-service.ts +50 -7
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +2 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +84 -60
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +2 -0
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +16 -2
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/packet-wire.d.ts +30 -31
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +81 -80
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +3 -0
- package/dist/core/plurnk-uri.d.ts.map +1 -0
- package/dist/core/plurnk-uri.js +23 -0
- package/dist/core/plurnk-uri.js.map +1 -0
- package/dist/core/scheme-types.d.ts +4 -0
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/schemes/Plurnk.d.ts.map +1 -1
- package/dist/schemes/Plurnk.js +8 -4
- package/dist/schemes/Plurnk.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +2 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +6 -1
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +3 -1
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/clientTurn.d.ts.map +1 -1
- package/dist/server/clientTurn.js +1 -2
- package/dist/server/clientTurn.js.map +1 -1
- package/dist/server/envelope.d.ts +1 -0
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +9 -0
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/methods/loop_run.js +2 -2
- package/dist/server/methods/loop_run.js.map +1 -1
- package/dist/server/methods/session_rename.d.ts +5 -0
- package/dist/server/methods/session_rename.d.ts.map +1 -0
- package/dist/server/methods/session_rename.js +32 -0
- package/dist/server/methods/session_rename.js.map +1 -0
- package/migrations/0000-00-00.01_schema.sql +3 -5
- package/package.json +9 -34
- package/requirements.md +2 -8
package/.env.example
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
# --- Storage ---
|
|
7
7
|
PLURNK_DB_PATH=./plurnk.db
|
|
8
8
|
|
|
9
|
+
# --- Sqlite tuning (curated knobs passed through to sqlrite; optional) ---
|
|
10
|
+
# sqlrite already sets the safe posture (WAL + synchronous=NORMAL + busy_timeout=5000ms).
|
|
11
|
+
# These are operator overrides — integers; unset = sqlrite/sqlite default. Uncomment to tune.
|
|
12
|
+
# busy_timeout (ms): how long a writer waits on a lock before SQLITE_BUSY. 0 = immediate.
|
|
13
|
+
# PLURNK_SQLITE_TIMEOUT=5000
|
|
14
|
+
# cache_size: positive = pages, negative = KiB of memory. Bigger = fewer disk reads on a hot db.
|
|
15
|
+
# PLURNK_SQLITE_CACHE_SIZE=-16000
|
|
16
|
+
# mmap_size: bytes of memory-mapped I/O (read perf on large file-backed dbs). 0 disables.
|
|
17
|
+
# PLURNK_SQLITE_MMAP_SIZE=268435456
|
|
18
|
+
# max_page_count: hard db-size ceiling in PAGES — a write past it errors (disk-fill guard).
|
|
19
|
+
# PLURNK_SQLITE_MAX_PAGE_COUNT=524288
|
|
20
|
+
|
|
9
21
|
# --- Daemon transport ---
|
|
10
22
|
PLURNK_HOST=127.0.0.1
|
|
11
23
|
PLURNK_PORT=3044
|
|
@@ -89,6 +101,12 @@ PLURNK_GIT_AUTO=1
|
|
|
89
101
|
# session.create settings.manifestItems, which replaces this value (#231).
|
|
90
102
|
PLURNK_MANIFEST_ITEMS=-1
|
|
91
103
|
|
|
104
|
+
# Prompt-preview cap: the loop's prompt renders in user.prompt every turn, and a fat prompt
|
|
105
|
+
# replays each turn (bloat). Show the first N CHARS of the body + a pointer to the full
|
|
106
|
+
# prompt (always READable at its plurnk://prompt/<loop>/<seq> entry — nothing is lost).
|
|
107
|
+
# -1 = no cap (render the full prompt every turn). Default 512.
|
|
108
|
+
PLURNK_PROMPT_PREVIEW_CHARS=512
|
|
109
|
+
|
|
92
110
|
# Session-tier ceiling on CONCURRENT active runs (a run with a non-terminal loop)
|
|
93
111
|
# — the fork-bomb / destabilization brake. -1 = no cap (default); only concurrency
|
|
94
112
|
# is bounded, never lifetime, since sessions persist for months. A spawn/fork past
|
|
@@ -100,12 +118,12 @@ PLURNK_SESSION_RUNS_MAX_ACTIVE=-1
|
|
|
100
118
|
# fail-hard if unset — 0 = native reasoning off (in-DSL PLAN does the reasoning), -1 =
|
|
101
119
|
# adaptive / no cap, N = capped at N tokens. Provider modules translate it per model
|
|
102
120
|
# family (reasoning_effort tiers, budget_tokens). Floor (gemma): 0.
|
|
103
|
-
PLURNK_PROVIDERS_REASONING_BUDGET
|
|
121
|
+
PLURNK_PROVIDERS_REASONING_BUDGET=-1
|
|
104
122
|
#
|
|
105
123
|
# Planning: enable the grammar's <<PLAN:...:PLAN op so the model reasons in-band before
|
|
106
124
|
# acting. A shared universal knob (like PLURNK_FETCH_TIMEOUT below): the service advertises
|
|
107
125
|
# the op in # Plurnk System Tools; the provider reads it too. =1 on, =0 off.
|
|
108
|
-
PLURNK_PLAN=
|
|
126
|
+
PLURNK_PLAN=0
|
|
109
127
|
# Service-wide fetch timeout in ms — the universal upper bound on any
|
|
110
128
|
# single outbound request (provider calls, future http:// scheme reads,
|
|
111
129
|
# anything that does network IO). Streamed completions can run long;
|
|
@@ -122,7 +140,7 @@ PLURNK_VERSION_POLL_TTL=3600000
|
|
|
122
140
|
# /v1/models fingerprint) can only sample valid plurnk DSL; others drop it silently.
|
|
123
141
|
# A bare name (plurnk.gbnf) is a variant shipped by
|
|
124
142
|
# @plurnk/plurnk-grammar; an absolute/relative path is your own. =0 (or empty) disables.
|
|
125
|
-
PLURNK_PROVIDERS_GBNF=plurnk.gbnf
|
|
143
|
+
# PLURNK_PROVIDERS_GBNF=plurnk.gbnf
|
|
126
144
|
# Provider retry attempts (providers 0.7+): how many times generate() retries a
|
|
127
145
|
# TRANSIENT failure (429 rate-limit, 5xx/network) with exponential backoff (base 2s
|
|
128
146
|
# is a provider constant — the COUNT is the operator knob). REQUIRED, fail-hard if
|
package/SPEC.md
CHANGED
|
@@ -856,6 +856,7 @@ registry.register("loop.run", {
|
|
|
856
856
|
| `session.runs` | `id?: number` | `{ runs: Run[] }` | Lists runs in a session (defaults to attached session); most-recent first. |
|
|
857
857
|
| `session.prompts` | `id?: number`, `limit?: number` | `{ prompts: string[] }` | A session's prior user prompts (the conversation run's loop seeds), newest-first, capped by `limit` (default 100); defaults to attached session. Lets a client seed up/down recall without log archaeology. |
|
|
858
858
|
| `session.set_root` | `projectRoot: string \| null` | `{ projectRoot }` | Update the workspace pointer on the attached session. Null reverts to headless. |
|
|
859
|
+
| `session.rename` | `name: string` | `{ id, name }` | Rename the attached session — its name is a **mutable handle** on the world (unlike a run, whose name is frozen at instantiation, §machine-processes). Mutates `sessions.name` only; runs, log, and membership untouched. A name another session holds is rejected (`sessions.name` is unique). {§methods-session-rename} |
|
|
859
860
|
| `session.constrain` | `effect: "pick" \| "hide" \| "view" \| "repo"`, `glob: string` | `{ effect, glob }` | Add a workspace membership constraint (§membership overlay): `pick` admits a file git misses (the sole source when git is absent), `hide` drops a tracked match, `view` admits a member read-only (refused at the edit gate), `repo` declares a git repo folder anywhere so its members join the manifest. Immediate. |
|
|
860
861
|
| `session.unconstrain` | `effect: "pick" \| "hide" \| "view" \| "repo"`, `glob: string` | `{ effect, glob }` | Remove a membership constraint (the `drop` verb) — the inverse of `session.constrain`. Immediate. |
|
|
861
862
|
| `session.constraints` | none | `{ constraints }` | List the attached session's membership constraints. |
|
package/bin/plurnk-service.ts
CHANGED
|
@@ -24,10 +24,25 @@ export default class Cli {
|
|
|
24
24
|
try { process.loadEnvFile(path); }
|
|
25
25
|
catch (cause) { Cli.#die(64, `failed to load ${path}: ${cause instanceof Error ? cause.message : String(cause)}`); }
|
|
26
26
|
} else if (required) {
|
|
27
|
-
Cli.#die(64,
|
|
27
|
+
Cli.#die(64, `${path} does not exist`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// node-style env-file flags: --env-file=<path> (required) / --env-file-if-exists=<path>
|
|
32
|
+
// (skip if missing), repeatable, in command-line order. They layer extra files ABOVE
|
|
33
|
+
// the .env cascade but BELOW shell env (loadEnvFile is set-if-unset) and the --<knob>
|
|
34
|
+
// CLI flags (assigned last). The `=` form only — node's canonical syntax (so it never
|
|
35
|
+
// leaks a positional). NB: node validates these paths from the full argv (and exits on
|
|
36
|
+
// a missing *required* one), but only LOADS pre-script files — the post-script loading
|
|
37
|
+
// a published `plurnk-service --env-file=…` needs is this.
|
|
38
|
+
static #envFileArgs(): Array<{ path: string; required: boolean }> {
|
|
39
|
+
return process.argv.flatMap((a): Array<{ path: string; required: boolean }> => {
|
|
40
|
+
if (a.startsWith("--env-file-if-exists=")) return [{ path: a.slice(a.indexOf("=") + 1), required: false }];
|
|
41
|
+
if (a.startsWith("--env-file=")) return [{ path: a.slice(a.indexOf("=") + 1), required: true }];
|
|
42
|
+
return [];
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
31
46
|
// The .env cascade always populates these from .env.example, so absence is
|
|
32
47
|
// a broken config, not a runtime branch — fail hard rather than `?? ""`.
|
|
33
48
|
static #requireEnv(name: string): string {
|
|
@@ -36,11 +51,34 @@ export default class Cli {
|
|
|
36
51
|
return value;
|
|
37
52
|
}
|
|
38
53
|
|
|
54
|
+
// Optional integer sqlite tuning knob — undefined when unset (so it never clobbers
|
|
55
|
+
// sqlrite's default by spreading an explicit `undefined`); fail-hard on a non-integer.
|
|
56
|
+
static #sqliteKnob(name: string): number | undefined {
|
|
57
|
+
const raw = process.env[name];
|
|
58
|
+
if (raw === undefined || raw.trim() === "") return undefined;
|
|
59
|
+
const n = Number(raw);
|
|
60
|
+
if (!Number.isInteger(n)) Cli.#die(78, `${name} must be an integer, got ${JSON.stringify(raw)}`);
|
|
61
|
+
return n;
|
|
62
|
+
}
|
|
63
|
+
|
|
39
64
|
static async #openDb(dbPath: string): Promise<Db> {
|
|
65
|
+
// Curated sqlite tuning (sqlrite 5.2.0, #7) — pass through ONLY the knobs the
|
|
66
|
+
// operator set, so an unset one keeps sqlrite's default (e.g. busy_timeout=5000).
|
|
67
|
+
const tuning: Record<string, number> = {};
|
|
68
|
+
for (const [env, opt] of [
|
|
69
|
+
["PLURNK_SQLITE_TIMEOUT", "timeout"],
|
|
70
|
+
["PLURNK_SQLITE_CACHE_SIZE", "cacheSize"],
|
|
71
|
+
["PLURNK_SQLITE_MMAP_SIZE", "mmapSize"],
|
|
72
|
+
["PLURNK_SQLITE_MAX_PAGE_COUNT", "maxPageCount"],
|
|
73
|
+
] as const) {
|
|
74
|
+
const v = Cli.#sqliteKnob(env);
|
|
75
|
+
if (v !== undefined) tuning[opt] = v;
|
|
76
|
+
}
|
|
40
77
|
const db = await SqlRite.open({
|
|
41
78
|
path: dbPath,
|
|
42
79
|
dir: [resolve(Cli.#projectRoot, "migrations"), resolve(Cli.#projectRoot, "src")],
|
|
43
80
|
functions: [resolve(Cli.#projectRoot, "src/schemes/cosine.ts")],
|
|
81
|
+
...tuning,
|
|
44
82
|
});
|
|
45
83
|
return db as unknown as Db;
|
|
46
84
|
}
|
|
@@ -71,10 +109,13 @@ export default class Cli {
|
|
|
71
109
|
}
|
|
72
110
|
|
|
73
111
|
static async main(): Promise<void> {
|
|
74
|
-
// Env cascade
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
112
|
+
// Env cascade, highest precedence loads FIRST (loadEnvFile is set-if-unset,
|
|
113
|
+
// first write wins): --env-file(s) < --config < .env < .env.example, all of them
|
|
114
|
+
// OUTRANKED by pre-set shell env, then by the --<knob> CLI flags (assigned last,
|
|
115
|
+
// below). So --env-file overrides the .env files but never a shell var or a CLI
|
|
116
|
+
// arg — node-idiomatic layering.
|
|
117
|
+
for (const { path: envFile, required } of Cli.#envFileArgs()) Cli.#loadEnv(envFile, required);
|
|
118
|
+
|
|
78
119
|
const configFlagIndex = process.argv.findIndex((a) => a === "--config" || a.startsWith("--config="));
|
|
79
120
|
const configFile = ((): string | null => {
|
|
80
121
|
if (configFlagIndex === -1) return null;
|
|
@@ -97,8 +138,10 @@ export default class Cli {
|
|
|
97
138
|
|
|
98
139
|
${EnvFlags.formatFlagsHelp(flagDescriptors)}
|
|
99
140
|
|
|
100
|
-
--
|
|
101
|
-
-
|
|
141
|
+
--env-file=<path> layer env from <path> (repeatable; errors if missing)
|
|
142
|
+
--env-file-if-exists=<path> layer env from <path> if present (repeatable)
|
|
143
|
+
--config=<path> layer additional env from <path>
|
|
144
|
+
-h, --help show this help
|
|
102
145
|
`;
|
|
103
146
|
|
|
104
147
|
const { positionals, values } = parseArgs({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChannelWrite.d.ts","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ChannelWrite.d.ts","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// Helpers update entry_channels (content / state) and subscriptions, and emit
|
|
7
7
|
// stream/event notifications scoped to the entry's session via an optional
|
|
8
8
|
// callback the daemon wires in.
|
|
9
|
+
import { renderAddress } from "./plurnk-uri.js";
|
|
9
10
|
export default class ChannelWrite {
|
|
10
11
|
static #channelMeta(db) { return db.channel_meta; }
|
|
11
12
|
static #appendStmt(db) { return db.append_to_channel; }
|
|
@@ -19,7 +20,7 @@ export default class ChannelWrite {
|
|
|
19
20
|
// a filesystem entry (the file scheme stores scheme=NULL), so it decodes to
|
|
20
21
|
// file:///.
|
|
21
22
|
static #targetUri(scheme, pathname) {
|
|
22
|
-
return
|
|
23
|
+
return renderAddress(scheme === null ? "file" : scheme, pathname);
|
|
23
24
|
}
|
|
24
25
|
// A stream chunk accumulates into the channel's content (§chunk-accumulation-chunks-accumulate)
|
|
25
26
|
// and fires a stream/event (§live-updates-stream-event-fires-on-chunk); the log carries the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChannelWrite.js","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,sFAAsF;AACtF,EAAE;AACF,mFAAmF;AACnF,4FAA4F;AAC5F,8EAA8E;AAC9E,2EAA2E;AAC3E,gCAAgC;
|
|
1
|
+
{"version":3,"file":"ChannelWrite.js","sourceRoot":"","sources":["../../src/core/ChannelWrite.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAwF,MAAM,wBAAwB,CAAC;AAMpJ,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAiB,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
|
package/dist/core/Engine.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Mimetypes, emptyRegistry } from "@plurnk/plurnk-mimetypes";
|
|
|
4
4
|
import EntryCrud from "../schemes/_entry-crud.js";
|
|
5
5
|
import EntryManifest from "../schemes/_entry-manifest.js";
|
|
6
6
|
import GitMembership from "./git-membership.js";
|
|
7
|
+
import { foldAuthorityIntoPath, renderAddress } from "./plurnk-uri.js";
|
|
7
8
|
import GitState from "./git-state.js";
|
|
8
9
|
import Fork from "./fork.js";
|
|
9
10
|
import RunCap from "./run-cap.js";
|
|
@@ -538,10 +539,10 @@ class Engine {
|
|
|
538
539
|
const promptRow = await this.#db.engine_get_loop_prompt.get({ loop_id: loopId });
|
|
539
540
|
if (promptRow !== undefined && typeof promptRow.prompt === "string" && promptRow.prompt.length > 0) {
|
|
540
541
|
const promptPath = {
|
|
541
|
-
kind: "url", raw: `plurnk
|
|
542
|
+
kind: "url", raw: `plurnk://prompt/${loopId}/${seq}`,
|
|
542
543
|
scheme: "plurnk", username: null, password: null,
|
|
543
|
-
hostname:
|
|
544
|
-
pathname:
|
|
544
|
+
hostname: "prompt", port: null,
|
|
545
|
+
pathname: `/${loopId}/${seq}`, params: {}, fragment: null,
|
|
545
546
|
};
|
|
546
547
|
const promptStmt = {
|
|
547
548
|
op: "EDIT", suffix: "", signal: null,
|
|
@@ -554,9 +555,9 @@ class Engine {
|
|
|
554
555
|
sequence: nextActionIndex, origin: "plurnk",
|
|
555
556
|
onDispatch: (id) => { promptLogId = id; onDispatch?.(id); },
|
|
556
557
|
});
|
|
557
|
-
// §prompt-fold (User Note 6): the prompt EDIT duplicates
|
|
558
|
-
//
|
|
559
|
-
//
|
|
558
|
+
// §prompt-fold (User Note 6): the prompt EDIT duplicates the
|
|
559
|
+
// prompt section, so fold it — logged for forensics, collapsed
|
|
560
|
+
// in the model's log, re-OPENable.
|
|
560
561
|
if (promptLogId !== undefined)
|
|
561
562
|
await this.#db.engine_fold_log_entry.run({ id: promptLogId });
|
|
562
563
|
nextActionIndex++;
|
|
@@ -659,7 +660,7 @@ class Engine {
|
|
|
659
660
|
// grammar can't bound degeneration *inside* a statement body — this caps the
|
|
660
661
|
// decode at the free window so a runaway can't reach the context wall.
|
|
661
662
|
const genCeiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling); // provider.contextSize, the immutable identity, read by the budget — §provider-surface-identity
|
|
662
|
-
const maxTokens = genCeiling === null ? undefined : Math.max(1, genCeiling - requestPacket.
|
|
663
|
+
const maxTokens = genCeiling === null ? undefined : Math.max(1, genCeiling - requestPacket.tokens);
|
|
663
664
|
const response = await provider.generate({ messages: modelMessages, runId: String(runId), signal, grammar: await this.#grammarConstraint(), maxTokens }); // §provider-surface-generate §provider-guarantees-single-call §provider-guarantees-signal-wired
|
|
664
665
|
// Engine splits wire-level response: emission (content, reasoning,
|
|
665
666
|
// parsed ops) → packet.assistant per Packet.json §assistant;
|
|
@@ -853,14 +854,15 @@ class Engine {
|
|
|
853
854
|
// scheme-agnostic, so the service teaches what schemes exist + what they do
|
|
854
855
|
// at packet-time (grammar#239 item 7). SchemeRegistry.teach() assembles it.
|
|
855
856
|
const system_definition = `${byRole("system")}\n\n${this.#schemes.teach()}`;
|
|
856
|
-
//
|
|
857
|
+
// the prompt section sources from the loop's most recent prompt entry first
|
|
857
858
|
// (plurnk:///prompt/<loop_id>/<N> for the highest N written to date).
|
|
858
859
|
// This is what inject + the turn-1 foist write into. Falls back to
|
|
859
860
|
// the runLoop caller's messages.user for tests that bypass the
|
|
860
861
|
// foist mechanism entirely.
|
|
861
|
-
const latestPromptRow = await this.#db.drain_get_latest_prompt_body_for_loop.get({ pattern:
|
|
862
|
+
const latestPromptRow = await this.#db.drain_get_latest_prompt_body_for_loop.get({ pattern: `/prompt/${loopId}/%` });
|
|
863
|
+
const promptCap = Number.parseInt(process.env.PLURNK_PROMPT_PREVIEW_CHARS ?? "", 10);
|
|
862
864
|
const prompt = (latestPromptRow !== undefined && typeof latestPromptRow.content === "string" && latestPromptRow.content.length > 0)
|
|
863
|
-
? latestPromptRow.content
|
|
865
|
+
? PacketWire.previewPrompt(latestPromptRow.content, renderAddress("plurnk", latestPromptRow.pathname), Number.isInteger(promptCap) ? promptCap : -1)
|
|
864
866
|
: byRole("user");
|
|
865
867
|
// Requirements is engine-sourced, NOT threaded from callers — that threading is
|
|
866
868
|
// exactly how it went missing (callers read the sysprompt but never the
|
|
@@ -874,65 +876,82 @@ class Engine {
|
|
|
874
876
|
const requirementsText = `Syntax: <<OPsuffix[signal]?(target)?<Line/Result>?:body?:OPsuffix\n\n${planDirective}${baseRequirements}`;
|
|
875
877
|
const log = await this.#buildLog(runId);
|
|
876
878
|
const telemetryErrors = presetTelemetry ?? await this.#buildTelemetryErrors(loopId, currentTurnSeq);
|
|
877
|
-
// Per-section render-cost subtotals via provider's tokenizer.
|
|
878
|
-
// Engine approximates each section by tokenizing its serialized
|
|
879
|
-
// form — wire-payload tokens may differ slightly because chat-
|
|
880
|
-
// template scaffolding adds bytes, but the subtotal tracks "what
|
|
881
|
-
// the model has to process" closely enough for budget diagnostics.
|
|
882
879
|
const countTokens = (t) => provider.countTokens(t); // §provider-surface-counttokens
|
|
883
|
-
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
//
|
|
888
|
-
//
|
|
889
|
-
//
|
|
880
|
+
const tools = this.#collectTools();
|
|
881
|
+
// Budget readout (SPEC.md §tokenomics). Two-pass: render the budget from
|
|
882
|
+
// the structured log's subtotals with a {{tokensFree}} placeholder, build
|
|
883
|
+
// the section list, measure the assembled total, resolve free, substitute.
|
|
884
|
+
// Subtotals come from the real log render — meta and fences included — not
|
|
885
|
+
// a serialized approximation. ceiling is the provider's window ×
|
|
886
|
+
// PLURNK_BUDGET_CEILING (null when no window is reported → headline
|
|
887
|
+
// omitted, section lines still shown). §tokenomics-render-weight-budget
|
|
890
888
|
const ceiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling);
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
889
|
+
const budgetReadout = this.#renderBudget(PacketWire.measureLogBudget(log, countTokens), ceiling);
|
|
890
|
+
// The default packet: an ordered list of sections, each addressable state
|
|
891
|
+
// (§packet-construction). `slot` is the prompt-cache boundary; order within
|
|
892
|
+
// a slot is the render order (requirements last — the contract closest to
|
|
893
|
+
// the assistant turn). budget/errors/git are peer sections (unbundled —
|
|
894
|
+
// each independently overridable). The budget section still carries its
|
|
895
|
+
// {{tokensFree}} placeholders here; they resolve below once the assembled
|
|
896
|
+
// total is known.
|
|
897
|
+
const defaults = [
|
|
898
|
+
{ name: "definition", slot: "system", header: null, content: system_definition, tokens: 0 },
|
|
899
|
+
{ name: "log", slot: "system", header: "Plurnk System Log", content: PacketWire.renderLog(log), tokens: 0 },
|
|
900
|
+
{ name: "prompt", slot: "user", header: "Plurnk System User Prompt", content: prompt, tokens: 0 },
|
|
901
|
+
{ name: "budget", slot: "user", header: "Plurnk System Budget", content: budgetReadout, tokens: 0 },
|
|
902
|
+
{ name: "errors", slot: "user", header: "Plurnk System Errors", content: PacketWire.renderErrors(telemetryErrors), tokens: 0 },
|
|
903
|
+
{ name: "git", slot: "user", header: "Plurnk System Git Status", content: PacketWire.renderGit(gitStatus), tokens: 0 },
|
|
904
|
+
{ name: "tools", slot: "user", header: "Plurnk System Tools", content: tools.join("\n"), tokens: 0 },
|
|
905
|
+
{ name: "requirements", slot: "user", header: "Plurnk System Requirements", content: requirementsText, tokens: 0 },
|
|
906
|
+
];
|
|
907
|
+
// Plugin packet control (§packet-construction): trusted schemes rewrite the
|
|
908
|
+
// default list — add, remove, reorder — in-process, before measurement.
|
|
909
|
+
const sections = await this.#schemes.transformSections(defaults);
|
|
910
|
+
// Pass 1: measure the assembled total with the placeholder budget in
|
|
911
|
+
// place, resolve free/percent, substitute into the budget section.
|
|
912
|
+
const total = countTokens(PacketWire.renderSlot(sections, "system")) + countTokens(PacketWire.renderSlot(sections, "user"));
|
|
898
913
|
const tokensFree = ceiling === null ? null : Math.max(0, ceiling - total); // free floors at 0 on overshoot — §tokenomics-over-budget-floor
|
|
899
914
|
const percent = ceiling === null ? null : Math.round((total / ceiling) * 100); // usage as % of the ceiling — §tokenomics-context-percent
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
.
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
915
|
+
if (tokensFree !== null) {
|
|
916
|
+
const budgetSec = sections.find((s) => s.name === "budget"); // a plugin may have removed it
|
|
917
|
+
if (budgetSec) {
|
|
918
|
+
budgetSec.content = budgetSec.content
|
|
919
|
+
.replace(TOKEN_USAGE_PLACEHOLDER, String(total))
|
|
920
|
+
.replace(TOKEN_PERCENT_PLACEHOLDER, percent === 0 && total > 0 ? "<1" : String(percent))
|
|
921
|
+
.replace(TOKENS_FREE_PLACEHOLDER, String(tokensFree));
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
// Pass 2: per-section render-weight + the assembled packet total (post
|
|
925
|
+
// substitution — the placeholder/number length delta is negligible).
|
|
926
|
+
for (const s of sections)
|
|
927
|
+
s.tokens = countTokens(PacketWire.renderSection(s));
|
|
928
|
+
const packetTokens = countTokens(PacketWire.renderSlot(sections, "system")) + countTokens(PacketWire.renderSlot(sections, "user"));
|
|
929
|
+
return { tokens: packetTokens, sections, telemetryErrors };
|
|
911
930
|
}
|
|
912
931
|
// Budget readout body, rendered into the `# Plurnk System Budget` section.
|
|
913
932
|
// Headline `ceiling/free` only when a ceiling exists; section lines for the
|
|
914
933
|
// curatable index/log weight the model can FOLD back. tokensFree is a
|
|
915
934
|
// placeholder here — buildSystem substitutes it after measuring the packet.
|
|
916
|
-
#renderBudget(
|
|
935
|
+
#renderBudget(log, ceiling) {
|
|
917
936
|
const lines = [];
|
|
918
937
|
if (ceiling !== null)
|
|
919
938
|
lines.push(`ceiling ${ceiling} · usage ${TOKEN_USAGE_PLACEHOLDER} (${TOKEN_PERCENT_PLACEHOLDER}%) · free ${TOKENS_FREE_PLACEHOLDER}`);
|
|
920
|
-
if (
|
|
921
|
-
lines.push(`Log entries: ${
|
|
939
|
+
if (log.entries > 0) {
|
|
940
|
+
lines.push(`Log entries: ${log.entries} entries, ${log.tokens} tokens`);
|
|
922
941
|
// Per-turn weight — the grinder's rollback unit, oldest first: the
|
|
923
942
|
// model sees what's first to go (§tokenomics {§tokenomics-turn-totals}).
|
|
924
|
-
if (
|
|
943
|
+
if (log.byTurn.length > 0) {
|
|
925
944
|
lines.push("Turns:", "| turn | tokens |", "|---|--:|");
|
|
926
|
-
for (const t of
|
|
945
|
+
for (const t of log.byTurn)
|
|
927
946
|
lines.push(`| ${t.turn} | ${t.tokens} |`);
|
|
928
947
|
}
|
|
929
948
|
// The heaviest individual log items — the FOLD targets behind the weight
|
|
930
949
|
// (§tokenomics {§tokenomics-largest-entries}). "items", not "entries": the readout
|
|
931
950
|
// lists log:/// rows (log items), distinct from catalog entries (plurnk.md: "EDIT
|
|
932
951
|
// is only for entries. Do not attempt to edit log items.").
|
|
933
|
-
if (
|
|
952
|
+
if (log.largest.length > 0) {
|
|
934
953
|
lines.push("Heaviest items:", "| item | tokens |", "|---|--:|");
|
|
935
|
-
for (const e of
|
|
954
|
+
for (const e of log.largest)
|
|
936
955
|
lines.push(`| ${e.path} | ${e.tokens} |`);
|
|
937
956
|
}
|
|
938
957
|
}
|
|
@@ -958,16 +977,16 @@ class Engine {
|
|
|
958
977
|
const entry = this.#executors.entry(tag);
|
|
959
978
|
if (entry?.example)
|
|
960
979
|
tools.push(`* ${entry.example}`);
|
|
961
|
-
// #note12 — link the executor's fuller doc (materialized at plurnk:///docs/<tag
|
|
980
|
+
// #note12 — link the executor's fuller doc (materialized at plurnk:///docs/<tag>.md);
|
|
962
981
|
// its token cost rides that manifest entry, so no inline recount here.
|
|
963
982
|
if (entry?.documentation)
|
|
964
|
-
tools.push(`* docs for ${tag}: plurnk
|
|
983
|
+
tools.push(`* docs for ${tag}: plurnk://docs/${tag}.md`);
|
|
965
984
|
}
|
|
966
985
|
}
|
|
967
986
|
return tools;
|
|
968
987
|
}
|
|
969
988
|
// #note12 — the daughter-provided reference docs (schemes' + execs' `documentation`),
|
|
970
|
-
// materialized at plurnk:///docs/<name
|
|
989
|
+
// materialized at plurnk:///docs/<name>.md by loop_run (like operator docs) so the
|
|
971
990
|
// catalogue's doc-links READ and the manifest carries each doc's token cost.
|
|
972
991
|
docEntries() {
|
|
973
992
|
const out = this.#schemes.docs();
|
|
@@ -988,7 +1007,7 @@ class Engine {
|
|
|
988
1007
|
// §grinder-overflow-only — fires only on actual overflow, never speculatively
|
|
989
1008
|
async #enforceBudget({ packet, provider, runId, loopId, turnId, sessionId, turnNumber, rebuild }) {
|
|
990
1009
|
const ceiling = _a.computeCeiling(provider.contextSize, this.#budgetCeiling);
|
|
991
|
-
const measure = (p) => p.
|
|
1010
|
+
const measure = (p) => p.tokens;
|
|
992
1011
|
if (ceiling === null || measure(packet) <= ceiling)
|
|
993
1012
|
return { packet, fit: true, struck: false };
|
|
994
1013
|
const folded = new Map();
|
|
@@ -1000,7 +1019,7 @@ class Engine {
|
|
|
1000
1019
|
note(le.scheme ?? "log");
|
|
1001
1020
|
if (priorLogs.length > 0)
|
|
1002
1021
|
await this.#db.engine_grinder_fold_prior_turn_logs.run({ loop_id: loopId, turn_id: turnId });
|
|
1003
|
-
const errors = packet.
|
|
1022
|
+
const errors = packet.telemetryErrors;
|
|
1004
1023
|
let current = priorLogs.length > 0 ? await rebuild(errors) : packet;
|
|
1005
1024
|
if (measure(current) <= ceiling) {
|
|
1006
1025
|
this.#emitBudgetOverflow(sessionId, loopId, folded);
|
|
@@ -1037,9 +1056,9 @@ class Engine {
|
|
|
1037
1056
|
#completePacket(requestPacket, assistant, assistantRaw, provider) {
|
|
1038
1057
|
const assistantTokens = provider.countTokens(assistant.content);
|
|
1039
1058
|
return {
|
|
1040
|
-
tokens: requestPacket.
|
|
1041
|
-
|
|
1042
|
-
|
|
1059
|
+
tokens: requestPacket.tokens + assistantTokens,
|
|
1060
|
+
sections: requestPacket.sections,
|
|
1061
|
+
telemetryErrors: requestPacket.telemetryErrors,
|
|
1043
1062
|
assistant,
|
|
1044
1063
|
assistantRaw,
|
|
1045
1064
|
};
|
|
@@ -1074,7 +1093,7 @@ class Engine {
|
|
|
1074
1093
|
});
|
|
1075
1094
|
return [...this.#drainTelemetry(loopId), ...actionFailures];
|
|
1076
1095
|
}
|
|
1077
|
-
// SPEC §packet
|
|
1096
|
+
// SPEC §packet the log section — chronological action-entries for the loop.
|
|
1078
1097
|
// Snapshot is taken at packet build (pre-dispatch this turn), so it
|
|
1079
1098
|
// reflects "what has happened before this turn." Each row carries a
|
|
1080
1099
|
// log:///<loop_seq>/<turn_seq>/<sequence> coordinate the model can READ.
|
|
@@ -1404,8 +1423,8 @@ class Engine {
|
|
|
1404
1423
|
return (row?.n ?? 0) > 0;
|
|
1405
1424
|
}
|
|
1406
1425
|
// Inject a prompt into the run's currently-executing loop. Writes a
|
|
1407
|
-
// plurnk:///prompt/<loop_id>/<next-turn> entry whose body becomes
|
|
1408
|
-
//
|
|
1426
|
+
// plurnk:///prompt/<loop_id>/<next-turn> entry whose body becomes the
|
|
1427
|
+
// prompt section at the next turn boundary. Last-wins: if two
|
|
1409
1428
|
// injects target the same next-turn slot, the second overwrites the
|
|
1410
1429
|
// first.
|
|
1411
1430
|
//
|
|
@@ -1425,7 +1444,7 @@ class Engine {
|
|
|
1425
1444
|
const sessionRow = await this.#db.drain_get_run_session.get({ run_id: runId });
|
|
1426
1445
|
if (sessionRow === undefined)
|
|
1427
1446
|
throw new Error(`Engine.inject: run ${runId} not found`);
|
|
1428
|
-
const pathname =
|
|
1447
|
+
const pathname = `/prompt/${loopId}/${turnSeq}`; // canonical storage form (leading slash), matching the foist via #pathnameOf
|
|
1429
1448
|
const ctx = {
|
|
1430
1449
|
db: this.#db, sessionId: sessionRow.session_id, runId, loopId,
|
|
1431
1450
|
turnId: 0, // no turn open at inject time; entries don't pin turnId
|
|
@@ -1955,9 +1974,14 @@ class Engine {
|
|
|
1955
1974
|
if (path.kind === "local")
|
|
1956
1975
|
return { scheme: null, username: null, password: null, hostname: null, port: null, pathname: decodePathParens(path.raw), params: null, fragment: null }; // #239 item 4
|
|
1957
1976
|
const scheme = path.scheme === "file" ? null : path.scheme;
|
|
1977
|
+
// plurnk uses its authority as a namespace — fold it into the canonical pathname so the
|
|
1978
|
+
// log keys identically to the entry (/prompt/<loop>, /docs/x.md). A web host (http://) is
|
|
1979
|
+
// NOT a namespace: keep it in hostname.
|
|
1980
|
+
const foldNs = scheme === "plurnk";
|
|
1958
1981
|
return {
|
|
1959
1982
|
scheme, username: path.username, password: path.password,
|
|
1960
|
-
hostname: path.hostname, port: path.port,
|
|
1983
|
+
hostname: foldNs ? null : path.hostname, port: path.port,
|
|
1984
|
+
pathname: decodePathParens(foldNs ? foldAuthorityIntoPath(path.hostname, path.pathname) : path.pathname), // #239 item 4
|
|
1961
1985
|
params: JSON.stringify(path.params), fragment: path.fragment,
|
|
1962
1986
|
};
|
|
1963
1987
|
}
|