@possumtech/rummy 2.1.0 → 2.2.1
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 +40 -15
- package/.xai.key +1 -0
- package/PLUGINS.md +169 -53
- package/README.md +38 -32
- package/SPEC.md +366 -179
- package/bin/digest.js +1097 -0
- package/biome/no-fallbacks.grit +2 -2
- package/gemini.key +1 -0
- package/lang/en.json +10 -1
- package/migrations/001_initial_schema.sql +9 -2
- package/package.json +19 -8
- package/service.js +1 -0
- package/src/agent/AgentLoop.js +76 -26
- package/src/agent/ContextAssembler.js +2 -0
- package/src/agent/Entries.js +238 -60
- package/src/agent/ProjectAgent.js +44 -0
- package/src/agent/TurnExecutor.js +99 -30
- package/src/agent/XmlParser.js +206 -111
- package/src/agent/errors.js +35 -0
- package/src/agent/known_queries.sql +1 -1
- package/src/agent/known_store.sql +3 -42
- package/src/agent/materializeContext.js +30 -1
- package/src/agent/runs.sql +8 -18
- package/src/agent/tokens.js +0 -1
- package/src/agent/turns.sql +1 -0
- package/src/hooks/Hooks.js +26 -0
- package/src/hooks/RummyContext.js +12 -1
- package/src/lib/hedberg/README.md +60 -0
- package/src/lib/hedberg/hedberg.js +60 -0
- package/src/lib/hedberg/marker.js +158 -0
- package/src/{plugins → lib}/hedberg/matcher.js +1 -2
- package/src/llm/LlmProvider.js +41 -3
- package/src/llm/openaiStream.js +17 -0
- package/src/plugins/ask_user/ask_user.js +12 -2
- package/src/plugins/ask_user/ask_userDoc.md +1 -5
- package/src/plugins/budget/README.md +29 -24
- package/src/plugins/budget/budget.js +166 -110
- package/src/plugins/cli/README.md +3 -4
- package/src/plugins/cli/cli.js +31 -5
- package/src/plugins/cloudflare/cloudflare.js +136 -0
- package/src/plugins/cp/cp.js +41 -4
- package/src/plugins/cp/cpDoc.md +5 -6
- package/src/plugins/engine/engine.sql +1 -1
- package/src/plugins/env/README.md +5 -4
- package/src/plugins/env/env.js +7 -4
- package/src/plugins/env/envDoc.md +7 -8
- package/src/plugins/error/error.js +56 -15
- package/src/plugins/file/README.md +12 -3
- package/src/plugins/file/file.js +2 -2
- package/src/plugins/get/get.js +59 -36
- package/src/plugins/get/getDoc.md +10 -34
- package/src/plugins/google/google.js +115 -0
- package/src/plugins/hedberg/hedberg.js +13 -56
- package/src/plugins/helpers.js +66 -12
- package/src/plugins/index.js +1 -2
- package/src/plugins/instructions/README.md +44 -47
- package/src/plugins/instructions/instructions-system.md +44 -0
- package/src/plugins/instructions/instructions-user.md +53 -0
- package/src/plugins/instructions/instructions.js +58 -189
- package/src/plugins/known/README.md +6 -7
- package/src/plugins/known/known.js +24 -30
- package/src/plugins/log/log.js +41 -32
- package/src/plugins/mv/mv.js +40 -1
- package/src/plugins/mv/mvDoc.md +1 -8
- package/src/plugins/ollama/ollama.js +4 -3
- package/src/plugins/openai/openai.js +4 -3
- package/src/plugins/openrouter/openrouter.js +14 -4
- package/src/plugins/persona/README.md +11 -13
- package/src/plugins/persona/default.md +29 -0
- package/src/plugins/persona/persona.js +10 -66
- package/src/plugins/policy/policy.js +23 -22
- package/src/plugins/prompt/README.md +37 -27
- package/src/plugins/prompt/prompt.js +13 -19
- package/src/plugins/rm/rm.js +18 -0
- package/src/plugins/rm/rmDoc.md +5 -6
- package/src/plugins/rpc/rpc.js +3 -3
- package/src/plugins/set/set.js +205 -323
- package/src/plugins/set/setDoc.md +47 -17
- package/src/plugins/sh/README.md +6 -5
- package/src/plugins/sh/sh.js +8 -5
- package/src/plugins/sh/shDoc.md +7 -8
- package/src/plugins/skill/README.md +37 -14
- package/src/plugins/skill/skill.js +200 -101
- package/src/plugins/skill/skillDoc.js +3 -0
- package/src/plugins/skill/skillDoc.md +9 -0
- package/src/plugins/stream/README.md +7 -6
- package/src/plugins/stream/finalize.js +100 -0
- package/src/plugins/stream/stream.js +13 -45
- package/src/plugins/telemetry/telemetry.js +27 -4
- package/src/plugins/think/think.js +2 -3
- package/src/plugins/think/thinkDoc.md +2 -4
- package/src/plugins/unknown/README.md +1 -1
- package/src/plugins/unknown/unknown.js +17 -19
- package/src/plugins/update/update.js +4 -51
- package/src/plugins/update/updateDoc.md +21 -6
- package/src/plugins/xai/xai.js +68 -102
- package/src/plugins/yolo/yolo.js +102 -75
- package/src/sql/functions/hedmatch.js +1 -1
- package/src/sql/functions/hedreplace.js +1 -1
- package/src/sql/functions/hedsearch.js +1 -1
- package/src/sql/functions/slugify.js +16 -2
- package/BENCH_ENVIRONMENT.md +0 -230
- package/CLIENT_INTERFACE.md +0 -396
- package/last_run.txt +0 -5617
- package/scriptify/ask_run.js +0 -77
- package/scriptify/cache_probe.js +0 -66
- package/scriptify/cache_probe_grok.js +0 -74
- package/src/agent/budget.js +0 -33
- package/src/agent/config.js +0 -38
- package/src/plugins/hedberg/README.md +0 -71
- package/src/plugins/hedberg/docs.md +0 -0
- package/src/plugins/hedberg/edits.js +0 -55
- package/src/plugins/hedberg/normalize.js +0 -17
- package/src/plugins/hedberg/sed.js +0 -49
- package/src/plugins/instructions/instructions.md +0 -34
- package/src/plugins/instructions/instructions_104.md +0 -8
- package/src/plugins/instructions/instructions_105.md +0 -39
- package/src/plugins/instructions/instructions_106.md +0 -22
- package/src/plugins/instructions/instructions_107.md +0 -17
- package/src/plugins/instructions/instructions_108.md +0 -0
- package/src/plugins/known/knownDoc.js +0 -3
- package/src/plugins/known/knownDoc.md +0 -8
- package/src/plugins/unknown/unknownDoc.js +0 -3
- package/src/plugins/unknown/unknownDoc.md +0 -11
- package/turns/cli_1777462658211/turn_001.txt +0 -772
- package/turns/cli_1777462658211/turn_002.txt +0 -606
- package/turns/cli_1777462658211/turn_003.txt +0 -667
- package/turns/cli_1777462658211/turn_004.txt +0 -297
- package/turns/cli_1777462658211/turn_005.txt +0 -301
- package/turns/cli_1777462658211/turn_006.txt +0 -262
- package/turns/cli_1777465095132/turn_001.txt +0 -715
- package/turns/cli_1777465095132/turn_002.txt +0 -236
- package/turns/cli_1777465095132/turn_003.txt +0 -287
- package/turns/cli_1777465095132/turn_004.txt +0 -694
- package/turns/cli_1777465095132/turn_005.txt +0 -422
- package/turns/cli_1777465095132/turn_006.txt +0 -365
- package/turns/cli_1777465095132/turn_007.txt +0 -885
- package/turns/cli_1777465095132/turn_008.txt +0 -1277
- package/turns/cli_1777465095132/turn_009.txt +0 -736
- /package/src/{plugins → lib}/hedberg/patterns.js +0 -0
package/SPEC.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# RUMMY: Architecture Specification
|
|
2
2
|
|
|
3
3
|
The authoritative reference for Rummy's design. The instructions
|
|
4
|
-
plugin (`instructions.md` +
|
|
5
|
-
|
|
6
|
-
everything else.
|
|
4
|
+
plugin (`instructions-system.md` + `instructions-user.md` + tool
|
|
5
|
+
docs) and the persona plugin (`persona/default.md`) define model-
|
|
6
|
+
facing behavior. This document defines everything else.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -18,10 +18,9 @@ uses one of these words, it should mean exactly what's written here.
|
|
|
18
18
|
| **loop** | One `ask` or `act` invocation and all its continuation turns until terminal `<update>`, abandonment, or abort. A run can contain multiple loops if a fresh prompt arrives on an existing run. |
|
|
19
19
|
| **turn** | One round-trip with the LLM: one assembled prompt sent, one response parsed. A loop is a sequence of turns. |
|
|
20
20
|
| **mode** | `ask` (read-only — no proposals, no `<sh>`, no edits) or `act` (full tool surface). Per loop, set at the entry point. |
|
|
21
|
-
| **phase** |
|
|
22
|
-
| **stage** | Model-facing synonym for **phase**. Lives in `instructions_*.md` and tooldocs. |
|
|
21
|
+
| **phase** | The RECORD→DISPATCH split within a single turn (see [dispatch_path](#dispatch_path)). AGENTS.md "Phase 1 / Phase 2 / ..." entries refer to project-development milestones; that's a separate use of the word. The model-facing workflow lives in `persona/default.md` as the 7D ladder — Draft → Decompose → Discover → Distill → Define → Determine → Deliver — a persona convention, not a status-keyed engine state. |
|
|
23
22
|
| **proposal** | A tool-call entry at status 202 awaiting client resolution (accept/reject). Side-effecting actions (`<sh>`, `<env>`, file `<set>`, file `<rm>`/`<mv>`/`<cp>`, `<ask_user>`) emit proposals. YOLO mode auto-accepts. |
|
|
24
|
-
| **verdict** | The end-of-turn ruling from `hooks.
|
|
23
|
+
| **verdict** | The end-of-turn ruling from `hooks.turn.verdict.filter` — a generic filter chain. Returns `{continue, status, reason}`. The error plugin is the canonical subscriber today; future plugins (cycle-detection, budget-overflow termination) can join the chain to vote without touching error.js or AgentLoop. Decides whether the loop continues to another turn or terminates. |
|
|
25
24
|
| **strike** | A turn whose verdict counts toward `MAX_STRIKES`. A strike fires when `turnErrors > 0` (any `error.log` entry that turn) or when cycle detection trips silently. The streak counter resets on a clean turn (no errors, no cycle); reaches `MAX_STRIKES` → loop abandons at 499. |
|
|
26
25
|
| **resolution** | Client's accept/reject of a proposal via `run/resolve` RPC. |
|
|
27
26
|
| **dispatch** | The DISPATCH phase of a turn — actually executing recorded action entries. |
|
|
@@ -124,11 +123,12 @@ hooks-and-filters system. Plugins subscribe to events (fire-and-forget
|
|
|
124
123
|
side effects) and filters (transformation chains that thread a value
|
|
125
124
|
through subscribers in priority order).
|
|
126
125
|
|
|
127
|
-
**Every `<tag>` the model sees is a plugin.** `<
|
|
128
|
-
plugin. `<unknowns>` → unknown plugin. `<
|
|
129
|
-
plugin. `<
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
**Every `<tag>` the model sees is a plugin.** `<summary>` /
|
|
127
|
+
`<visible>` → known plugin. `<unknowns>` → unknown plugin. `<log>`
|
|
128
|
+
→ log plugin. `<instructions>` → instructions plugin. `<prompt>` →
|
|
129
|
+
prompt plugin. `<budget>` → budget plugin. No monolithic assembler
|
|
130
|
+
decides what goes where. Each plugin filters for its own data from
|
|
131
|
+
the shared row set, renders its section, returns.
|
|
132
132
|
|
|
133
133
|
**Plugins compose, they don't coordinate.** A plugin subscribes to a
|
|
134
134
|
filter at a priority, receives the accumulator value, appends its
|
|
@@ -252,7 +252,7 @@ Every entry plays one of four roles:
|
|
|
252
252
|
|
|
253
253
|
| Role | Category | Section | Description |
|
|
254
254
|
|------|----------|---------|-------------|
|
|
255
|
-
| **Data** | `data` | `<
|
|
255
|
+
| **Data** | `data` | `<summary>` + `<visible>` | Entries the model works with — persistent state and captured payload. Summary line in `<summary>` for visible+summarized tiers; full body in `<visible>` only when promoted. |
|
|
256
256
|
| **Logging** | `logging` | `<log>` | Records of what happened — tool results, lifecycle signals |
|
|
257
257
|
| **Unknowns** | `unknown` | `<unknowns>` | Open questions the model is tracking |
|
|
258
258
|
| **Prompt** | `prompt` | `<prompt>` | The task driving the loop |
|
|
@@ -287,7 +287,7 @@ across two namespaces as a direct consequence:
|
|
|
287
287
|
scheme=`log`, category=`logging`. Renders in `<log>`.
|
|
288
288
|
- **Payload channels** live in `{action}://turn_N/{slug}_N` —
|
|
289
289
|
scheme=`{action}` (registered as `category: "data"`). Render in
|
|
290
|
-
`<
|
|
290
|
+
`<summary>` (always, while tracked) and `<visible>` (when
|
|
291
291
|
promoted).
|
|
292
292
|
|
|
293
293
|
This keeps `<log>` a terse audit trail (what happened, exit code,
|
|
@@ -390,11 +390,18 @@ the current loop; pending loops survive. Projects > runs > loops > turns.
|
|
|
390
390
|
|
|
391
391
|
The `file_constraints` table is project-level configuration — it
|
|
392
392
|
defines which files a project cares about. This is backbone, not tool
|
|
393
|
-
dispatch.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
dispatch. Constraint type governs **membership** and **write
|
|
394
|
+
permission**, not in-context visibility. In-context visibility
|
|
395
|
+
(`visible` / `summarized` / `archived`) is per-entry and model-
|
|
396
|
+
controlled — files default to `archived` on ingestion; the model
|
|
397
|
+
promotes via `<get>` / `<set visibility=…>`.
|
|
398
|
+
|
|
399
|
+
- `add` — file is part of the project; ingested as an entry; model
|
|
400
|
+
may write. Default for `setConstraint`.
|
|
401
|
+
- `readonly` — same ingestion; `<set>` is vetoed at the proposal-
|
|
402
|
+
accept gate.
|
|
403
|
+
- `ignore` — excluded from scans entirely. The file remains on disk
|
|
404
|
+
for `<sh>` / `<env>` invocation but is not present as an entry.
|
|
398
405
|
|
|
399
406
|
**Boundary:** Setting a constraint (`File.setConstraint`) is a
|
|
400
407
|
project-config write. Promoting/demoting the matching entries is tool
|
|
@@ -503,9 +510,9 @@ to a continuation (the model's claim of doneness is false); the update
|
|
|
503
510
|
plugin resolves the update entry to 409 and surfaces it to the next
|
|
504
511
|
turn as a continuation. Multiple `<update>` tags → last signal wins.
|
|
505
512
|
|
|
506
|
-
**Post-dispatch budget check:** After all tools dispatch,
|
|
507
|
-
|
|
508
|
-
|
|
513
|
+
**Post-dispatch budget check:** After all tools dispatch, TurnExecutor
|
|
514
|
+
emits `turn.dispatched`; the budget plugin subscribes, re-materializes
|
|
515
|
+
context, and checks the ceiling. If context exceeds the ceiling, Turn
|
|
509
516
|
Demotion fires — all `visible` `run_views` rows for the current turn
|
|
510
517
|
have their `visibility` flipped to `summarized`, and an `error://` entry at status 413 is
|
|
511
518
|
written. Status is NOT touched (see [schemes_status_visibility](#schemes_status_visibility)). The tools already ran;
|
|
@@ -685,44 +692,43 @@ plumbing for the attribute and the rummy-context payload enrichment
|
|
|
685
692
|
on `proposal.pending`. Feature logic stays in
|
|
686
693
|
`src/plugins/yolo/yolo.js`.
|
|
687
694
|
|
|
688
|
-
###
|
|
695
|
+
### Project Manifest {#project_manifest}
|
|
689
696
|
|
|
690
|
-
The `rummy.repo` plugin
|
|
691
|
-
run
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
697
|
+
The `rummy.repo` plugin writes a single `log://turn_0/repo/manifest` entry
|
|
698
|
+
once per run — a flat snapshot of every project file with its token
|
|
699
|
+
cost. It gives the model orientation at run start without burning
|
|
700
|
+
prefix-cache on a turn-keyed regeneration. Files themselves default
|
|
701
|
+
to `archived` so a 5000-file repo doesn't dump hundreds of thousands
|
|
702
|
+
of tokens into context before any work happens.
|
|
695
703
|
|
|
696
704
|
**Entry contract.**
|
|
697
705
|
|
|
698
|
-
- Path: `repo
|
|
699
|
-
|
|
700
|
-
- Visibility: `visible`
|
|
701
|
-
- Body: a
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
706
|
+
- Path: `log://turn_0/repo/manifest` (log scheme; turn-0 marks "before
|
|
707
|
+
any model turn"). One entry per run, written once.
|
|
708
|
+
- Visibility: `visible` at write; demotable like any log entry.
|
|
709
|
+
- Body: a flat list of `* <relative-path> - <N> tokens` lines, one
|
|
710
|
+
per file, sorted by path. No headers, no directory aggregation, no
|
|
711
|
+
constraints, no navigation legend — those are the model's business
|
|
712
|
+
to derive from the list itself or from tooldocs.
|
|
713
|
+
|
|
714
|
+
**Stale by design.** The manifest is a turn-0 snapshot; it does not
|
|
715
|
+
update mid-run. Authoritative current state lives in the per-file
|
|
716
|
+
entries (mtime/hash-driven, change-only writes). The model can
|
|
717
|
+
`<get path="**" preview/>` for a fresh listing if it suspects
|
|
718
|
+
staleness.
|
|
708
719
|
|
|
709
720
|
**File default visibility flip.**
|
|
710
721
|
|
|
711
722
|
`FileScanner` registers each tracked file at `archived` by default
|
|
712
723
|
(was `summarized`). Files with `constraint=active` still register at
|
|
713
|
-
`visible`. The model uses
|
|
724
|
+
`visible`. The model uses the manifest to discover paths, then
|
|
714
725
|
promotes individual files via `<get path=...>` (visible, full body)
|
|
715
726
|
or whole subtrees via `<set path=".../**" visibility="summarized"/>`
|
|
716
727
|
(skim mode, symbols only).
|
|
717
728
|
|
|
718
|
-
**Bounded cost.** The overview body is constant-ish in size regardless
|
|
719
|
-
of repo size: root files capped, directory counts aggregated, no per-
|
|
720
|
-
file symbol enumeration. The token cost in context stays roughly
|
|
721
|
-
flat from a 30-file project to a 50,000-file monorepo.
|
|
722
|
-
|
|
723
729
|
**Disabled when noRepo.** Setting `noRepo: true` on a run skips the
|
|
724
|
-
scan entirely; no
|
|
725
|
-
|
|
730
|
+
scan entirely; no manifest is created and no file entries are
|
|
731
|
+
registered. Behaviour identical to pre-plugin runs.
|
|
726
732
|
|
|
727
733
|
### Streaming Entries {#streaming_entries}
|
|
728
734
|
|
|
@@ -749,13 +755,13 @@ log://turn_N/{action}/{slug} scheme=log category=logging status=202
|
|
|
749
755
|
|
|
750
756
|
{action}://turn_N/{slug}_1 scheme={action} category=data status=102 → 200/500
|
|
751
757
|
body: primary stream (stdout for shell)
|
|
752
|
-
|
|
753
|
-
(line in <
|
|
758
|
+
tags="{command}" visibility=summarized
|
|
759
|
+
(line in <summary>; full body in
|
|
754
760
|
<visible> when promoted)
|
|
755
761
|
|
|
756
762
|
{action}://turn_N/{slug}_2 scheme={action} category=data status=102 → 200/500
|
|
757
763
|
body: alt stream (stderr for shell)
|
|
758
|
-
(line in <
|
|
764
|
+
(line in <summary>; full body in
|
|
759
765
|
<visible> when promoted, often empty)
|
|
760
766
|
```
|
|
761
767
|
|
|
@@ -809,21 +815,32 @@ Two messages per turn. System = stable truth. User = active task.
|
|
|
809
815
|
|
|
810
816
|
```
|
|
811
817
|
[system message]
|
|
812
|
-
instructions text
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
818
|
+
instructions-system.md text (with [%TOOLS%] / [%TOOLDOCS%]
|
|
819
|
+
expansions) + persona body. Resolved by the instructions
|
|
820
|
+
plugin's hooks.instructions.resolveSystemPrompt — single-owner,
|
|
821
|
+
cache-stable across all turns within a run. The assembly.system
|
|
822
|
+
filter chain exists but currently has no subscribers; the
|
|
823
|
+
system message is the resolved system prompt verbatim.
|
|
824
|
+
[user message] (sandwich ordering — see below)
|
|
825
|
+
<prompt tokenUsage="N" tokensFree="M">user prompt</prompt>
|
|
826
|
+
(prompt.js, assembly.user priority 30 — front, cacheable
|
|
827
|
+
across the run within a loop)
|
|
828
|
+
<summary>
|
|
817
829
|
one entry per category=data entry whose visibility is visible
|
|
818
|
-
or summarized
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
830
|
+
or summarized. Each entry renders under its scheme tag with
|
|
831
|
+
its summarized projection as the tag body — the compact-but-
|
|
832
|
+
informative view produced by the plugin's summarized() hook
|
|
833
|
+
(truncated knowns, code symbols for files, page abstracts
|
|
834
|
+
for URLs). Identity-keyed, slow-mutating: only grows when a
|
|
835
|
+
new entry lands. Archived entries — including prompts —
|
|
836
|
+
are filtered out uniformly. There is no instruction-side
|
|
837
|
+
guard against archiving the active prompt — if the model
|
|
838
|
+
archives it, the next turn renders without a <prompt> tag
|
|
839
|
+
and visibly fails (paradigm purity over silent rescue;
|
|
840
|
+
action-gate is the principled future fix per
|
|
841
|
+
src/plugins/prompt/README.md).
|
|
842
|
+
(known.js, assembly.user priority 50)
|
|
843
|
+
</summary>
|
|
827
844
|
<visible>
|
|
828
845
|
each category=data entry whose visibility is visible, rendered
|
|
829
846
|
under its scheme tag with its visible projection as the tag
|
|
@@ -833,63 +850,86 @@ Two messages per turn. System = stable truth. User = active task.
|
|
|
833
850
|
(known.js, assembly.user priority 75)
|
|
834
851
|
</visible>
|
|
835
852
|
<log>
|
|
836
|
-
action history —
|
|
853
|
+
action history — all logging-category entries (log:// audit
|
|
854
|
+
records, error://, update://) plus pre-latest prompt://
|
|
855
|
+
entries (the active prompt is extracted to <prompt>).
|
|
837
856
|
(log.js, assembly.user priority 100)
|
|
838
857
|
</log>
|
|
839
858
|
<unknowns>
|
|
840
|
-
|
|
859
|
+
open questions at category=unknown, rendered under <unknown>
|
|
860
|
+
children with their bodies as questions. (unknown.js,
|
|
861
|
+
assembly.user priority 150)
|
|
841
862
|
</unknowns>
|
|
842
863
|
<instructions>
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
864
|
+
instructions-user.md text. Per-turn imperative reminders.
|
|
865
|
+
Same bytes every turn — no phase keying, no status-driven
|
|
866
|
+
selection. (instructions.js, assembly.user priority 165)
|
|
846
867
|
</instructions>
|
|
847
|
-
<
|
|
868
|
+
<budget tokenUsage="N" tokensFree="M">…breakdown table…</budget>
|
|
869
|
+
(budget.js, assembly.user priority 175 — last, recency for
|
|
870
|
+
the live accounting at the action site)
|
|
848
871
|
```
|
|
849
872
|
|
|
850
873
|
**System** = stable world state the model operates within (identity,
|
|
851
|
-
tools, tool docs). Stable across turns within a run, which
|
|
852
|
-
prompt caching intact. **User** = active work
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
`<instructions>` and the codebase
|
|
856
|
-
|
|
857
|
-
mutable state in system would invalidate the
|
|
858
|
-
|
|
874
|
+
tools, tool docs, persona). Stable across turns within a run, which
|
|
875
|
+
keeps prompt caching intact. **User** = active work: the project's
|
|
876
|
+
data surface, history, open questions, current task, and live
|
|
877
|
+
accounting. The user message changes turn-to-turn so it sits outside
|
|
878
|
+
the prefix-cacheable region; both `<instructions>` and the codebase
|
|
879
|
+
blocks (`<summary>` / `<visible>`) live here because they mutate at
|
|
880
|
+
turn cadence — putting mutable state in system would invalidate the
|
|
881
|
+
cache on every promote.
|
|
882
|
+
|
|
883
|
+
**Sandwich ordering.** User-message blocks are arranged
|
|
884
|
+
`<prompt>` (30, front) → `<summary>` (50) → `<visible>` (75) →
|
|
885
|
+
`<log>` (100) → `<unknowns>` (150) → `<instructions>` (165) →
|
|
886
|
+
`<budget>` (175, last). The prompt sits at the front (cacheable
|
|
887
|
+
across turns of a loop, since it doesn't change within a loop); the
|
|
888
|
+
instructions and budget sit at the tail so the rules and live
|
|
889
|
+
accounting have recency at the action site. An earlier front-loaded
|
|
890
|
+
ordering (instructions first for max cache) regressed terminal-
|
|
891
|
+
`<update>` discipline in e2e — the model lost the rule when it sat
|
|
892
|
+
3K tokens upstream of the action. Recency at the action site beats
|
|
893
|
+
cache savings when the action depends on remembering a rule.
|
|
859
894
|
|
|
860
895
|
**Why two blocks instead of one `<context>`.** Promote/demote is the
|
|
861
|
-
dominant intra-
|
|
862
|
-
|
|
863
|
-
`<
|
|
896
|
+
dominant intra-loop operation. A single-block render would
|
|
897
|
+
invalidate the entire data surface on every promote. With the split,
|
|
898
|
+
`<summary>` mutates only when a new entry lands (slow); `<visible>`
|
|
864
899
|
mutates on every promote/demote (fast). Ordering slow-above-fast
|
|
865
|
-
preserves the prefix cache for `<
|
|
866
|
-
Cognitively: `<
|
|
900
|
+
preserves the prefix cache for `<summary>` across the common case.
|
|
901
|
+
Cognitively: `<summary>` is "what I know exists" (identity);
|
|
867
902
|
`<visible>` is "what I'm reading right now" (working memory).
|
|
868
903
|
|
|
869
904
|
The `<prompt>` tag is present on every turn — first turn and
|
|
870
|
-
continuations alike. The model always sees its task. The
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
attributes so the model can do budget arithmetic in-line with the cause.
|
|
905
|
+
continuations alike. The model always sees its task. The
|
|
906
|
+
`tokenUsage` / `tokensFree` attributes also appear on `<budget>` so
|
|
907
|
+
the model can do budget arithmetic at both ends of the user message.
|
|
874
908
|
|
|
875
|
-
### Loops
|
|
909
|
+
### Loops and Cross-Loop Continuity {#loops_previous_performed}
|
|
876
910
|
|
|
877
911
|
A **loop** is one `ask` or `act` invocation and all its continuation
|
|
878
|
-
turns until `<update status="200">`, fail, or abort.
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
(
|
|
888
|
-
|
|
912
|
+
turns until `<update status="200">`, fail, or abort. A run may
|
|
913
|
+
contain many loops; pending loops queue FIFO via the loops table.
|
|
914
|
+
|
|
915
|
+
Cross-loop continuity is carried by the entry store itself:
|
|
916
|
+
|
|
917
|
+
- **Knowns, files, unknowns** persist across loop boundaries with
|
|
918
|
+
whatever visibility the model left them at. They render in
|
|
919
|
+
`<summary>` / `<visible>` per visibility, regardless of which
|
|
920
|
+
loop wrote them.
|
|
921
|
+
- **Log entries** (action audit, errors, updates) accumulate at
|
|
922
|
+
`log://turn_N/...` for every turn of every loop; `log.js`
|
|
923
|
+
renders all logging-category entries plus pre-latest prompts in
|
|
924
|
+
`<log>` in chronological order.
|
|
925
|
+
- **The active prompt** is extracted from its chronological
|
|
926
|
+
position and rendered as `<prompt>` at priority 30 (front);
|
|
927
|
+
prior prompts render in `<log>` like any other logging entry.
|
|
889
928
|
|
|
890
929
|
When a new prompt arrives on an existing run, the prior loop's
|
|
891
|
-
|
|
892
|
-
|
|
930
|
+
`prompt://N` entry stays in the store; on the next assembly it
|
|
931
|
+
falls out of `<prompt>` (replaced by the new prompt) and into
|
|
932
|
+
`<log>` — visibility-driven re-rendering of the same entry rows.
|
|
893
933
|
|
|
894
934
|
### Key Entries {#key_entries}
|
|
895
935
|
|
|
@@ -911,23 +951,33 @@ Each turn:
|
|
|
911
951
|
|
|
912
952
|
1. Write `instructions://system` (empty body, attributes = { persona, toolSet })
|
|
913
953
|
2. Emit `turn.started` — plugins write prompt/instructions entries
|
|
914
|
-
3. Resolve the instructions system prompt
|
|
954
|
+
3. Resolve the instructions system prompt
|
|
955
|
+
(`hooks.instructions.resolveSystemPrompt` — single-owner; see
|
|
956
|
+
AGENTS.md "Architectural exceptions"). Returns
|
|
957
|
+
`instructions-system.md` with `[%TOOLS%]` / `[%TOOLDOCS%]`
|
|
958
|
+
expanded, persona body appended.
|
|
915
959
|
4. Query `v_model_context` VIEW → visible entries (joined from
|
|
916
960
|
`run_views` + `entries` + `schemes`)
|
|
917
961
|
5. Project each entry through its scheme's `visible`/`summarized` projection
|
|
918
962
|
6. Insert projected rows into `turn_context`
|
|
919
|
-
7. Invoke `assembly.system` filter chain
|
|
920
|
-
|
|
921
|
-
|
|
963
|
+
7. Invoke `assembly.system` filter chain — currently no
|
|
964
|
+
subscribers, so the system message is the resolved system
|
|
965
|
+
prompt verbatim.
|
|
922
966
|
8. Invoke `assembly.user` filter chain (empty string as base):
|
|
923
|
-
-
|
|
924
|
-
|
|
925
|
-
-
|
|
926
|
-
|
|
967
|
+
- Prompt plugin (priority 30) → `<prompt>` element (carries
|
|
968
|
+
`tokenUsage` / `tokensFree` attrs)
|
|
969
|
+
- Known plugin (priority 50) → `<summary>` section
|
|
970
|
+
- Known plugin (priority 75) → `<visible>` section
|
|
971
|
+
- Log plugin (priority 100) → `<log>` section
|
|
972
|
+
- Unknown plugin (priority 150) → `<unknowns>` section
|
|
973
|
+
- Instructions plugin (priority 165) → `<instructions>` section
|
|
974
|
+
(renders `instructions-user.md`)
|
|
975
|
+
- Budget plugin (priority 175) → `<budget>` element (carries
|
|
976
|
+
`tokenUsage` / `tokensFree` and per-scheme breakdown)
|
|
927
977
|
9. Store as `system://N` and `user://N` audit entries (telemetry plugin)
|
|
928
978
|
|
|
929
979
|
The VIEW determines visibility from `visibility` and `status`:
|
|
930
|
-
- `visibility = 'visible'` → full body visible in `<
|
|
980
|
+
- `visibility = 'visible'` → full body visible in `<visible>` (data) or `<log>` (logging).
|
|
931
981
|
- `visibility = 'summarized'` → summarized projection visible (typically path +
|
|
932
982
|
summary attr). Promote with `<get>` to expand.
|
|
933
983
|
- `visibility = 'archived'` → invisible. Discoverable via pattern search
|
|
@@ -947,6 +997,29 @@ Model controls visibility via `<set>` attributes:
|
|
|
947
997
|
attaches a description (≤ 80 chars) that persists across visibility
|
|
948
998
|
changes.
|
|
949
999
|
|
|
1000
|
+
### Filesystem Freshness {#filesystem_freshness}
|
|
1001
|
+
|
|
1002
|
+
After any mutation of a file or scheme entry, the next turn's
|
|
1003
|
+
assembled context reflects the post-mutation body AND visibility,
|
|
1004
|
+
without the model needing a fresh `<get>` to recover its own
|
|
1005
|
+
changes. The model's view of the entry store is always a faithful
|
|
1006
|
+
projection of current state — there is no read-after-write skew.
|
|
1007
|
+
|
|
1008
|
+
The invariant has two parts:
|
|
1009
|
+
|
|
1010
|
+
1. **Body freshness** — a write that changes the entry body shows
|
|
1011
|
+
the new body on the next assembly's `<visible>` (when visible)
|
|
1012
|
+
or under `<get>` (when summarized/archived).
|
|
1013
|
+
2. **Visibility freshness** — a write that explicitly sets
|
|
1014
|
+
`visibility=...` honors the requested level on the next
|
|
1015
|
+
assembly. Edit-path side effects (e.g., a SEARCH/REPLACE accept
|
|
1016
|
+
silently downgrading visibility) violate the invariant; the
|
|
1017
|
+
model would answer the next turn from memory of pre-edit state
|
|
1018
|
+
while the new body sits invisible.
|
|
1019
|
+
|
|
1020
|
+
Enforcement: `test/integration/file_freshness.test.js` exercises
|
|
1021
|
+
write-through for both file and scheme entries.
|
|
1022
|
+
|
|
950
1023
|
### Token Accounting {#token_accounting}
|
|
951
1024
|
|
|
952
1025
|
Tokens are a property of the materialized packet, not of stored entries.
|
|
@@ -1021,49 +1094,55 @@ an entry is being written.
|
|
|
1021
1094
|
### Budget Enforcement {#budget_enforcement}
|
|
1022
1095
|
|
|
1023
1096
|
The model owns its context. The system enforces a hard ceiling and
|
|
1024
|
-
surfaces the numbers
|
|
1097
|
+
surfaces the numbers. Auto-demotion is reserved for the 413 budget
|
|
1098
|
+
grinder, which only fires in response to actual overflow — never
|
|
1099
|
+
helpfully or speculatively.
|
|
1025
1100
|
|
|
1026
1101
|
**Ceiling.** `ceiling = floor(contextSize × RUMMY_BUDGET_CEILING)`
|
|
1027
1102
|
(default `RUMMY_BUDGET_CEILING = 0.9`, i.e. 10% headroom). All budget
|
|
1028
1103
|
decisions compare `assembledTokens` against `ceiling`, never against
|
|
1029
1104
|
`contextSize` directly.
|
|
1030
1105
|
|
|
1031
|
-
**Pre-LLM
|
|
1032
|
-
the LLM call
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
**
|
|
1053
|
-
`
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1106
|
+
**Pre-LLM grinder** (`hooks.turn.beforeDispatch.filter`, in
|
|
1107
|
+
TurnExecutor before the LLM call; budget is the canonical
|
|
1108
|
+
subscriber). A four-step ladder. Each step demotes a strictly smaller
|
|
1109
|
+
scope and rechecks. The first step that fits the ceiling proceeds to
|
|
1110
|
+
the LLM; if step 4 fires, AgentLoop exits the loop with 413.
|
|
1111
|
+
|
|
1112
|
+
1. **Check budget.** Measure `assembledTokens` (using
|
|
1113
|
+
`turns.context_tokens` from the prior turn when available, the
|
|
1114
|
+
materialized packet estimate as a first-turn fallback). If
|
|
1115
|
+
`assembledTokens ≤ ceiling`, proceed to the LLM.
|
|
1116
|
+
2. **Soft 413 — previous-turn demotion.** Flip every `run_views`
|
|
1117
|
+
row where `turn = current_turn - 1 AND visibility = visible` to
|
|
1118
|
+
`summarized` (status preserved — see
|
|
1119
|
+
[schemes_status_visibility](#schemes_status_visibility)). All
|
|
1120
|
+
schemes participate; no exemption for knowns / unknowns /
|
|
1121
|
+
files. Re-materialize, re-check.
|
|
1122
|
+
3. **Soft 413 — current-prompt demotion.** Flip the incoming
|
|
1123
|
+
`prompt://N` entry to `summarized`. Re-materialize, re-check.
|
|
1124
|
+
Step 3 exists because the prompt is stamped at `current_turn`,
|
|
1125
|
+
not the previous turn — step 2's filter never sees it. Without
|
|
1126
|
+
step 3, an oversized first-turn prompt has no path to fit.
|
|
1127
|
+
4. **Hard 413.** Emit a 413 `error://` entry via
|
|
1128
|
+
`hooks.error.log.emit` with the descriptive body (what was
|
|
1129
|
+
demoted across steps 2-3, the ceiling, the residual overflow).
|
|
1130
|
+
AgentLoop exits the loop with 413.
|
|
1131
|
+
|
|
1132
|
+
Steps 2 and 3 also emit 413 `error://` entries when they fire
|
|
1133
|
+
(distinct from step 4 in that the run keeps going). The model reads
|
|
1134
|
+
those next turn and learns what got auto-demoted. Status of the
|
|
1135
|
+
turn that proceeded after a soft 413 is unaffected.
|
|
1136
|
+
|
|
1137
|
+
**Trunks and forks are treated identically.** A forked run inherits
|
|
1138
|
+
the parent's `run_views` rows verbatim — each entry keeps its
|
|
1139
|
+
original `turn`. There is no fork-event restamping. The grinder's
|
|
1140
|
+
`current_turn - 1` rule applies the same way in both cases. For
|
|
1141
|
+
the rule to point at meaningful inherited content on a fork's first
|
|
1142
|
+
dispatch, the child run inherits the parent's `next_turn` so turn
|
|
1143
|
+
numbering is absolute across the lineage; sibling forks share the
|
|
1144
|
+
same prior history at lower turn numbers and only diverge at
|
|
1145
|
+
fork-time.
|
|
1067
1146
|
|
|
1068
1147
|
**LLM-reported context exceeded.** If the LLM rejects the request
|
|
1069
1148
|
with a "context too long" error (detected via the regex in
|
|
@@ -1147,9 +1226,9 @@ on `get` also sets a project-level file constraint (operator privilege).
|
|
|
1147
1226
|
|
|
1148
1227
|
| Method | Params |
|
|
1149
1228
|
|--------|--------|
|
|
1150
|
-
| `startRun` | `{ model, temperature?, persona?, contextLimit? }` |
|
|
1151
|
-
| `ask` | `{ prompt, model, run?, temperature?, persona?, contextLimit?, noRepo?, noInteraction?, noWeb?, fork? }` |
|
|
1152
|
-
| `act` | `{ prompt, model, run?, temperature?, persona?, contextLimit?, noRepo?, noInteraction?, noWeb?, fork? }` |
|
|
1229
|
+
| `startRun` | `{ model, temperature?, persona?, contextLimit?, yolo? }` |
|
|
1230
|
+
| `ask` | `{ prompt, model, run?, temperature?, persona?, contextLimit?, noRepo?, noInteraction?, noWeb?, noProposals?, yolo?, fork? }` |
|
|
1231
|
+
| `act` | `{ prompt, model, run?, temperature?, persona?, contextLimit?, noRepo?, noInteraction?, noWeb?, noProposals?, yolo?, fork? }` |
|
|
1153
1232
|
| `run/resolve` | `{ run, resolution: { path, action, output? } }` |
|
|
1154
1233
|
| `run/abort` | `{ run }` |
|
|
1155
1234
|
| `run/rename` | `{ run, name }` |
|
|
@@ -1161,6 +1240,10 @@ on `get` also sets a project-level file constraint (operator privilege).
|
|
|
1161
1240
|
be added explicitly by the client).
|
|
1162
1241
|
`noInteraction` removes `ask_user` from the tool list.
|
|
1163
1242
|
`noWeb` removes `search` from the tool list.
|
|
1243
|
+
`noProposals` removes `ask_user` / `env` / `sh` from the tool list
|
|
1244
|
+
(no proposals at all).
|
|
1245
|
+
`yolo` opts the run into server-side proposal auto-accept and
|
|
1246
|
+
in-process sh/env execution — see [yolo_mode](#yolo_mode).
|
|
1164
1247
|
|
|
1165
1248
|
#### Streaming (see [streaming_entries](#streaming_entries))
|
|
1166
1249
|
|
|
@@ -1190,17 +1273,20 @@ connected clients). `stream/cancel` also handles stale 102 cleanup.
|
|
|
1190
1273
|
|
|
1191
1274
|
#### Skills & Personas
|
|
1192
1275
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
`
|
|
1276
|
+
Both attach to a run via the entry grammar.
|
|
1277
|
+
|
|
1278
|
+
- **Skills** — model emits `<skill path="[path-or-url]"/>`.
|
|
1279
|
+
Handler walks local file/folder/`.zip` (via `yauzl-promise`) or
|
|
1280
|
+
fetches a URL. Single `.md` registers as `skill://<name>`
|
|
1281
|
+
(summarized); folder/zip registers root `index.md` summarized,
|
|
1282
|
+
rest archived; `foo/index.md` collapses to `skill://<name>/foo`.
|
|
1283
|
+
Re-emit overwrites. Authors link with absolute `skill://...` URIs.
|
|
1284
|
+
- **Personas** — `ask` / `act` / `startRun` accept `persona` as a
|
|
1285
|
+
run attribute. The persona plugin renders the persona body inside
|
|
1286
|
+
the system prompt (below tooldocs) on first turn; if no `persona`
|
|
1287
|
+
is passed, `AgentLoop.ensureRun` defaults to
|
|
1288
|
+
`src/plugins/persona/default.md`. 1:1 run:persona, immutable for
|
|
1289
|
+
the run's lifetime.
|
|
1204
1290
|
|
|
1205
1291
|
### Notifications {#notifications}
|
|
1206
1292
|
|
|
@@ -1378,18 +1464,116 @@ are universal — not a feature of any single tool.
|
|
|
1378
1464
|
|
|
1379
1465
|
---
|
|
1380
1466
|
|
|
1381
|
-
##
|
|
1467
|
+
## Edit Syntax
|
|
1468
|
+
|
|
1469
|
+
The model expresses entry writes through `<set path="..."><body></set>`.
|
|
1470
|
+
The body shape determines the operation. All shaped operations use a
|
|
1471
|
+
bash-heredoc-flavored marker family.
|
|
1472
|
+
|
|
1473
|
+
### Marker Grammar
|
|
1474
|
+
|
|
1475
|
+
<<IDENT
|
|
1476
|
+
body content
|
|
1477
|
+
IDENT
|
|
1478
|
+
|
|
1479
|
+
Where `IDENT` matches `[A-Z][A-Za-z0-9_]*`. The leading keyword of
|
|
1480
|
+
`IDENT` selects the operation; any trailing alphanumeric suffix is
|
|
1481
|
+
opaque to operation routing and exists to disambiguate nested markers
|
|
1482
|
+
or avoid collisions when the body literally contains the bare keyword
|
|
1483
|
+
(same convention as bash heredoc `<<EOF1` vs `<<EOF`).
|
|
1484
|
+
|
|
1485
|
+
The opener `<<IDENT` must be preceded by start-of-body, whitespace,
|
|
1486
|
+
or `>` (so `vec<<SEARCH` mid-token does not false-trigger). The
|
|
1487
|
+
closer is bare `IDENT` with whitespace boundaries on both sides.
|
|
1488
|
+
|
|
1489
|
+
Newline-tolerant: the multi-line shape above and the single-line
|
|
1490
|
+
`<<IDENT body IDENT` form parse identically.
|
|
1491
|
+
|
|
1492
|
+
### Distinct from Packet Rendering
|
|
1493
|
+
|
|
1494
|
+
The engine renders entry bodies in context using a different marker
|
|
1495
|
+
shape: `<<:::path...:::path` (see `plugins/helpers.js`). Edit syntax
|
|
1496
|
+
is the bare `<<IDENT` form; packet rendering keeps the `:::` sentinel.
|
|
1497
|
+
The two grammars are visibly distinct so model emissions and engine
|
|
1498
|
+
renderings can never be confused. A `<set>` body echoing the packet
|
|
1499
|
+
shape is NOT treated as edit syntax — it falls through to plain-body
|
|
1500
|
+
REPLACE with the markers preserved as literal content.
|
|
1501
|
+
|
|
1502
|
+
### Operations
|
|
1503
|
+
|
|
1504
|
+
| IDENT prefix | Effect |
|
|
1505
|
+
|---|---|
|
|
1506
|
+
| `NEW` | Create the entry. Behaves identically to `REPLACE` on existing entries — named separately to align with model intent. |
|
|
1507
|
+
| `PREPEND` | Prepend body content to the existing entry. Creates the entry if it doesn't exist. |
|
|
1508
|
+
| `APPEND` | Append body content to the existing entry. Creates the entry if it doesn't exist. |
|
|
1509
|
+
| `REPLACE` | Replace the entire entry body with the marker content. Standalone (not preceded by `SEARCH`). |
|
|
1510
|
+
| `DELETE` | Remove a literal-matching region from the existing entry body. The marker content is the region to remove. |
|
|
1511
|
+
| `SEARCH` | Match a literal region in the existing entry body. Must be immediately followed by a `REPLACE` block; the pair is an in-place edit. |
|
|
1512
|
+
|
|
1513
|
+
### SEARCH / REPLACE Pairs
|
|
1514
|
+
|
|
1515
|
+
Surgical in-place edits. `SEARCH` must be immediately followed by
|
|
1516
|
+
`REPLACE` (no intervening operation):
|
|
1517
|
+
|
|
1518
|
+
<set path="src/main.go"><<SEARCH
|
|
1519
|
+
old line
|
|
1520
|
+
SEARCH
|
|
1521
|
+
<<REPLACE
|
|
1522
|
+
new line
|
|
1523
|
+
REPLACE</set>
|
|
1524
|
+
|
|
1525
|
+
Multiple pairs in one `<set>` body apply in order against the
|
|
1526
|
+
progressively-edited body.
|
|
1527
|
+
|
|
1528
|
+
### Suffix for Body Collisions
|
|
1529
|
+
|
|
1530
|
+
When the body content literally contains a marker keyword (`SEARCH`
|
|
1531
|
+
in prose, `<<` in code), the model appends a digit or alphanumeric
|
|
1532
|
+
suffix to the IDENT so the inner literal does not prematurely close
|
|
1533
|
+
the outer marker:
|
|
1534
|
+
|
|
1535
|
+
<set path="docs/grammar.md"><<DOC1
|
|
1536
|
+
The opener is <<SEARCH and the closer is bare SEARCH alone on
|
|
1537
|
+
a line. Use <<SEARCH1 ... SEARCH1 if your body contains literal
|
|
1538
|
+
SEARCH or <<SEARCH tokens.
|
|
1539
|
+
DOC1</set>
|
|
1540
|
+
|
|
1541
|
+
### Errors
|
|
1542
|
+
|
|
1543
|
+
| Condition | Outcome |
|
|
1544
|
+
|---|---|
|
|
1545
|
+
| `SEARCH` content not found in current body | conflict (soft) |
|
|
1546
|
+
| `DELETE` content not found in current body | conflict (soft) |
|
|
1547
|
+
| Lone `SEARCH` (no following `REPLACE`) | parse error |
|
|
1548
|
+
| Unclosed marker (opener with no matching `IDENT` closer) | parse error |
|
|
1549
|
+
| Non-keyword `IDENT` (e.g. `<<EOF`, `<<DOC`) | routes to REPLACE — inner content becomes the new body |
|
|
1550
|
+
| `<set>` body with no `<<IDENT` markers at all | full-body REPLACE (tolerated; not demonstrated to models) |
|
|
1551
|
+
|
|
1552
|
+
### Pattern Matching
|
|
1553
|
+
|
|
1554
|
+
The literal-match semantics used by `SEARCH` and `DELETE` are
|
|
1555
|
+
delegated to the Hedberg pattern library — see [hedberg](#hedberg).
|
|
1556
|
+
Matching is fuzzy on whitespace and indentation; an exact-byte match
|
|
1557
|
+
is not required.
|
|
1558
|
+
|
|
1559
|
+
---
|
|
1560
|
+
|
|
1561
|
+
## Hedberg Pattern Library {#hedberg}
|
|
1562
|
+
|
|
1563
|
+
The pattern library exposed to every plugin through `core.hooks.hedberg`.
|
|
1564
|
+
Used internally by the Edit Syntax (above) for `SEARCH` / `DELETE`
|
|
1565
|
+
matching and by `<get>` / `<rm>` for path globs.
|
|
1382
1566
|
|
|
1383
|
-
|
|
1567
|
+
| Function | Purpose |
|
|
1568
|
+
|---|---|
|
|
1569
|
+
| `match(pattern, string)` | Full-string match — paths, equality. |
|
|
1570
|
+
| `search(pattern, string)` | Substring search — content filtering. |
|
|
1571
|
+
| `replace(text, search, replace, options)` | Patch application; fuzzy on whitespace and indentation. |
|
|
1572
|
+
| `generatePatch(path, oldBody, newBody)` | Unified-diff rendering for telemetry. |
|
|
1384
1573
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
4. Sed syntax: `s/old/new/flags`
|
|
1389
|
-
5. Claude XML: `<old_text>old</old_text><new_text>new</new_text>`
|
|
1390
|
-
6. JSON body: `{"search": "old", "replace": "new"}` or `{search="old", replace="new"}`
|
|
1391
|
-
7. XML attributes: `<set search="old" replace="new"/>`
|
|
1392
|
-
8. Full replacement: anything else becomes the new content
|
|
1574
|
+
Pattern types: glob (picomatch-backed, with `**` cross-slash and
|
|
1575
|
+
`!()` negation), regex (`/pattern/flags`), xpath, jsonpath. Detection
|
|
1576
|
+
is by syntactic shape — see `src/lib/hedberg/patterns.js`.
|
|
1393
1577
|
|
|
1394
1578
|
---
|
|
1395
1579
|
|
|
@@ -1477,10 +1661,9 @@ htmlparser2 dropped. Close current, open new, emit recovery warning.
|
|
|
1477
1661
|
attributes on the open tag *and* body text inside the tag. If the
|
|
1478
1662
|
canonical attribute is missing, the body silently fills it. The
|
|
1479
1663
|
shape per tool:
|
|
1480
|
-
- `set` —
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
attr-set, plain write).
|
|
1664
|
+
- `set` — body parsed via `parseMarkerBody` (see "Edit Syntax"
|
|
1665
|
+
above): `<<:::IDENT...:::IDENT` markers route to `operations`
|
|
1666
|
+
list; bodies without markers are plain-body REPLACE.
|
|
1484
1667
|
- `update` — body fills `body`, status defaults to 102 if absent.
|
|
1485
1668
|
- `get` / `rm` — attr `path` or body fills target. Spread `a` so
|
|
1486
1669
|
`line` / `limit` / `visibility` / future attrs reach the handler.
|
|
@@ -1642,7 +1825,7 @@ Full reference is `.env.example` — these are the load-bearing vars.
|
|
|
1642
1825
|
| Var | Default | Purpose |
|
|
1643
1826
|
|-----|---------|---------|
|
|
1644
1827
|
| `PORT` | 3044 | WebSocket port |
|
|
1645
|
-
| `RUMMY_HOME` | `~/.rummy` |
|
|
1828
|
+
| `RUMMY_HOME` | `~/.rummy` | Local config root. Used by telemetry; available for future per-user state. |
|
|
1646
1829
|
| `RUMMY_DB_PATH` | `rummy.db` | SQLite path |
|
|
1647
1830
|
| `RUMMY_MMAP_MB` | 0 | SQLite mmap hint (MB; 0 disables) |
|
|
1648
1831
|
| `RUMMY_DEBUG` | false | Verbose logging |
|
|
@@ -1665,10 +1848,12 @@ Full reference is `.env.example` — these are the load-bearing vars.
|
|
|
1665
1848
|
| `RUMMY_MIN_CYCLES` | 3 | Consecutive repetitions to trigger cycle detection |
|
|
1666
1849
|
| `RUMMY_MAX_CYCLE_PERIOD` | 4 | Max cycle period checked by healer |
|
|
1667
1850
|
| `RUMMY_RETENTION_DAYS` | 31 | Days of completed/aborted runs kept |
|
|
1668
|
-
| `RUMMY_THINK` |
|
|
1669
|
-
| `RUMMY_TEMPERATURE` | 0.
|
|
1851
|
+
| `RUMMY_THINK` | 0 | Reasoning request flag forwarded to LLM provider |
|
|
1852
|
+
| `RUMMY_TEMPERATURE` | 0.1 | Default LLM temperature |
|
|
1670
1853
|
| `RUMMY_RPC_TIMEOUT` | 30000 | RPC timeout (ms) |
|
|
1671
1854
|
| `RUMMY_FETCH_TIMEOUT` | 300000 | LLM HTTP timeout (ms) |
|
|
1855
|
+
| `RUMMY_LLM_DEADLINE` | 600000 | LLM transient-retry deadline (ms). Used as the budget for `warmup` and `rate_limit` categories in `src/llm/retry.js#retryClassified`; gateway/server categories have shorter hardcoded deadlines (30s / 60s). |
|
|
1856
|
+
| `RUMMY_LLM_MAX_BACKOFF` | 30000 | Max single backoff between retry attempts (ms) for warmup/rate_limit categories. |
|
|
1672
1857
|
|
|
1673
1858
|
**LLM providers** (plugin-scoped; a provider with no config is inert):
|
|
1674
1859
|
|
|
@@ -1699,9 +1884,11 @@ local `node_modules` then global).
|
|
|
1699
1884
|
|
|
1700
1885
|
| Var | Purpose |
|
|
1701
1886
|
|-----|---------|
|
|
1702
|
-
| `
|
|
1703
|
-
| `
|
|
1704
|
-
| `
|
|
1887
|
+
| `RUMMY_WEB_SEARXNG_URL` | SearXNG instance URL (SearXNG federates Brave / DuckDuckGo / Wikipedia / etc. upstream and normalizes the responses) |
|
|
1888
|
+
| `RUMMY_WEB_FETCH_TIMEOUT` | Playwright `page.goto` timeout (ms) |
|
|
1889
|
+
| `RUMMY_WEB_PLAYWRIGHT_WS` | Optional CDP endpoint for shared chromium |
|
|
1890
|
+
| `RUMMY_WEB_NO_SANDBOX` | `1` to drop chromium's user-namespace sandbox |
|
|
1891
|
+
| `RUMMY_WEB_CHROMIUM_HEAP_MB` | Cap chromium's V8 heap (MB) |
|
|
1705
1892
|
|
|
1706
1893
|
**Testing:**
|
|
1707
1894
|
|