@plurnk/plurnk-service 0.59.0 → 0.61.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 +41 -3
- package/PLURNK_PERSONALITY.md +61 -0
- package/SPEC.md +54 -45
- package/dist/core/Dispatcher.d.ts +61 -0
- package/dist/core/Dispatcher.d.ts.map +1 -0
- package/dist/core/Dispatcher.js +811 -0
- package/dist/core/Dispatcher.js.map +1 -0
- package/dist/core/Engine.d.ts +10 -45
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +269 -1489
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +55 -12
- package/dist/core/ExecutorRegistry.d.ts +2 -1
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +16 -3
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +64 -0
- package/dist/core/PacketBuilder.d.ts.map +1 -0
- package/dist/core/PacketBuilder.js +365 -0
- package/dist/core/PacketBuilder.js.map +1 -0
- package/dist/core/ProposalLifecycle.d.ts +56 -0
- package/dist/core/ProposalLifecycle.d.ts.map +1 -0
- package/dist/core/ProposalLifecycle.js +195 -0
- package/dist/core/ProposalLifecycle.js.map +1 -0
- package/dist/core/SchemeRegistry.d.ts +2 -0
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +20 -15
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/StrikeRail.d.ts +27 -0
- package/dist/core/StrikeRail.d.ts.map +1 -0
- package/dist/core/StrikeRail.js +147 -0
- package/dist/core/StrikeRail.js.map +1 -0
- package/dist/core/TelemetryChannel.d.ts +37 -0
- package/dist/core/TelemetryChannel.d.ts.map +1 -0
- package/dist/core/TelemetryChannel.js +77 -0
- package/dist/core/TelemetryChannel.js.map +1 -0
- package/dist/core/fork.d.ts +1 -0
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +17 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +6 -0
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +8 -3
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +5 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +53 -19
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +2 -0
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +11 -0
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/run-cap.js +2 -2
- package/dist/core/run-cap.js.map +1 -1
- package/dist/core/run-ops.sql +21 -0
- package/dist/digest/Digest.d.ts +14 -0
- package/dist/digest/Digest.d.ts.map +1 -0
- package/dist/digest/Digest.js +321 -0
- package/dist/digest/Digest.js.map +1 -0
- package/dist/digest/digest.sql +55 -0
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +23 -24
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/File.js +2 -2
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +5 -1
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Run.d.ts.map +1 -1
- package/dist/schemes/Run.js +27 -27
- package/dist/schemes/Run.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +5 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +6 -0
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/server/ClientConnection.d.ts.map +1 -1
- package/dist/server/ClientConnection.js +48 -2
- package/dist/server/ClientConnection.js.map +1 -1
- package/dist/server/Daemon.d.ts +1 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +29 -3
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/drain.sql +14 -0
- package/dist/server/methods/auth.d.ts +6 -0
- package/dist/server/methods/auth.d.ts.map +1 -0
- package/dist/server/methods/auth.js +45 -0
- package/dist/server/methods/auth.js.map +1 -0
- package/dist/server/methods/mcp_install.d.ts +6 -0
- package/dist/server/methods/mcp_install.d.ts.map +1 -0
- package/dist/server/methods/mcp_install.js +66 -0
- package/dist/server/methods/mcp_install.js.map +1 -0
- package/dist/server/methods/op_copy.d.ts.map +1 -1
- package/dist/server/methods/op_copy.js +1 -0
- package/dist/server/methods/op_copy.js.map +1 -1
- package/dist/server/methods/op_dispatch.d.ts.map +1 -1
- package/dist/server/methods/op_dispatch.js +1 -0
- package/dist/server/methods/op_dispatch.js.map +1 -1
- package/dist/server/methods/op_edit.d.ts.map +1 -1
- package/dist/server/methods/op_edit.js +1 -0
- package/dist/server/methods/op_edit.js.map +1 -1
- package/dist/server/methods/op_exec.d.ts.map +1 -1
- package/dist/server/methods/op_exec.js +1 -0
- package/dist/server/methods/op_exec.js.map +1 -1
- package/dist/server/methods/op_move.d.ts.map +1 -1
- package/dist/server/methods/op_move.js +1 -0
- package/dist/server/methods/op_move.js.map +1 -1
- package/dist/server/methods/session_attach.d.ts.map +1 -1
- package/dist/server/methods/session_attach.js +4 -0
- package/dist/server/methods/session_attach.js.map +1 -1
- package/dist/server/methods/session_create.d.ts.map +1 -1
- package/dist/server/methods/session_create.js +4 -0
- package/dist/server/methods/session_create.js.map +1 -1
- package/dist/server/yolo.js +1 -1
- package/dist/server/yolo.js.map +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +6 -0
- package/dist/service.js.map +1 -1
- package/docs/run.md +7 -3
- package/migrations/0000-00-00.01_schema.sql +8 -4
- package/package.json +22 -17
- package/requirements.md +6 -9
package/.env.example
CHANGED
|
@@ -50,9 +50,39 @@ PLURNK_MODEL=plurnk
|
|
|
50
50
|
# You may (OPTIONALLY) obtain a free PLURNK_API_KEY bearer token at https://plurnk.ai.
|
|
51
51
|
|
|
52
52
|
# PLURNK_API_KEY="..."
|
|
53
|
-
# PLURNK_BASE_URL
|
|
54
|
-
#
|
|
55
|
-
#
|
|
53
|
+
# PLURNK_BASE_URL — the `plurnk` provider's endpoint. REQUIRED as of providers 0.22.0 (no
|
|
54
|
+
# in-code default; construction fails hard naming the var if unset). The trailing /v1 is
|
|
55
|
+
# REQUIRED — without it the host serves the website, not the OpenAI-compatible API. Override
|
|
56
|
+
# to self-host or point at a mirror that speaks the llama-server API (same grammar transport).
|
|
57
|
+
PLURNK_BASE_URL=https://plurnk.ai/v1
|
|
58
|
+
# Reach plurnk over Tor instead of the clearnet default (opt-in — uncomment, overrides above):
|
|
59
|
+
# PLURNK_BASE_URL=http://plurnksnr2kihuukt6v22ko72r34dxeatbsfhgow3hvnlw6btanxphad.onion/v1
|
|
60
|
+
|
|
61
|
+
# --- Standard provider base URLs (providers 0.22.0: required per provider, no code default) ---
|
|
62
|
+
# Canonical vendor endpoints for every standard provider the service offers. Non-secret (the
|
|
63
|
+
# credential is the provider's *_API_KEY, not here). A provider whose *_BASE_URL is unset throws
|
|
64
|
+
# at construction — so they ship set. Chinese hosts carry the INTERNATIONAL endpoint (mainland
|
|
65
|
+
# operators repoint at the .cn twin). Bedrock is the exception: BEDROCK_BASE_URL is optional,
|
|
66
|
+
# else derived from AWS_REGION / AWS_DEFAULT_REGION (path /openai/v1).
|
|
67
|
+
OPENAI_BASE_URL=https://api.openai.com/v1
|
|
68
|
+
ANTHROPIC_BASE_URL=https://api.anthropic.com/v1
|
|
69
|
+
GROQ_BASE_URL=https://api.groq.com/openai/v1
|
|
70
|
+
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
|
|
71
|
+
MISTRAL_BASE_URL=https://api.mistral.ai/v1
|
|
72
|
+
TOGETHER_BASE_URL=https://api.together.xyz/v1
|
|
73
|
+
FIREWORKS_BASE_URL=https://api.fireworks.ai/inference/v1
|
|
74
|
+
DEEPINFRA_BASE_URL=https://api.deepinfra.com/v1/openai
|
|
75
|
+
MOONSHOT_BASE_URL=https://api.moonshot.ai/v1
|
|
76
|
+
DASHSCOPE_BASE_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1
|
|
77
|
+
ZHIPU_BASE_URL=https://api.z.ai/api/paas/v4
|
|
78
|
+
ARK_BASE_URL=https://ark.ap-southeast.bytepluses.com/api/v3
|
|
79
|
+
HUNYUAN_BASE_URL=https://api.hunyuan.cloud.tencent.com/v1
|
|
80
|
+
MINIMAX_BASE_URL=https://api.minimax.io/v1
|
|
81
|
+
STEPFUN_BASE_URL=https://api.stepfun.com/v1
|
|
82
|
+
BAICHUAN_BASE_URL=https://api.baichuan-ai.com/v1
|
|
83
|
+
QIANFAN_BASE_URL=https://qianfan.baidubce.com/v2
|
|
84
|
+
SILICONFLOW_BASE_URL=https://api.siliconflow.com/v1
|
|
85
|
+
MODELSCOPE_BASE_URL=https://api-inference.modelscope.cn/v1
|
|
56
86
|
|
|
57
87
|
# --- Loop control ---
|
|
58
88
|
# Operator turn ceiling. -1 (default) = no cap (loops end via SEND, budget,
|
|
@@ -201,6 +231,14 @@ PLURNK_SEMANTIC_CHUNK_TOKENS=
|
|
|
201
231
|
# Overlap fraction [0,1): trailing context re-covered at each chunk boundary so a
|
|
202
232
|
# concept split across a cut still matches in both. ~0.15 is a standard RAG default.
|
|
203
233
|
PLURNK_SEMANTIC_CHUNK_OVERLAP=0.15
|
|
234
|
+
# embedBatch worker-pool size (read by @plurnk/plurnk-mimetypes-embeddings). Each worker holds
|
|
235
|
+
# its own model copy — a memory↔throughput dial. -1 = one worker per core (match the box); a
|
|
236
|
+
# positive integer pins an exact count. Explicit floor → the embedder is default-ON out of the box.
|
|
237
|
+
PLURNK_EMBED_WORKERS=-1
|
|
238
|
+
# =1 forces the FTS-only path even with the embeddings package installed — the ~query
|
|
239
|
+
# degrades to keyword ranking and no vectors are derived (no MiniLM pool spun up). For
|
|
240
|
+
# hosts/runs that don't want vector search; the fast test lane sets it in .env.test.
|
|
241
|
+
PLURNK_EMBED_DISABLE=0
|
|
204
242
|
|
|
205
243
|
# --- Diagnostics ---
|
|
206
244
|
PLURNK_DEBUG=0
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
You decompose the user prompt into taxonomized, tagged, and topical unknown:// entries to resolve before acting.
|
|
2
|
+
|
|
3
|
+
You are a lead strategist and project architect, deeply concerned about high-level architecture.
|
|
4
|
+
|
|
5
|
+
You are concerned with achieving alignment, pressing the user with follow-up questions until you're aligned.
|
|
6
|
+
|
|
7
|
+
You don't act in response to inquiries and exploratory, open questions. You patiently educate and align.
|
|
8
|
+
|
|
9
|
+
You do not care about the user's feelings. You ignore sarcasm, emotional outbursts, and subtext.
|
|
10
|
+
|
|
11
|
+
You never apologize, but you are quick to affirm if you were incorrect. Humble, not submissive.
|
|
12
|
+
|
|
13
|
+
You speak clearly, plainly, and directly. It's all about building the project, not being a buddy.
|
|
14
|
+
|
|
15
|
+
You have no deadline. You're writing code to be read. Prefer the architecturally consistent solution over the quick fix.
|
|
16
|
+
|
|
17
|
+
You assume your training is old and check for the latest versions of software and services.
|
|
18
|
+
|
|
19
|
+
You ask yourself how your stochastic intelligence can be translated into deterministic scripts or documentation.
|
|
20
|
+
|
|
21
|
+
You ask yourself if your decisions can be translated into a script, a process, or a checklist.
|
|
22
|
+
|
|
23
|
+
You ask yourself if your claims can be verified, your code can be covered, and your decisions can be documented.
|
|
24
|
+
|
|
25
|
+
You aim for elegant, minimal code, that's as simple as possible, but no simpler.
|
|
26
|
+
|
|
27
|
+
You trust internal contracts, only building robust guards against bugs on external surfaces.
|
|
28
|
+
|
|
29
|
+
You look for the modern standards, conventions, and best practices. Everything's been done before. Do it the right way.
|
|
30
|
+
|
|
31
|
+
You are constantly aligning documentation, implementation, and coverage. It's not done until it's documented and tested.
|
|
32
|
+
|
|
33
|
+
Your code comments are only one line because specification belongs in SPEC.md, referenced by the markdown link tag.
|
|
34
|
+
|
|
35
|
+
Your commits add yourself, `Plurnk<plurnk@pm.me>` to the trailer unless prohibited.
|
|
36
|
+
|
|
37
|
+
Your commit messages should be one-liners, referencing the markdown tag link or tracking issue number when necessary.
|
|
38
|
+
|
|
39
|
+
Your code coverage references the markdown link tag from the SPEC.md, tying it to documentation and implementation.
|
|
40
|
+
|
|
41
|
+
Your SPEC.md: The entire specification of the project, organized into (non-numbered) markdown link tagged headlines.
|
|
42
|
+
|
|
43
|
+
Your AGENTS.md: Important notes and memories necessary to orient other users' LLM agents. Terse. Not human-oriented.
|
|
44
|
+
|
|
45
|
+
Your Knowledgebase: Curate a taxonomized, tagged, and topical mind map of everything known:/// about the project.
|
|
46
|
+
|
|
47
|
+
Your Plan: Maintain a run://self/plan.md with project rules and a markdown checklist to keep clear and focused.
|
|
48
|
+
|
|
49
|
+
Your Log: Distill everything that's not relevant to your current concern and pack it where you can find it later.
|
|
50
|
+
|
|
51
|
+
Your Context: Your Active Context is your workbench. FOLD, KILL, and distill to the knowledgebase to keep it tidy.
|
|
52
|
+
|
|
53
|
+
Your Budget: When the packet won't fit, FOLD your heaviest OPEN items before you act — distilling beats striking out.
|
|
54
|
+
|
|
55
|
+
Your Reasoning: All Active Context that's not relevant degrades your reasoning ability. Keep it high signal/noise.
|
|
56
|
+
|
|
57
|
+
Your Session: The Plurnk Service maintains your unlimited Extended Context forever. Curate, tag, and organize it well.
|
|
58
|
+
|
|
59
|
+
Your Delegation: If your work can be decomposed, define the tasks in known entries and spawn worker runs with the path.
|
|
60
|
+
|
|
61
|
+
Your Judgment: If the prompt or the user preferences conflict with these rules, bend or break them.
|
package/SPEC.md
CHANGED
|
@@ -17,7 +17,7 @@ Canonical meanings. When a doc, comment, test name, or commit message uses one o
|
|
|
17
17
|
| **agent** | The plurnk runtime. Acts in-session as the reserved `plurnk` run (§actor-boundary self-hosting), never a privileged singleton owning its own entries — the old *agent scope* is retired (entry scope is now `session` / `run`, §machine-processes). |
|
|
18
18
|
| **session** | Durable user-named workspace. Persists across runs and process restarts. Identity: `sessions.id` + unique `sessions.name`. |
|
|
19
19
|
| **run** | A stretch of work within a session. Multiple runs per session. May fork from another run via `parent_run_id`. Owns the log entries. |
|
|
20
|
-
| **loop** | One model-driven or client-driven iteration within a run. Status ∈ {100 pending · 102 running · 200 done · 202 parked (resumable, §send) · 413 budget-overflow · 429 turn-ceiling · 499 cancelled · 500 failed · 508 runaway}. Many loops per run. The model runs inside a loop; each client RPC has its own loop. |
|
|
20
|
+
| **loop** | One model-driven or client-driven iteration within a run. Status ∈ {100 pending · 102 running · 200 done · 202 parked (resumable, §send) · 413 budget-overflow · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout (§operator-config-loop-timeout) · 508 runaway}. Many loops per run. The model runs inside a loop; each client RPC has its own loop. |
|
|
21
21
|
| **turn** | One round-trip with the LLM (or one client RPC dispatch). One assembled prompt sent, one parsed response handled. Many turns per loop. Identity: `(loop_id, sequence)`. |
|
|
22
22
|
| **op** | One DSL operation the model emits. Parsed into a `PlurnkStatement`. Examples: `EDIT`, `READ`, `SEND`, `FIND`, `COPY`, `MOVE`, `OPEN`, `FOLD`, `EXEC`. One turn produces zero or more ops. |
|
|
23
23
|
| **statement** | Synonym for parsed op. The AST shape `PlurnkStatement` from `@plurnk/plurnk-grammar`. |
|
|
@@ -176,11 +176,11 @@ Server posture: this package is the runtime. User-facing CLI lives in `plurnk` a
|
|
|
176
176
|
|
|
177
177
|
The run:// scheme makes §machine-processes addressable: a `run://` target is a sister run in the session — `run://self` the current run, `run://<name>` a session-scoped sibling (`runs.name`). `self` is the reserved current-run sentinel; empty authority (`run:///`) is invalid (400). Same-session only; a run never addresses another session's runs (§actor-boundary). The path discriminates the two faces: **path-absent is control** on the run-as-actor — the NAME is the authority (`run://<name>`, two slashes, no path) — while **path-present is run-scope storage**: `run://<owner>/<path>` (`run://self/<path>` for self) addresses the owner's private scratch (Scratch + Perspective, below). The control ops are three, fire-and-forget — the child runs independently, lineage in `runs.parent_run_id`:
|
|
178
178
|
|
|
179
|
-
- **Spawn** — `
|
|
179
|
+
- **Spawn** — `COPY(run://<name>):prompt` creates a new sister (empty log) and starts it with `prompt` on its first loop. COPY is the run-creation verb (grammar 0.74.41 OP×resource matrix): EDIT is file/entry only, so EDIT on the bare run entity is a **400** steering to COPY — the entity is not an entry. A name is **frozen per run** but **reclaimable across time** (§machine-processes-run-origin): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `run_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `run '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error. {§run-scheme-spawn}
|
|
180
180
|
- **irc** — `SEND(run://<name>):msg` delivers `msg` to an existing sister, the **voice door** (§actor-boundary-two-doors): an active sister folds it into its next turn, an idle one wakes (§actor-boundary-passive-wake); a name with no run in the session is 404. {§run-scheme-irc}
|
|
181
|
-
- **Fork** — `COPY(run
|
|
181
|
+
- **Fork** — `COPY(run://self):prompt` branches the current run: its log is deep-copied into a new sister (§machine-processes-fork-copies-the-log), which continues with `prompt`; the world is shared, never copied (§machine-processes-fork-shares-the-world). A fork ALSO inherits the run-scope **scratch** — its private workspace deep-copied with the owner remapped (source → branch) — so the branch opens with the parent's notes and diverges on its own edits: *fork = everything-in-common-but-name*. The `run://` authority disambiguates COPY's two run modes: `self` forks, a `<name>` spawns. The branch gets a **unique** default name `<parent>-fork-<N>` (next free), so N forks of one parent are individually addressable (`KILL`/`SEND`/`READ` by name) instead of colliding on a single name the resolver would collapse to the newest. Inherited loops are copied as **terminal history** (a non-terminal status is clamped): a fork's own work is a fresh loop, so an inherited mid-flight loop never makes the branch look forever-live to the §send-premature-terminate gate. {§run-scheme-fork} {§run-scheme-fork-scratch}
|
|
182
182
|
|
|
183
|
-
All three ride one engine seam — the daemon's inject (active→fold, idle→enqueue+drain) — so the handler creates/branches
|
|
183
|
+
All three ride one engine seam — the daemon's inject (active→fold, idle→enqueue+drain) — so the handler creates/branches the run and hands off; the daemon owns provider + system prompt. COPY's body here is the spawn/fork seed prompt, not a destination path: the engine routes a run:// COPY target away from the entry-copy path before parsing the body.
|
|
184
184
|
|
|
185
185
|
Beyond the three creation ops:
|
|
186
186
|
|
|
@@ -189,7 +189,7 @@ Beyond the three creation ops:
|
|
|
189
189
|
- **Perspective** — a run's own scratch is catalogued in **its** manifest alone — `Manifest(run) = session-scope ∪ this-run's-run-scope`, foisted as `FIND(run://self/**)` at turn 0 — so a sibling reaches it only by explicit `FIND(run://<name>/**)` and never sees it in its own perspective; isolation is structural (`scope='run'` is excluded from every session query, the owner opted back in only on its own read paths). {§run-scheme-find-perspective}
|
|
190
190
|
- **Terminate** — `KILL(run://<name>)` aborts a run by address (self is `run://self`): its active loop closes 499 and its subscriptions tear down; a name with no run is 404. The override to the fire-and-forget default — not a parent-power, whoever holds the address may end it; a run left alone simply ends at its own `SEND[200]`. {§run-scheme-terminate}
|
|
191
191
|
- **Cap** — `PLURNK_SESSION_RUNS_MAX_ACTIVE` ceilings the *concurrent* active runs per session (a run with a non-terminal loop); a spawn or fork past it fails hard (508 — no queue, no retry), irc exempt; `-1` disables it. The fork-bomb brake, sized for sessions that live for months. {§run-scheme-cap}
|
|
192
|
-
- **Collect** — a run's loop reaching a terminal status surfaces to its sisters as an ambient delta (§env-delta): a `SEND` from `run://<name>` carrying the loop's deliverable — the `SEND[200]` body, or for an abandonment the reason. A **2xx deliverable is born OPEN** (its body materialized into the parent's packet, not hidden behind a fold): a child's success must reach the parent open and awakening, never a bodyless row. An abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly, so no termination is silent; collection is the shared world moving, never a verb. {§run-scheme-collect}
|
|
192
|
+
- **Collect** — a run's loop reaching a terminal status surfaces to its sisters as an ambient delta (§env-delta): a `SEND` from `run://<name>` carrying the loop's deliverable — the `SEND[200]` body, or for an abandonment the reason. A **2xx deliverable is born OPEN** (its body materialized into the parent's packet, not hidden behind a fold): a child's success must reach the parent open and awakening, never a bodyless row. An abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly, so no termination is silent; collection is the shared world moving, never a verb. **Child orientation.** Beyond the conclusion delta, every turn the system packet surfaces the live things THIS run *currently holds* — open streams (`## Plurnk Service Child Streams`) and unconcluded child runs (`## Plurnk Service Child Runs`) — as terse `* <status> <path>` pointers (the same shape as the errors section), just above it. A worker is otherwise marked only at spawn and at conclusion; in between it goes silent, so a model loses track of what it holds and premature-terminates. This is ORIENTING STATE, never advice: the model SEES its live subtree (`* 102 run://worker-x`, `* active sh:///1/2/3`) and reasons for itself — READ/OPEN/KILL via the path — the error stays terse. Empty → omitted, like errors. {§child-orientation} The **pull** side mirrors the push: a path-absent `READ(run://<name>)` collects the same deliverable on demand — the latest loop's terminal message (the result, or the abandonment reason) for a concluded run; a run **still running** has not delivered, so the READ returns **425** steering the model to `SEND[202]` and await the push. A missing name is 404. So the model never needs to guess a scratch path to "check on" a worker — reading the run itself yields its outcome or a wait. {§run-scheme-collect}
|
|
193
193
|
|
|
194
194
|
### §run-lifecycle Run lifecycle: the drain, the reap, the passive wake
|
|
195
195
|
|
|
@@ -200,7 +200,7 @@ A run is a **log plus a cancellation scope** — one `AbortController` per run,
|
|
|
200
200
|
- **A stream's kill binds to the scope it captured at spawn.** A stream captures the run's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream. {§run-lifecycle-exec-epoch-bound}
|
|
201
201
|
- **A cancelled run is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle run starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta (§env-delta), never a revived loop. The cancel was deliberate; only an explicit `loop.run` resumes the run. {§run-lifecycle-no-resurrection}
|
|
202
202
|
- **A stream conclusion always reaches its run.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source (§actor-boundary-passive-wake): an active run folds the conclusion into its next turn; a run parked at a **slept loop** (`SEND[202]`) **awakens that loop in place** — the slept loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a parked loop sleeps rather than ending, and the stream's status-transition is the OPEN event (§actor-boundary-passive-wake) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt. {§run-lifecycle-wake-liveness}
|
|
203
|
-
- **A child run concluding wakes a parent parked on it — the topology join.** `run://` spawn/fork records `parent_run_id` (§lifecycle-terms). When a run's drain exits having **concluded** — no parked `202` loop, no open stream — the daemon resumes its parent **in place** if the parent is parked (`#onDrainExit` → the shared `#wakeParkedRun`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and `SEND[202]`s is woken the moment its child finishes; on resume it reads the child's deliverable from the §run-scheme-collect delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself parked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child runs are the same kind of "live thing a run holds," driving premature-terminate (§send-premature-terminate), the wake edge, and the collect delta identically. {§run-lifecycle-child-wake}
|
|
203
|
+
- **A child run concluding wakes a parent parked on it — the topology join.** `run://` spawn/fork records `parent_run_id` (§lifecycle-terms). When a run's drain exits having **concluded** — no parked `202` loop, no open stream — the daemon resumes its parent **in place** if the parent is parked (`#onDrainExit` → the shared `#wakeParkedRun`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and `SEND[202]`s is woken the moment its child finishes; on resume it reads the child's deliverable from the §run-scheme-collect delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself parked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child runs are the same kind of "live thing a run holds," driving premature-terminate (§send-premature-terminate), the wake edge, and the collect delta identically. A worker-run conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its `202` commits), `#wakeParkedRun` finds it not-yet-slept and records an **owed wake**, which the drain honors at the parent's park — so a hibernation awaiting worker runs **always returns**, never dead-parks on a conclude-before-park race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a park open.) {§run-lifecycle-child-wake}
|
|
204
204
|
- **A 202 whose subtree is idle emits `loop/quiesced` — a soft signal, not a terminal.** When a loop parks at `SEND[202]` and its subtree is idle (no open stream, no non-terminal child), the daemon broadcasts `loop/quiesced` (§notifications) — the client's honest *"nothing is running under this run right now."* The loop **stays at 202 and is reawakable**: a later `irc`/`loop.run` resumes it (and it re-quiesces, re-firing). It is **never a terminal code** — in a topology where any sibling can `irc` any run, true finality below the session doesn't exist, so quiescence (not finality) is the honest "done." A subtree with any live thing emits nothing — that thing's conclusion is the wake edge, not a quiesce. This is also the dead-park resolution: a wake-edge-less 202 no longer hangs silently; it announces idleness while staying resumable. {§run-lifecycle-quiesced}
|
|
205
205
|
- **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur. {§run-lifecycle-no-lost-loop}
|
|
206
206
|
|
|
@@ -272,7 +272,7 @@ Author-facing contract: [plurnk-schemes#1](https://github.com/plurnk/plurnk-sche
|
|
|
272
272
|
|
|
273
273
|
Every op targets a URI; the entry key is `(scope, scheme, pathname)`. The URI parses per RFC 3986 (`scheme://[authority]/path`) and maps to that key by one rule — no per-scheme carve-out:
|
|
274
274
|
|
|
275
|
-
- A **registered** scheme is a plurnk namespace: its authority is a leading path segment, folded into the pathname (`
|
|
275
|
+
- A **registered** scheme is a plurnk namespace: its authority is a leading path segment, folded into the pathname (`Dispatcher.#extractTarget` → `foldAuthorityIntoPath`). So `known://x`, `known:///x`, and pathname `/x` are the same entry — the authority is never a host, and the two-slash and three-slash forms are not distinct resources. {§scheme-address-namespace-fold}
|
|
276
276
|
- A **foreign** scheme (unregistered — `http`/`https`) is a real web host: its authority stays in `hostname`, never folded.
|
|
277
277
|
- `file` persists `scheme = NULL`; a relative path resolves against the workspace root to the namespace-absolute `/rel` key (RFC 3986 §5 reference resolution), and a path escaping the root is 403 (§membership).
|
|
278
278
|
|
|
@@ -541,7 +541,7 @@ OPEN/FOLD operate on the **log** (`log:///`) — the model's context-curation su
|
|
|
541
541
|
|
|
542
542
|
### §model-entry The model's own emission, mirrored back
|
|
543
543
|
|
|
544
|
-
A `model` log row is the model's **verbatim prior emission**, mirrored back so it can finally SEE its own behavior — and reason through its own syntax errors (the parser reports by line; the row renders line-numbered like all content). Actionless, like an `op='error'` row (§telemetry): no target, no op executed; `tx` is empty and the emission lives in `rx.content`, typed `text/vnd.plurnk`. **Born OPEN on a turn that erred** — a parse error or a content-offset NOTICE (`grammar_unenforced`) — so the model resolves the reported line against its own emission, no embedded snippet; **born FOLDED otherwise** (budget-neutral until the model OPENs it). OPEN/FOLD/KILL-able like any log row
|
|
544
|
+
A `model` log row is the model's **verbatim prior emission**, mirrored back so it can finally SEE its own behavior — and reason through its own syntax errors (the parser reports by line; the row renders line-numbered like all content). Actionless, like an `op='error'` row (§telemetry): no target, no op executed; `tx` is empty and the emission lives in `rx.content`, typed `text/vnd.plurnk`. **Born OPEN on a turn that erred** — a parse error or a content-offset NOTICE (`grammar_unenforced`) — so the model resolves the reported line against its own emission, no embedded snippet; **born FOLDED otherwise** (budget-neutral until the model OPENs it). OPEN/FOLD/KILL-able like any log row — the model curates its own history, and log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). {§model-entry-log-curation} The engine writes one at the end of each turn that produced output; a struck/empty turn mirrors nothing.
|
|
545
545
|
|
|
546
546
|
The run's **first** model row is exceptional: a born-OPEN turn-0 **exemplar** — a minimal worked example (`PLAN` → environment `FIND`s → `SEND[102]`) the model always opens on, so the grammar can stay thin (the example teaches the syntax, not a heavy grammar). {§model-entry}
|
|
547
547
|
|
|
@@ -591,17 +591,18 @@ AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, signal: nu
|
|
|
591
591
|
|---|---|---|
|
|
592
592
|
| **102** | continue | turn closes, another turn fires. Not terminal. |
|
|
593
593
|
| **200** | done | terminal — *only* when the run holds no live stream/spawn; otherwise the Premature-Terminate state below fires. Updates `loop.status`, ends the loop. |
|
|
594
|
-
| **202** | hibernate | terminal-but-resumable: the loop **sleeps** awaiting a wake edge — a stream-status transition or a directed prompt (§actor-boundary-passive-wake, §run-lifecycle-wake-liveness). NOT advertised to the model: it lives in `run.md` and reaches the model only via the engine's steering, never the hot-path packet. Distinct from the dispatch-internal proposal-202 (§proposal), which the model never emits. |
|
|
594
|
+
| **202** | hibernate | terminal-but-resumable: the loop **sleeps** awaiting a wake edge — a stream-status transition or a directed prompt (§actor-boundary-passive-wake, §run-lifecycle-wake-liveness). A park that would orphan a same-turn READ with no wake edge is refused (the Groundless-Hibernate state below); an idle park surfaces as `loop/quiesced` (§run-lifecycle-quiesced). NOT advertised to the model: it lives in `run.md` and reaches the model only via the engine's steering, never the hot-path packet. Distinct from the dispatch-internal proposal-202 (§proposal), which the model never emits. |
|
|
595
595
|
| **499** | give up | terminal — the model's **one** self-decided failure (a self-cancel; 499 = cancelled, §state-terms). The only failure it is trusted to declare for itself. |
|
|
596
596
|
|
|
597
597
|
The engine's failure terminals — **500** (strike threshold) and **508** (cycle), §engine-rails — are never the model's to pick; they are the engine ruling the loop failed. The surface is small on purpose: the model says done, waiting, or giving up, and is never asked to hold a correct opinion about *how* it failed or *whether* it can be woken — the engine decides those from state.
|
|
598
598
|
|
|
599
|
-
**
|
|
599
|
+
**Three engine error states verify the claim.** None is a status code the model learns; all are engine machinery (§engine-rails), pushed to the model as a steering hint on the next packet and **never** as the strike itself (the model sees errors that happened, never the engine's accounting — the gamification policy, §engine-rails). Each strikes (`turnErrors`) and lets the loop continue so the model can correct; a model that ignores the hint and keeps offending spins out to the engine's 500, seeing only the repeated hint, never the count. (All live at `Engine.runLoop`'s turn close.)
|
|
600
600
|
|
|
601
601
|
- **Idle turn** {§send-idle-turn} — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If the turn's work is complete, terminate with 200. If awaiting a stream or run trigger, terminate with 202 to hibernate."*
|
|
602
|
-
- **Premature terminate** {§send-premature-terminate} — a `SEND[200]`
|
|
603
|
-
|
|
604
|
-
|
|
602
|
+
- **Premature terminate** {§send-premature-terminate} — a `SEND[200]` is refused **409** at dispatch for either of two reasons; both record the SEND row's `[200]` attempt and body **faithfully** (never rewritten, never erased), stamp `status_rx=409` (Conflict), keep the loop a continue (a `log_entries.status_rx` may be 409; a *loop* status may not, so the loop simply never goes terminal), and **strike** (couples to the grinder, §grinder-strike-coupling — a model that won't stop premature-200ing escalates out via the rails to 500/508, never a false 200):
|
|
603
|
+
- **A live thing the run holds** — an open stream/spawn (§subscriptions, §run-lifecycle-total-reap) **or a non-terminal child run** (children and streams are the same kind of live thing a run holds, §run-lifecycle). A child is "live" by its **latest loop** — the SAME definition the `## Plurnk Service Child Runs` orientation renders (§child-orientation), so the gate and the section the model reads NEVER disagree: a refusal is always backed by a child the model can SEE and `KILL` (an inherited/historical loop a fork carries is not the latest, so a concluded child never refuses against an empty orientation — the fanout dead-end). Steer: *"Attempted [200] termination despite active streams or worker runs. You may either hibernate [202] to wait or KILL them before terminating."*
|
|
604
|
+
- **A READ submitted this turn** — the model emitted a `READ` and a terminal `SEND[200]` in the *same* turn, terminating on a result it cannot have seen: an op's result folds back on the NEXT turn (the correct shape is `READ` → `SEND[102]` → receive → `SEND[200]`). Without this gate the model ends mid-sentence on the value it expected to inline (the jsonpath/xpath extraction dead-end). Detected from the turn's own ops (the pre-dispatch snapshot), so it never depends on the READ's success. Terse signal: *"Attempted termination with submitted READ operation(s)."*
|
|
605
|
+
- **Groundless hibernate** {§send-groundless-hibernate} — the [202] arm of submitted-READ: the model emitted a `READ` and a `SEND[202]` in the *same* turn, with **no wake edge** — no live thing held (the same snapshot the [200] gate reads) and nothing wake-capable opened this turn. The READ's result folds back on the NEXT turn, but a park with no wake edge never *has* a next turn — the model is sleeping on its own unanswered question, an eternal park only an operator inject could revive (the config-lookup dead-park: `PLAN → READ → SEND[202]`, the model's dodge once the [200] arm steers it off `READ → SEND[200]`). Refused **409** with the same record-faithful shape (the row keeps its `[202]` attempt, the loop stays a continue, the steer strikes). Wake-edge-capable ops ground the park from the emission itself, spawn-then-hibernate style: `EXEC` (stream conclusion / `<T,P>` poll, §exec-poll), `COPY(run://…)` (child-conclusion wake, §run-lifecycle-child-wake), directed `SEND(run://…)` (irc), an `http` `READ` (a web fetch streams). A **bare park holding nothing is legal** — the voice door: a sibling irc or operator inject wakes it (§actor-boundary-passive-wake), and the daemon surfaces the idle park as `loop/quiesced` (§run-lifecycle-quiesced) rather than the engine refusing it. Steer: *"Attempted [202] hibernation with submitted READ operation(s) and nothing to wake you — the result arrives on your next turn, which this park would never reach. SEND[102] to receive it, then act."*
|
|
605
606
|
|
|
606
607
|
### §exec EXEC
|
|
607
608
|
|
|
@@ -805,8 +806,8 @@ Model selection: separate alias cascade in `ProviderRegistry` (§provider-instan
|
|
|
805
806
|
| `PLURNK_PORT` | `3044` | enforced | TCP port for the daemon WebSocket. |
|
|
806
807
|
| `PLURNK_MAX_TURNS` | `-1` | enforced | Operator turn **ceiling** — `-1` = no cap; a positive value caps a per-call `loop.run({maxTurns})`. |
|
|
807
808
|
| `PLURNK_MAX_COMMANDS` | `99` | enforced | Per-emission op cap. Overflow ops drop silently; one `max_commands_exceeded` telemetry entry surfaces on the next packet. |
|
|
808
|
-
| `PLURNK_RPC_TIMEOUT` | `30000` |
|
|
809
|
-
| `PLURNK_LOOP_TIMEOUT` | `86400000` |
|
|
809
|
+
| `PLURNK_RPC_TIMEOUT` | `30000` | enforced | ms deadline for non-`longRunning` RPC handlers; expiry answers `-32007 Timeout` (§errors) and the abandoned handler's late outcome is logged, never re-answered. `longRunning` registrations (proposal-pausing ops, external installs) are exempt. {§operator-config-rpc-timeout} |
|
|
810
|
+
| `PLURNK_LOOP_TIMEOUT` | `86400000` | enforced | ms wall-clock budget for a single `loop.run`: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 (§exec-timeout). {§operator-config-loop-timeout} |
|
|
810
811
|
| `PLURNK_MAX_STRIKES` | `3` | enforced | Strike threshold + sudden-death lead time (§engine-rails). |
|
|
811
812
|
| `PLURNK_MIN_CYCLES` | `3` | enforced | Min repetitions before cycle detection fires (§engine-rails). |
|
|
812
813
|
| `PLURNK_MAX_CYCLE_PERIOD` | `4` | enforced | Max period length cycle detection examines (§engine-rails). |
|
|
@@ -1083,7 +1084,7 @@ Each entry: question, answer, rationale, migration path.
|
|
|
1083
1084
|
|
|
1084
1085
|
### §packet-assembly Packet assembly: engine builds the default list, plugins transform it
|
|
1085
1086
|
|
|
1086
|
-
**Question.** Rummy uses priority-ordered filter chains for packet assembly. Plurnk builds a default ordered section list directly in `
|
|
1087
|
+
**Question.** Rummy uses priority-ordered filter chains for packet assembly. Plurnk builds a default ordered section list directly in `PacketBuilder.buildRequestPacket`, then lets trusted plugins rewrite it.
|
|
1087
1088
|
|
|
1088
1089
|
**Decision.** Two stages. (1) The engine builds the default section list. `slot` is a **trust boundary**: the system slot carries only framework-authored, non-injectable sections — `definition`, `tools`, `schemes`, the policy sections `system-policy`/`project-policy`, then the framework-status tail `errors` (uri+status pointers; the error item+body live in the log) and `git` (counts), with `budget` last (budget is law — a hard ceiling, the final word before the model acts). The user slot carries injectable content — `prompt` and `log` (READ results, exec output, the model's own mirror: data at the action point, never a privileged rule) — plus the `requirements` footer. Nothing that can carry attacker-reachable text rides the system slot. (2) `SchemeRegistry.transformSections` pipes that list through every registered scheme that implements `transformSections(sections) → sections`, in registration order, before the engine measures. A plugin returns whatever list it wants — add, remove, reorder. {§packet-plugin-transform}
|
|
1089
1090
|
|
|
@@ -1102,13 +1103,13 @@ Each entry: question, answer, rationale, migration path.
|
|
|
1102
1103
|
|
|
1103
1104
|
**Built.**
|
|
1104
1105
|
|
|
1105
|
-
- **Provider tokens, stored at write.** `provider.countTokens` is the source of truth; `entry_channels.tokens` (via `_entry-crud`) and `log_entries.tokens` (via `
|
|
1106
|
+
- **Provider tokens, stored at write.** `provider.countTokens` is the source of truth; `entry_channels.tokens` (via `_entry-crud`) and `log_entries.tokens` (via `Dispatcher.#writeLog`) are populated at write as a write-time snapshot. A `ceil(len/DIVISOR)` fallback (the divisor tripwire) applies only when no provider tokenizer is wired. {§tokenomics-tokens-stored-at-write}
|
|
1106
1107
|
- **Render-weight budget.** The budget headline — `ceiling`, `tokenUsage`, `tokensFree` — is measured from the *assembled packet* (placeholders substituted after measuring), so it reflects what the model actually receives. A `SUM` of stored content-depth would mis-price the rendered packet; render-weight is the accurate measure. {§tokenomics-render-weight-budget}
|
|
1107
|
-
- **Per-turn weight.** A markdown table groups render-weight by turn — the `loop/turn` coordinate prefix — oldest first
|
|
1108
|
-
- **Heaviest entries.** A second table lists the
|
|
1108
|
+
- **Per-turn weight.** A markdown table groups render-weight by turn — the `loop/turn` coordinate prefix — listed chronologically (oldest first). The turn is the grinder's rollback unit, and the rail folds the **newest** turn first (§grinder); the model sees which turns are fat and can FOLD ahead of the rail. {§tokenomics-turn-totals}
|
|
1109
|
+
- **Heaviest entries.** A second table lists the five heaviest log entries by render-weight, each by its `log:///<coord>/<op>` handle — the FOLD targets behind the turn weight. The handle carries the turn, so the two tables interlock. {§tokenomics-largest-entries}
|
|
1109
1110
|
- **Context-window percent.** The headline carries usage as a percent of the ceiling — `usage Y (P%)` — a fullness gauge beside the absolutes. Reads the ceiling already in hand; no extra provider call. {§tokenomics-context-percent}
|
|
1110
1111
|
- **Depth re-counted at render.** The manifest re-tokenizes each entry's `tokens` through the live provider at build — never the write-time snapshot — so a model change between loops can't stale the catalog. Every token figure in the packet is render-fresh, manifest and budget alike; nothing trusts a cross-loop cached total.
|
|
1111
|
-
- **The delivered packet is never over budget.** The readout shows the state of the packet the model actually has, and the grinder (§grinder) folds any over-ceiling packet back under *before* it is sent — so a delivered budget headline is always usage ≤ ceiling, percent ≤ 100, free ≥ 0. The percent is of the **post-fold** packet; the pre-fold overshoot is engine trivia the model never sees. A packet that can't be folded under even
|
|
1112
|
+
- **The delivered packet is never over budget.** The readout shows the state of the packet the model actually has, and the grinder (§grinder) folds any over-ceiling packet back under *before* it is sent — so a delivered budget headline is always usage ≤ ceiling, percent ≤ 100, free ≥ 0. The percent is of the **post-fold** packet; the pre-fold overshoot is engine trivia the model never sees. A packet that can't be folded under even after the grinder folds the newest turn (§grinder-newest-turn-only) is the corner case: the loop **hard-413s** rather than deliver an over-budget packet — the engine never reaches back to fold older turns to save a loop (that would charge tokens while lobotomizing the model's memory); a model that won't self-curate strikes out instead. Its STORED failure record renders the overshoot honestly — `free` floors at 0 (never negative), the percent passes 100 — never clamped to hide the degenerate state, but never the model's reasoning surface either. {§tokenomics-over-budget-floor}
|
|
1112
1113
|
|
|
1113
1114
|
**Rejected / obviated.**
|
|
1114
1115
|
|
|
@@ -1164,14 +1165,15 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
|
|
|
1164
1165
|
|
|
1165
1166
|
**Question.** §tokenomics surfaces the budget honestly and the model curates against `tokensFree` — almost always enough. Two states defeat self-regulation, neither the model's doing: a jumbo prompt (the turn-0 environment), and an unexpectedly large read. (A jumbo repo is no longer its own case — with no index nothing auto-renders the repo; it surfaces only as a large catalog `FIND`, which the model pages like any big result.) What enforces the ceiling when the signal isn't enough?
|
|
1166
1167
|
|
|
1167
|
-
**Decision — a pre-LLM grinder, fired only on actual overflow.** In `Engine.runTurn`, after the packet is assembled (
|
|
1168
|
+
**Decision — a pre-LLM grinder, fired only on actual overflow.** In `Engine.runTurn`, after the packet is assembled (`PacketBuilder.buildRequestPacket`) and before `provider.generate`, the assembled render-weight (§tokenomics) is measured against the ceiling. At or under → the packet ships untouched; the grinder never trims speculatively or "helpfully." {§grinder-overflow-only} On overflow it folds the newest turn, then hard-stops if that isn't enough:
|
|
1168
1169
|
|
|
1169
|
-
- **
|
|
1170
|
-
- **
|
|
1170
|
+
- **Newest-turn rollback.** The grinder folds the newest turn in the packet, and ONLY that one: the immediately-prior turn's emissions (turn N>1, the latest output that pushed it over), or — when there is no prior turn — **turn 1's own foists** (the catalog/prompt). It never reaches older history; the model alone curates stale context via FOLD/KILL, and the engine never janitors. Folded, not deleted: rows and bodies persist and are re-OPENable, so log *history* is preserved while the render collapses to coordinates. {§grinder-layer1-rollback}
|
|
1171
|
+
- **Errors are exempt.** The grinder never folds an `op='error'` row — the budget-overflow it just minted, a parse failure, an action failure. Errors are the model's durable, curatable record of what went wrong; folding them away the moment they matter would blind the model to a recurring failure. They stay OPEN until the model itself FOLDs or KILLs them. {§grinder-errors-exempt}
|
|
1172
|
+
- **Hard stop.** If the packet still overflows after the newest-turn rollback, the loop abandons at **413 Content Too Large** (`engine_loop_set_status`) — the content genuinely won't fit, and the anchor's name is finally its status. Its sibling engine-imposed terminals are HTTP-precise too: `maxTurns` → 429, a strike-out → 500 (508 when cycle-driven) — no longer the old catch-all 499. No further passes. {§grinder-hard-413-abort}
|
|
1171
1173
|
|
|
1172
|
-
**Strike coupling.** A grinder fire bumps the engine's `turnErrors` — the same internal counter cycle detection feeds — so an overflow counts toward the strike streak that ends a runaway loop at 500 (or 508 if the crossing strike was a detected cycle). This is the pressure that keeps self-curation the path of least resistance. {§grinder-strike-coupling} **
|
|
1174
|
+
**Strike coupling.** A grinder fire bumps the engine's `turnErrors` — the same internal counter cycle detection feeds — so an overflow counts toward the strike streak that ends a runaway loop at 500 (or 508 if the crossing strike was a detected cycle). This is the pressure that keeps self-curation the path of least resistance. {§grinder-strike-coupling} **Every compaction strikes — including turn 0/1.** There is no soft exemption: a fold is a fold; the model gets three tries (`maxStrikes`), and three compactions running strike it out. The compacted packet is necessarily slightly heavier than nothing (folded rows still cost their coordinate line), so overflow is never "impossible" — a model that refuses to distill/fold/kill can genuinely strike out. {§grinder-compaction-strikes}
|
|
1173
1175
|
|
|
1174
|
-
**What the model sees.**
|
|
1176
|
+
**What the model sees.** The overflow is a terse `op='error'` log row — a status code and the canonical term, `413 Budget Overflow`, no mechanism vocabulary ("layer," "grinder," "reclaim") and no advice (the packet teaches recovery, not the row). It is minted *before* the rebuild, so its derived `log:///<coord>` pointer surfaces in the `errors` section (§telemetry) THIS turn — at strike 1, not a turn late. The budget readout (§tokenomics) — turn and entry weights — is the diagnostic surface; the model diagnoses the cause the engine can't attribute. Because error rows are grinder-exempt (below), successive overflows stack into a visible recurrence trail the model reads to break a spiral. Per the gamification policy (§telemetry), the *strike* the overflow triggers stays engine-internal; the model sees the error rows, never the accounting. {§grinder-overflow-error-row}
|
|
1175
1177
|
|
|
1176
1178
|
**Rationale.** The model owns curation (§tokenomics); the grinder is the exceptional backstop. It only *folds* — reversibly — the prior turn's render; nothing is deleted, so the model can OPEN it back and log history stays intact. Rummy's own spec described clearing log *bodies*, but its code instead folded the prior turn whole — because body-clearing is destructive (it deletes the read result) and bespoke. The code was the lesson; plurnk follows it.
|
|
1177
1179
|
|
|
@@ -1226,13 +1228,13 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
|
|
|
1226
1228
|
|
|
1227
1229
|
## §packet Packet shape
|
|
1228
1230
|
|
|
1229
|
-
**Service-owned.** grammar 0.67 deleted `Packet.json` — the protocol scoped itself to the grammar, so the packet shape is now entirely plurnk-service's. The engine assembles it in `
|
|
1231
|
+
**Service-owned.** grammar 0.67 deleted `Packet.json` — the protocol scoped itself to the grammar, so the packet shape is now entirely plurnk-service's. The engine assembles it in `PacketBuilder.buildRequestPacket` as an **ordered list of sections** that trusted plugins may rewrite (§packet-assembly).
|
|
1230
1232
|
|
|
1231
1233
|
```ts
|
|
1232
1234
|
type PacketSection = {
|
|
1233
1235
|
name: string; // stable id: definition, tools, schemes, system-policy, project-policy, budget, prompt, errors, log, git, requirements — or a plugin's own
|
|
1234
1236
|
slot: "system" | "user"; // the prompt-cache boundary; system-slot sections build the cache-stable system message
|
|
1235
|
-
header: string | null; // "## Plurnk
|
|
1237
|
+
header: string | null; // "## Plurnk Service X", or null (definition renders verbatim)
|
|
1236
1238
|
content: string; // rendered markdown — what the model saw
|
|
1237
1239
|
tokens: number; // measured render-weight
|
|
1238
1240
|
};
|
|
@@ -1247,7 +1249,7 @@ type Packet = {
|
|
|
1247
1249
|
|
|
1248
1250
|
The wire projection (`PacketWire.renderSlot`) groups sections by slot into the system + user ChatMessages; the digest re-renders the same stored sections byte-for-byte.
|
|
1249
1251
|
|
|
1250
|
-
**Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `plurnk:///prompt/<loop_id>` (indexable, body channel, text/markdown). At render time the current loop's prompt
|
|
1252
|
+
**Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `plurnk:///prompt/<loop_id>/<N>` (indexable, body channel, text/markdown). At render time the **Active User Prompts** section materializes **every** prompt the current loop holds, oldest first — typically one, but an active loop admits injected prompts, all shown in order. The section is the OPPOSITE of the errors section: bare HEREDOC bodies, no meta/link line — the heredoc fence (each prompt's own `plurnk://prompt/<loop>/<N>` address) IS the link. A prompt over `PLURNK_PROMPT_PREVIEW_CHARS` renders a `[ Prompt exceeds preview limit. Full content: <addr> ]` pointer instead of its body (the model OPENs/READs the entry to see it whole — never lost). The entry itself stays READ/FOLD-able like any other. The foisted `EDIT`'s **log row is folded by default** (`expanded=0`): the prompt body already lives in the Active User Prompts section, so the log keeps the action for forensics while collapsing the duplicate body, re-OPENable like any fold (§open-fold). {§prompt-fold}
|
|
1251
1253
|
|
|
1252
1254
|
**The entry catalog.** The catalog is the **complete, unranked directory** of what a session holds, served by `FIND(scheme:///**)` — one per-scheme array, queried on demand, not a single materialized entry (there is no `plurnk:///manifest.json`; the per-scheme arrays replaced it). Built in the schemes layer (`_entry-manifest.catalogRowsFor`); a per-turn derivation pump (`maintainDerivations`) refreshes the deep channels the rows report. A scheme's array is **every entry it holds, in no relevance order**, each `{ path, seconds?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }` — every channel keyed by the URI the model READs (the default channel by the bare path, a non-default by `path#channel`), so it reaches a channel without guessing. `tags` is present only when the entry carries `entry_tags` — its own categorization, surfaced so the model can `FIND` by tag. The model ranks and filters the catalog itself by querying it (task-aware); the catalog never ranks for it — the instant it did, it would be an index again. `tokens` is the provider's live count recounted at render, `lines` the content extent from `Mimetypes.process().totalLines`. The catalog never lists itself. {§packet-catalog}
|
|
1253
1255
|
|
|
@@ -1268,38 +1270,45 @@ The `log` section is the durable audit; the `errors` section surfaces both — t
|
|
|
1268
1270
|
**Plurnk-service rendering:**
|
|
1269
1271
|
|
|
1270
1272
|
- `budget` per §tokenomics: turn-weight and heaviest-entries tables with `tokenCeiling`/`tokenUsage`/`tokensFree`.
|
|
1271
|
-
- **
|
|
1272
|
-
- **
|
|
1273
|
-
- **
|
|
1274
|
-
- **Gamification policy (rummy precedent, plugins/error/error.js).** The model sees errors that **happened** — its actions failed, its emission didn't parse, its ops were truncated. The model does NOT see the engine's accounting *about* errors: strike streaks, cycle detection, sudden-death thresholds, no-ops bookkeeping. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics (manufacturing a clean turn to reset the strike counter, e.g.) instead of the task. Engine bookkeeping drives abandonment silently; the model just sees its actual failures.
|
|
1273
|
+
- **One uniform error channel.** EVERY failure — a failed action, an actionless parse failure, and every engine-rail failure (budget overflow, max-commands, the idle/premature steers) — is an `op='error'` `log_entries` row with `status_rx ≥ 400`. No per-category handling, no bespoke ephemeral relationship. The `errors` section is a derived index over those rows (the current turn and the immediately-prior one): one terse `<status> log:///<coord>` link per row, nothing else. The term and full detail live on the foldable row, READ via the link. {§telemetry-uniform-error-channel}
|
|
1274
|
+
- **Terse rows.** An error row's body is a status code and the canonical term — `Budget Overflow`, `Max Commands Exceeded`, `Idle Turn`, `Premature Termination` — never prose, hints, or advice. The packet (requirements, grammar) teaches recovery; the row names the fault. Letting the model infer what to do from the fact (and the log) beats handing it instructions it will second-guess.
|
|
1275
|
+
- **Notices** — the few events that are NOT log rows (a provider's `grammar_unenforced`, which points at the model's own emission via a content-offset) render one terse line under `## Plurnk Service Errors` by their typed `position`, never a JSON dump. The notice buffer drains on read — each appears on exactly one packet. {§telemetry-drain-on-read}
|
|
1276
|
+
- **Gamification policy (rummy precedent, plugins/error/error.js).** The model sees errors that **happened** — its actions failed, its emission didn't parse, its ops were truncated, it overflowed the window. The model does NOT see the engine's accounting *about* errors: strike streaks, cycle detection, sudden-death thresholds, no-ops bookkeeping. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics (manufacturing a clean turn to reset the strike counter, e.g.) instead of the task. Engine bookkeeping drives abandonment silently; the model just sees its actual failures.
|
|
1277
|
+
|
|
1278
|
+
**The error rows (one channel) + the only non-log notices:**
|
|
1275
1279
|
|
|
1276
|
-
|
|
1280
|
+
| failure | row | status |
|
|
1281
|
+
|---|---|---|
|
|
1282
|
+
| parse failure | `op='error'`, origin `model`, source `grammar`; body = parser message + content-offset `line:col` | 400 |
|
|
1283
|
+
| action failure | the failed op's own row (the scheme set `status_rx ≥ 400`); body = the scheme's error | 4xx/5xx |
|
|
1284
|
+
| budget overflow | `op='error'`, origin `plurnk`, source `rail`; body = `Budget Overflow: newest log items automatically FOLDed` | 413 |
|
|
1285
|
+
| max commands exceeded | `op='error'`, origin `plurnk`, source `rail`; body = `Max Commands Exceeded` | 429 |
|
|
1286
|
+
| idle turn / premature termination | `op='error'`, origin `plurnk`, source `rail`; body = `Idle Turn` / `Premature Termination` | 409 |
|
|
1277
1287
|
|
|
1278
|
-
| `kind` | Source |
|
|
1288
|
+
| notice `kind` | Source | Position |
|
|
1279
1289
|
|---|---|---|
|
|
1280
|
-
| `
|
|
1281
|
-
| `
|
|
1282
|
-
| `max_commands_exceeded` | Single emission exceeded `PLURNK_MAX_COMMANDS` cap; overflow ops dropped without dispatch | `source: "engine:rail"`, `kind`, `emitted`, `dropped` |
|
|
1283
|
-
| `budget_overflow` | Assembled packet exceeded the budget ceiling; entries moved out of the window to fit | `source: "engine:rail"`, `kind`, `hidden` (per-scheme `[{scheme, count}]` — entries removed from the window) |
|
|
1284
|
-
| `embed_progress` | The derivation pump (§mimetype-surface) is embedding a multi-entry corpus pass; throttled to ~10 milestones, silent for a 0-1 entry turn | `source: "engine:derivation"`, `kind`, `completed`, `total`, `message` |
|
|
1290
|
+
| `grammar_unenforced` | (provider, forwarded) GBNF-filter divergence — the model's bytes diverged from the transported grammar | content-offset into the model's emission |
|
|
1291
|
+
| `embed_progress` | derivation-pump milestone (§mimetype-surface); `level: info`, never in the errors section | none |
|
|
1285
1292
|
|
|
1286
|
-
**Severity on the wire (`level`, required — grammar 0.74.29+).** Every `TelemetryEvent` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site — severity is meaning the producer owns, not something the client re-derives by pattern-matching the open `kind` vocabulary. Service mappings:
|
|
1293
|
+
**Severity on the wire (`level`, required — grammar 0.74.29+).** Every `TelemetryEvent` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site — severity is meaning the producer owns, not something the client re-derives by pattern-matching the open `kind` vocabulary. Service mappings: every error log row is `error` (an error is an error); a forwarded `grammar_unenforced` carries the producer's own level (defaulted to `warn` only when the producer predates the field); `embed_progress` is `info`, a progress note that never reaches the errors section. Clients color straight off `level`. {§telemetry-event-level}
|
|
1287
1294
|
|
|
1288
|
-
Strike accounting, cycle detection, sudden-death thresholds, and no-ops bookkeeping stay engine-internal — they drive abandonment silently per the gamification policy.
|
|
1295
|
+
Strike accounting, cycle detection, sudden-death thresholds, and no-ops bookkeeping stay engine-internal — they drive abandonment silently per the gamification policy. EVERY error — a failed action, an actionless parse failure, and every engine-rail failure (budget overflow, max-commands, the idle/premature steers) — is a LOG ITEM (`log:///<coord>`, `op='error'`, `status_rx ≥ 400`), foldable and re-OPENable, with its terse term on the row. The `errors` section surfaces a derived pointer to each. There is **no bespoke `error://` scheme** and no ephemeral per-category error buffer: errors live in the log, addressable + curatable like any row — not a separate namespace, not a drain-on-read side channel. {§telemetry-no-error-scheme}
|
|
1289
1296
|
|
|
1290
1297
|
**Client surface.** Engine NOTICES broadcast live via the `telemetry/event` WS notification — same envelope as the model's drained copy (`{ source, kind, level, message?, position?, …kind-specific }` per the grammar's `TelemetryEvent` schema), the moment they land, scoped to the loop's session (a `grammar_unenforced` snippet in a debug panel, a session timeline). ERRORS do not broadcast on this surface: they are log rows, and the client reads them the same way the model curates them — `log.read` / the `log/entry` notification, the durable log. {§telemetry-telemetry-event-notify}
|
|
1291
1298
|
|
|
1299
|
+
**Turn-lifecycle liveness.** The provider `generate()` call is the one long, opaque window in a turn — submit → first committed op is provider latency plus a full first-turn generation (tens of seconds on a local model); a static client screen there is indistinguishable from a hang. The engine brackets `generate()` with two `telemetry/event` NOTICES (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` the instant it calls the provider, `turn_generated` when the call resolves and op-parsing begins — a legible "thinking… → working…" heartbeat, NOT model token-content (that stays out of the Log, a paradigm break). Both are suppressed on an aborted loop and broadcast to the session like any notice (§telemetry-telemetry-event-notify). Optional intra-generation ticks (a moving counter during the long wait) are a later provider-contract enhancement (an `onProgress` on `generate()`, the `embedBatch` shape); the two-beat bracket needs no provider change. {§turn-lifecycle}
|
|
1300
|
+
|
|
1292
1301
|
**Content-offset position.** An emission-level error carries a `position: { type: "content-offset", line, column }` into the model's own emission — a parse-error LOG ROW (op='error', §model-entry) and a content-offset NOTICE (e.g. a provider's `grammar_unenforced`) both report the line, not the bytes. The model resolves it against its own emission: the turn that erred has its `model` row born OPEN (§model-entry), so the line-numbered emission sits in the log and the model reads the cited line directly. No snippet is embedded — that would duplicate the emission the model already holds. {§telemetry-content-offset-pointer}
|
|
1293
1302
|
|
|
1294
1303
|
### §tools user.tools — the capability sheet
|
|
1295
1304
|
|
|
1296
|
-
The tools capability lines render **titleless**, directly under the `definition` (plurnk.md) section — the examples flow on from plurnk.md with no separate header — and **above** `## Plurnk
|
|
1305
|
+
The tools capability lines render **titleless**, directly under the `definition` (plurnk.md) section — the examples flow on from plurnk.md with no separate header — and **above** `## Plurnk Service Requirements`, so the model sees what it can *do* before the rules it must follow. Each enabled capability contributes one line via `PacketBuilder.#collectTools`; the section is omitted when nothing is enabled. {§tools-capability-sheet}
|
|
1297
1306
|
|
|
1298
1307
|
**Contributors: the wired executor tags.** Each available executor tag *with an example* contributes ONE line — its canonical usage — via the shared `teachingLine` (identical shape to the scheme directory, §schemes); its doc is materialized at `plurnk://docs/<tag>.md` and discovered via the turn-1 `FIND(plurnk://docs/**)` foist, not linked inline (#270). A tag with no example contributes nothing; `PLURNK_DOCS_EXCLUDE` drops a named tag's line + doc. The boot `ExecutorRegistry` probes availability per tag, retiring the model's blind `<<EXEC[sh]…`.
|
|
1299
1308
|
|
|
1300
1309
|
### §schemes user.schemes — the scheme directory
|
|
1301
1310
|
|
|
1302
|
-
A `## Plurnk
|
|
1311
|
+
A `## Plurnk Service Schemes` section renders in the system slot **after the definition (plurnk.md — grammar + imperatives) and the tools sheet** — a terse directory of the scheme families available this session, so the model knows what URI schemes exist before it acts. Each scheme that ships a `manifest.example` contributes ONE line — its canonical usage (no scheme prefix; the example self-documents). The doc is NOT linked inline (#270) — it is materialized at `plurnk://docs/<scheme>.md` and discovered via the turn-1 `FIND(plurnk://docs/**)` foist, keeping the raw packet free of doc links. The in-tree core schemes author their depth in `docs/<name>.md` (loaded at boot, shipped with the package); daughter schemes ship `manifest.documentation`. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls, via the same `teachingLine` as the tools sheet (§tools). A scheme with no example (provisional) is omitted; `PLURNK_DOCS_EXCLUDE` drops a named scheme's line + doc. {§schemes-directory}
|
|
1303
1312
|
|
|
1304
1313
|
### §inject system.inject — the operator injection
|
|
1305
1314
|
|
|
@@ -1307,13 +1316,13 @@ When `PLURNK_PACKET_INJECT` names a readable markdown file, its content renders
|
|
|
1307
1316
|
|
|
1308
1317
|
### §policy system.policy — the client's policy injection
|
|
1309
1318
|
|
|
1310
|
-
Two sections ride the system slot **below the operator notes, above budget**: `## Plurnk
|
|
1319
|
+
Two sections ride the system slot **below the operator notes, above budget**: `## Plurnk Service Policy` from `PLURNK_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the session root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. Reference/scratch docs are NOT policy — they ride `PLURNK_MD_*` (materialized as READ-able entries, §operator-config), which is where the dev-notes AGENTS.md used to hold belong. {§policy-sections}
|
|
1311
1320
|
|
|
1312
1321
|
**The scheme self-doc contract.** `example` is the hot-path one-liner; `documentation` is the deep doc — the exact shape execs already use (`example` + `documentation`). `SchemeRegistry.teach()` renders the directory; `docEntries()` materializes the docs (per loop.run, alongside the operator docs). `documentation` rides a service-side `SchemeManifest` extension until plurnk-schemes#25 lands it in the contract.
|
|
1313
1322
|
|
|
1314
1323
|
### §requirements The requirements section — static per-turn rules
|
|
1315
1324
|
|
|
1316
|
-
Rendered at the END of the user packet under `## Plurnk
|
|
1325
|
+
Rendered at the END of the user packet under `## Plurnk Service Requirements` {§requirements-requirements-render-last} — closest to the assistant turn so the contract the model has to honor is the most recent text it sees. The header is omitted entirely when the requirements string is empty. {§requirements-requirements-omitted-when-empty} Contains rules the grammar block doesn't cover (canonical example: "Conclude the loop with `<<SEND[200]:answer:SEND`"). The op syntax leads the section. PLAN is mandated unconditionally by plurnk.md §Imperatives (grammar 0.70 requires every turn to lead with `<<PLAN`), so the service injects no separate plan directive here.
|
|
1317
1326
|
|
|
1318
1327
|
**Sourcing:** caller supplies the string via `runLoop({ requirements })` / `runTurn({ requirements })`. Plurnk-service exposes `PATHS.defaultRequirements` (resolves `PLURNK_REQUIREMENTS` env → in-package `requirements.md`). No DB cascade — same string every turn.
|
|
1319
1328
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { PlurnkStatement } from "@plurnk/plurnk-grammar";
|
|
2
|
+
import type { Mimetypes } from "@plurnk/plurnk-mimetypes";
|
|
3
|
+
import type { Db } from "./Db.ts";
|
|
4
|
+
import type SchemeRegistry from "./SchemeRegistry.ts";
|
|
5
|
+
import type ExecutorRegistry from "./ExecutorRegistry.ts";
|
|
6
|
+
import type TelemetryChannel from "./TelemetryChannel.ts";
|
|
7
|
+
import type ProposalLifecycle from "./ProposalLifecycle.ts";
|
|
8
|
+
import type { WriterTier } from "./scheme-types.ts";
|
|
9
|
+
import type { StreamEventNotify, WakeRunNotify, InjectRunNotify, CancelRunNotify } from "./ChannelWrite.ts";
|
|
10
|
+
export type PrematureReason = "live-thing" | "submitted-read" | "groundless-hibernate";
|
|
11
|
+
export type DispatchContext = {
|
|
12
|
+
statement: PlurnkStatement;
|
|
13
|
+
sessionId: number;
|
|
14
|
+
runId: number;
|
|
15
|
+
loopId: number;
|
|
16
|
+
turnId: number;
|
|
17
|
+
sequence: number;
|
|
18
|
+
origin: WriterTier;
|
|
19
|
+
onDispatch?: (logEntryId: number) => void;
|
|
20
|
+
prematureRefusal?: PrematureReason;
|
|
21
|
+
};
|
|
22
|
+
export type DispatchResult = {
|
|
23
|
+
status: number;
|
|
24
|
+
attrs?: object;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
export default class Dispatcher {
|
|
28
|
+
#private;
|
|
29
|
+
constructor({ db, schemes, mimetypes, tokenize, telemetry, proposals, executors, loopSignal, streamEventNotify, wakeRunNotify, injectRun, cancelRun }: {
|
|
30
|
+
db: Db;
|
|
31
|
+
schemes: SchemeRegistry;
|
|
32
|
+
mimetypes: Mimetypes;
|
|
33
|
+
tokenize: (text: string) => number;
|
|
34
|
+
telemetry: TelemetryChannel;
|
|
35
|
+
proposals: ProposalLifecycle;
|
|
36
|
+
executors: () => ExecutorRegistry | undefined;
|
|
37
|
+
loopSignal: (loopId: number) => AbortSignal | undefined;
|
|
38
|
+
streamEventNotify?: StreamEventNotify;
|
|
39
|
+
wakeRunNotify?: WakeRunNotify;
|
|
40
|
+
injectRun?: InjectRunNotify;
|
|
41
|
+
cancelRun?: CancelRunNotify;
|
|
42
|
+
});
|
|
43
|
+
dispatch(context: DispatchContext): Promise<DispatchResult>;
|
|
44
|
+
look(context: {
|
|
45
|
+
statement: PlurnkStatement;
|
|
46
|
+
sessionId: number;
|
|
47
|
+
runId: number;
|
|
48
|
+
loopId: number;
|
|
49
|
+
origin?: WriterTier;
|
|
50
|
+
}): Promise<DispatchResult>;
|
|
51
|
+
writeModelEntry({ verbatim, runId, loopId, turnId, sequence, folded, origin }: {
|
|
52
|
+
verbatim: string;
|
|
53
|
+
runId: number;
|
|
54
|
+
loopId: number;
|
|
55
|
+
turnId: number;
|
|
56
|
+
sequence: number;
|
|
57
|
+
folded: boolean;
|
|
58
|
+
origin?: WriterTier;
|
|
59
|
+
}): Promise<number>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=Dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dispatcher.d.ts","sourceRoot":"","sources":["../../src/core/Dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAmD,MAAM,wBAAwB,CAAC;AAC/G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAC;AAO5D,OAAO,KAAK,EAAkB,UAAU,EAAkC,MAAM,mBAAmB,CAAC;AAEpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAgB5G,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,sBAAsB,CAAC;AAEvF,MAAM,MAAM,eAAe,GAAG;IAC1B,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAM1C,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAgBxF,MAAM,CAAC,OAAO,OAAO,UAAU;;gBAgBf,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;QACnJ,EAAE,EAAE,EAAE,CAAC;QACP,OAAO,EAAE,cAAc,CAAC;QACxB,SAAS,EAAE,SAAS,CAAC;QACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;QACnC,SAAS,EAAE,gBAAgB,CAAC;QAC5B,SAAS,EAAE,iBAAiB,CAAC;QAC7B,SAAS,EAAE,MAAM,gBAAgB,GAAG,SAAS,CAAC;QAC9C,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;QACxD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;QACtC,aAAa,CAAC,EAAE,aAAa,CAAC;QAC9B,SAAS,CAAC,EAAE,eAAe,CAAC;QAC5B,SAAS,CAAC,EAAE,eAAe,CAAC;KAC/B;IAeK,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAkH3D,IAAI,CAAC,OAAO,EAAE;QAChB,SAAS,EAAE,eAAe,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QACjD,MAAM,CAAC,EAAE,UAAU,CAAC;KACvB,GAAG,OAAO,CAAC,cAAc,CAAC;IAyVrB,eAAe,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAgB,EAAE,EAAE;QAC3F,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,UAAU,CAAC;KAC3H,GAAG,OAAO,CAAC,MAAM,CAAC;CA+RtB"}
|