@hicaru/pi-rlm 0.2.1 → 0.3.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/README.md +28 -47
- package/README.ru.md +18 -23
- package/README.zh-CN.md +17 -28
- package/package.json +22 -19
- package/src/bridge/add-context.ts +322 -0
- package/src/bridge/subcall-handlers.ts +63 -17
- package/src/commands/rlm-config.ts +47 -18
- package/src/commands/rlm.ts +3 -152
- package/src/config/defaults.ts +8 -18
- package/src/config/settings.ts +13 -34
- package/src/context/anydoc.ts +67 -0
- package/src/context/listing.ts +70 -0
- package/src/context/md-cache.ts +112 -0
- package/src/context/merge.ts +97 -0
- package/src/context/namespace.ts +180 -0
- package/src/context/resolve.ts +122 -0
- package/src/context/source-dir.ts +166 -0
- package/src/context/source-doc.ts +71 -0
- package/src/context/source-git.ts +51 -0
- package/src/context/source-text.ts +45 -0
- package/src/context/types.ts +88 -0
- package/src/context/walk.ts +250 -0
- package/src/core/engine.ts +61 -345
- package/src/core/history.ts +1 -1
- package/src/core/limits.ts +5 -12
- package/src/core/resource-limits.ts +0 -2
- package/src/core/types.ts +10 -38
- package/src/index.ts +92 -54
- package/src/mode/llm-model.ts +54 -0
- package/src/mode/rlm-mode.ts +28 -58
- package/src/prompts/glossary.ts +290 -0
- package/src/prompts/native.ts +127 -0
- package/src/prompts/system.ts +15 -408
- package/src/sandbox/context-file.ts +154 -0
- package/src/sandbox/interrupts.ts +160 -0
- package/src/sandbox/protocol.ts +20 -75
- package/src/sandbox/py/__pycache__/guards.cpython-314.pyc +0 -0
- package/src/sandbox/py/__pycache__/retrieval.cpython-314.pyc +0 -0
- package/src/sandbox/py/__pycache__/tasks.cpython-314.pyc +0 -0
- package/src/sandbox/py/guards.py +150 -0
- package/src/sandbox/py/retrieval.py +265 -0
- package/src/sandbox/py/tasks.py +129 -0
- package/src/sandbox/py/worker.py +856 -0
- package/src/sandbox/sandbox-manager.ts +24 -9
- package/src/sandbox/sandbox.ts +99 -193
- package/src/text/tokens.ts +31 -5
- package/src/tool/repl-details.ts +2 -2
- package/src/tool/repl-render.ts +58 -0
- package/src/tool/repl-result.ts +70 -0
- package/src/tool/repl-tool.ts +60 -170
- package/src/tool/rlm-aggregator.ts +2 -10
- package/src/tool/rlm-details.ts +0 -2
- package/src/tool/rlm-events.ts +0 -14
- package/src/tool/rlm-tool.ts +2 -13
- package/src/ui/config-panel.ts +12 -20
- package/src/ui/intro.ts +1 -2
- package/src/ui/model-picker.ts +34 -10
- package/src/ui/status.ts +3 -7
- package/src/util/concurrency.ts +9 -5
- package/src/bridge/fallback-todo.ts +0 -148
- package/src/bridge/interactive.ts +0 -65
- package/src/bridge/library.ts +0 -155
- package/src/bridge/pi-interactive.ts +0 -41
- package/src/context/library-context.ts +0 -266
- package/src/context/repomix-context.ts +0 -204
- package/src/core/artifacts.ts +0 -89
- package/src/core/critique.ts +0 -92
- package/src/core/gates.ts +0 -301
- package/src/core/pipeline-handlers.ts +0 -319
- package/src/core/pipeline.ts +0 -268
- package/src/prompts/phases.ts +0 -104
- package/src/sandbox/worker.py +0 -1456
- package/src/state/index.ts +0 -24
- package/src/state/internal.ts +0 -46
- package/src/state/paths.ts +0 -44
- package/src/state/reads.ts +0 -133
- package/src/state/resume.ts +0 -173
- package/src/state/rows.ts +0 -123
- package/src/state/writes.ts +0 -58
package/README.md
CHANGED
|
@@ -58,7 +58,10 @@ sub-LLM calls, hence the name.
|
|
|
58
58
|
|
|
59
59
|
- A **root orchestrator** model drives a **persistent Python REPL** turn-by-turn.
|
|
60
60
|
- Long-context work is **delegated** to cheap worker models via `llm_query` / `llm_query_batched`.
|
|
61
|
-
- Hard sub-problems **recurse** into child RLMs via `rlm_query` (depth-capped).
|
|
61
|
+
- Hard sub-problems **recurse** into child RLMs via `rlm_query` (depth-capped). A child inherits
|
|
62
|
+
its parent's `context` — every file loaded so far, including sources added with `add_context()` —
|
|
63
|
+
so it runs the same retrieval primitives over the same paths. Inheritance costs no extra tokens:
|
|
64
|
+
the content lives in the sandbox, and only a size line reaches the model.
|
|
62
65
|
- Everything runs **in-process** — the only external process is one local `python3` worker.
|
|
63
66
|
|
|
64
67
|
> This is a Pi-plugin reimplementation of the RLM method (see the [RLM paper](https://arxiv.org/abs/2512.24601)).
|
|
@@ -94,9 +97,6 @@ sub-LLM calls, hence the name.
|
|
|
94
97
|
| `/rlm` | `Ctrl+Shift+R` | Toggle persistent RLM mode (route plain prompts through the RLM engine) |
|
|
95
98
|
| `/rlm-stop` | | Abort an in-progress run |
|
|
96
99
|
| `/rlm-config` | | Pick smart + worker models and tune run settings |
|
|
97
|
-
| `/rlm-resume` | | Resume an interrupted run (default `@latest`) |
|
|
98
|
-
| `/rlm-runs` | | List recent runs |
|
|
99
|
-
| `/rlm-help` | | Show the startup guide & cheatsheet |
|
|
100
100
|
|
|
101
101
|
While a run is active, a **live tree** shows the root orchestrator and every sub-LLM /
|
|
102
102
|
recursive child with status, model, cost, tokens, and duration. The final answer is posted
|
|
@@ -109,51 +109,36 @@ These functions are injected into the model's Python namespace inside the REPL:
|
|
|
109
109
|
|
|
110
110
|
| Function | Signature | Description |
|
|
111
111
|
|---|---|---|
|
|
112
|
-
| `context` | `list[dict]` |
|
|
112
|
+
| `context` | `list[dict]` | Loaded files as `[{"path","content","tokens"}, …]` — starts empty; cwd seeds on first `repl()` |
|
|
113
113
|
| `llm_query` | `(prompt, model=None) -> str` | One-shot sub-LLM call (worker model) |
|
|
114
114
|
| `llm_query_batched` | `(prompts, model=None) -> list[str]` | Concurrent sub-LLM calls (pool-bounded) |
|
|
115
115
|
| `llm_query_chunked` | `(text, prompt, model=None) -> list[str]` | Split large text into cap-sized chunks and fan out via sub-LLMs |
|
|
116
|
-
| `rlm_query` | `(prompt, model=None) -> str` | Recursive child RLM with its own sandbox (depth-capped) |
|
|
117
|
-
| `rlm_query_batched` | `(prompts, model=None) -> list[str]` | Concurrent recursive child RLMs |
|
|
118
|
-
| `
|
|
119
|
-
| `ask_user_question` | `(questions) -> list[dict]` | Ask the user structured questions (depth 0 only) |
|
|
120
|
-
| `load_library` | `(source) -> dict \| str` | Append an external dir, file, or git URL into `context` under `lib/<id>/` |
|
|
121
|
-
| `save_artifact` | `(kind, content) -> str` | Persist a stage artifact (`clarification` / `research` / `plan` / `validation`) under `.rlm/artifacts/` (root depth only). Returns preflight gate critique. |
|
|
122
|
-
| `advance_phase` | `(phase, summary=None) -> str` | Advance one step in order `clarify → research → blueprint → validate` (clarify skipped when `askUserQuestion` is off). **Engine-gated** on the latest artifact + interview rounds. Rejected transitions return the gate error. |
|
|
116
|
+
| `rlm_query` | `(prompt, model=None, paths=None) -> str` | Recursive child RLM with its own sandbox (depth-capped). Inherits your `context`; `paths` narrows it by prefix |
|
|
117
|
+
| `rlm_query_batched` | `(prompts, model=None, paths=None) -> list[str]` | Concurrent recursive child RLMs, sharing one `paths` slice |
|
|
118
|
+
| `add_context` | `(source) -> dict \| str` | Append a dir, file, document, or git URL into `context` under `ctx/<id>/` |
|
|
123
119
|
| `SHOW_VARS` | `() -> str` | List currently defined variables & their types |
|
|
124
120
|
| `answer` | `dict` | Set `answer["content"]=...; answer["ready"]=True` to finalize |
|
|
125
121
|
|
|
126
|
-
###
|
|
122
|
+
### Adding context
|
|
127
123
|
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
`context` starts empty. The working directory seeds automatically on the first `repl()` call
|
|
125
|
+
(un-prefixed paths so `search()` hits remain real paths for `edit`/`write`). For an **external
|
|
126
|
+
tree, document, or git URL**, call `add_context(source)`:
|
|
130
127
|
|
|
131
128
|
```python
|
|
132
|
-
info =
|
|
133
|
-
info =
|
|
134
|
-
info =
|
|
135
|
-
|
|
136
|
-
#
|
|
129
|
+
info = add_context("../some-lib") # local directory → packed + appended
|
|
130
|
+
info = add_context("docs/api.md") # single file → one entry in context
|
|
131
|
+
info = add_context("report.pdf") # document → Markdown, then appended
|
|
132
|
+
info = add_context("https://github.com/x/y.git") # shallow clone, then pack + append
|
|
133
|
+
# Files land in the SAME `context` list under ctx/<source_id>/…
|
|
134
|
+
# info == {"source_id", "path_prefix", "files", "chars", "context_len", "already_loaded", "converted", "skipped", …}
|
|
137
135
|
lib = [f for f in context if f["path"].startswith(info["path_prefix"])]
|
|
138
136
|
```
|
|
139
137
|
|
|
140
138
|
There is no `context_1` / `context_2` — only `context`. Paths are namespaced so multiple
|
|
141
|
-
|
|
142
|
-
default on)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
### Artifact-gated pipeline (opt-in via `pipeline: true`)
|
|
146
|
-
|
|
147
|
-
When enabled at root depth:
|
|
148
|
-
|
|
149
|
-
1. **Goal capture** — the brief is written verbatim to `.rlm/artifacts/goal/goal-<ts>.md` with a pre-run dirty-tree baseline.
|
|
150
|
-
2. **Stages** — `clarify → research → blueprint → validate` (**read-only** — produces a validated plan; does not write code). Each produces a durable markdown artifact with frontmatter contracts; chat history is **reset** at every phase boundary (artifacts are the only channel; REPL vars persist).
|
|
151
|
-
3. **Clarify (intake)** — interviews the user via `ask_user_question` (intent first, then evidence-confirmed decisions). Writes `.rlm/artifacts/clarifications/*` with `decisions_count` / `open_questions_count`. Engine gate: **≥1 serviced ask round** + artifact contract. When **`askUserQuestion` is off**, clarify is skipped and the run starts at research.
|
|
152
|
-
4. **Gates (TypeScript, never LLM judgment)** — `status: ready`; clarify structure; plan `phases:` ≡ fence-aware `## Phase N:` headings; every `file:line` citation resolves; validate carries `blockers_count` + `verdict`. Preflight critique runs on every `save_artifact`.
|
|
153
|
-
5. **Validate** — adversarial plan review against the tree (not a post-implementation diff check). Final answer is the validated plan.
|
|
154
|
-
6. **Corrective loop** — `blockers_count > 0` re-enters blueprint (superseded plan kept for context), bounded by `maxBackwardJumps` (default 2).
|
|
155
|
-
|
|
156
|
-
Native RLM mode authors file changes with Pi's native `edit` / `write` tools. Sub-LLMs extract and locate; they never ship code.
|
|
139
|
+
sources do not collide. Toggle via `/rlm-config` → **Context loader** (`contextLoader`,
|
|
140
|
+
default on) and **Auto-seed cwd** (`autoSeedCwd`, default on). A source loaded at any point is
|
|
141
|
+
inherited by every child spawned afterwards.
|
|
157
142
|
|
|
158
143
|
## Settings (`/rlm-config`)
|
|
159
144
|
|
|
@@ -164,26 +149,22 @@ Native RLM mode authors file changes with Pi's native `edit` / `write` tools. Su
|
|
|
164
149
|
| Max recursion depth | `4` | `rlm_query` past this degrades to plain `llm_query` |
|
|
165
150
|
| Max iterations | `30` | root REPL turns before RLM asks for a final answer |
|
|
166
151
|
| REPL block timeout (s) | `120` | wall-clock limit for one Python REPL block (SIGALRM) |
|
|
167
|
-
| Max concurrent sub-calls | `
|
|
168
|
-
|
|
|
152
|
+
| Max concurrent sub-calls | `16` | concurrency pool size for `*_batched` |
|
|
153
|
+
| Max concurrent children | `6` | concurrent `rlm_query` child engines per depth |
|
|
169
154
|
| Wall-clock ceiling (min) | none | total runtime cap for the whole recursive tree |
|
|
170
155
|
| Token ceiling | none | total input+output token cap for the whole recursive tree |
|
|
171
156
|
| Max consecutive errors | `5` | stop after N consecutive failing turns (none = off) |
|
|
172
157
|
| Orchestrator addendum | on | divide-and-conquer guidance in the root system prompt |
|
|
173
|
-
| Phase pipeline | off | artifact-gated clarify→research→blueprint→validate (read-only plan pipeline) |
|
|
174
|
-
| Max validate→blueprint loops | `2` | bounded corrective re-entries when validation reports blockers |
|
|
175
|
-
| Ask user question | on | when pipeline is on, enables clarify intake; when off, pipeline starts at research |
|
|
176
158
|
| Trajectory compaction | on (0.65) | summarize old turns when history nears the context window |
|
|
177
159
|
| Root model output cap (tok) | `16384` | max output tokens per root-model turn |
|
|
178
160
|
| Sandbox init timeout | `30000` ms | how long to wait for the Python worker to start |
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
| Library loader | on | expose `load_library()` for external dirs/files/git repos |
|
|
161
|
+
| Context loader | on | expose `add_context()` for external dirs/files/documents/git repos |
|
|
162
|
+
| Auto-seed cwd | on | seed the working directory into `context` on the first `repl()` |
|
|
182
163
|
|
|
183
164
|
> **Concurrency note:** each `rlm_query` child spawns its own `python3` worker (~50–150 ms
|
|
184
|
-
> cold start).
|
|
185
|
-
>
|
|
186
|
-
> caps (above) bound
|
|
165
|
+
> cold start). Children are bounded separately (`maxConcurrentChildren`, default 6) because
|
|
166
|
+
> each holds a full Python process and its own copy of the inherited context. Error and
|
|
167
|
+
> wall-clock caps (above) still bound a runaway tree.
|
|
187
168
|
|
|
188
169
|
## Security
|
|
189
170
|
|
package/README.ru.md
CHANGED
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
- **Модель-оркестратор** управляет постоянным Python REPL пошагово.
|
|
35
35
|
- Работа с длинным контекстом **делегируется** дешевым worker-моделям через `llm_query` / `llm_query_batched`.
|
|
36
36
|
- Сложные подзадачи **рекурсивно** передаются в дочерние RLM через `rlm_query` (с ограничением глубины).
|
|
37
|
+
Дочерний RLM наследует `context` родителя — репозиторий и все библиотеки, загруженные через
|
|
38
|
+
`add_context()`, — и работает с теми же путями. Наследование не стоит дополнительных токенов:
|
|
39
|
+
содержимое живёт в песочнице, модель видит только строку с размером.
|
|
37
40
|
- Все работает **in-process** — единственным внешним процессом является локальный worker `python3`.
|
|
38
41
|
|
|
39
42
|
> This is a Pi-plugin reimplementation of the RLM method (see the [RLM paper](https://arxiv.org/abs/2512.24601)).
|
|
@@ -54,7 +57,7 @@ pi process (TypeScript)
|
|
|
54
57
|
|
|
55
58
|
- **Никаких серверов, сокетов или Docker.** Единственным внешним процессом является локальная песочница `python3`. Когда код в песочнице вызывает `llm_query`, worker пишет запрос в stdout и блокируется на stdin; Pi обрабатывает его внутри своего процесса и записывает ответ обратно. **API-ключи провайдеров никогда не попадают в песочницу.**
|
|
56
59
|
- Песочница предоставляет `context`, `llm_query`, `llm_query_batched`, `rlm_query`,
|
|
57
|
-
`rlm_query_batched`, `SHOW_VARS()`, `
|
|
60
|
+
`rlm_query_batched`, `SHOW_VARS()`, `ask_user_question()` и словарь `answer`.
|
|
58
61
|
Модель отправляет окончательный результат, устанавливая `answer["ready"] = True`.
|
|
59
62
|
|
|
60
63
|
## Установка
|
|
@@ -91,9 +94,6 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
91
94
|
| `/rlm` | `Ctrl+Shift+R` | Переключить постоянный режим RLM (направлять обычные промпты через движок RLM) |
|
|
92
95
|
| `/rlm-stop` | | Прервать текущий запуск |
|
|
93
96
|
| `/rlm-config` | | Выбрать smart- и worker-модели и настроить параметры запуска |
|
|
94
|
-
| `/rlm-resume` | | Возобновить прерванный запуск (по умолчанию `@latest`) |
|
|
95
|
-
| `/rlm-runs` | | Список последних запусков |
|
|
96
|
-
| `/rlm-help` | | Показать руководство по запуску и шпаргалку |
|
|
97
97
|
|
|
98
98
|
Пока запуск активен, **живое дерево** отображает корневой оркестратор и каждый sub-LLM / рекурсивный дочерний элемент со статусом, моделью, стоимостью, токенами и длительностью. Окончательный ответ публикуется в чате в формате markdown; любые правки кода собираются в виде диффов и проверяются через всплывающее окно (если не включен `yolo`).
|
|
99
99
|
|
|
@@ -107,9 +107,8 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
107
107
|
| `llm_query` | `(prompt, model=None) -> str` | Одноразовый вызов sub-LLM (worker-модель) |
|
|
108
108
|
| `llm_query_batched` | `(prompts, model=None) -> list[str]` | Параллельные вызовы sub-LLM (с ограничением пула) |
|
|
109
109
|
| `llm_query_chunked` | `(text, prompt, model=None) -> list[str]` | Дробит большой текст на части по лимиту и обрабатывает через sub-LLM |
|
|
110
|
-
| `rlm_query` | `(prompt, model=None) -> str` | Рекурсивный дочерний RLM со своей песочницей (с ограничением глубины) |
|
|
111
|
-
| `rlm_query_batched` | `(prompts, model=None) -> list[str]` | Параллельные рекурсивные дочерние RLM |
|
|
112
|
-
| `todo` | `(action, **kwargs) -> str` | Список задач: `create`/`update`/`list`/`get`/`delete`/`clear` |
|
|
110
|
+
| `rlm_query` | `(prompt, model=None, paths=None) -> str` | Рекурсивный дочерний RLM со своей песочницей (с ограничением глубины). Наследует ваш `context`; `paths` сужает его по префиксу |
|
|
111
|
+
| `rlm_query_batched` | `(prompts, model=None, paths=None) -> list[str]` | Параллельные рекурсивные дочерние RLM с общим срезом `paths` |
|
|
113
112
|
| `ask_user_question` | `(questions) -> list[dict]` | Задать пользователю структурированные вопросы (только на глубине 0) |
|
|
114
113
|
| `SHOW_VARS` | `() -> str` | Список текущих переменных и их типов |
|
|
115
114
|
| `answer` | `dict` | Установите `answer["content"]=...; answer["ready"]=True` для завершения |
|
|
@@ -130,13 +129,11 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
130
129
|
| Trajectory compaction | вкл (0.85) | суммаризация истории при приближении к лимиту окна контекста |
|
|
131
130
|
| `yolo` | выкл | применять предлагаемые правки немедленно, пропуская окно подтверждения |
|
|
132
131
|
| `askUserQuestion` | вкл | предоставить доступ к `ask_user_question()` для модели |
|
|
133
|
-
| `todo` | вкл | предоставить доступ к `todo()` для модели |
|
|
134
132
|
|
|
135
133
|
> **Примечание по параллелизму:** каждый дочерний `rlm_query` запускает собственного worker `python3` (~50–150 мс «холодного старта»). В худшем случае количество параллельных интерпретаторов ≈ `maxConcurrentSubcalls`^(depth−1); при настройках по умолчанию (глубина 4, параллелизм 4) это 4³ = 64 в патологическом случае. Лимиты бюджета и ошибок (см. выше) ограничивают общие затраты независимо от степени разветвления.
|
|
136
134
|
|
|
137
135
|
## Логи запусков
|
|
138
136
|
|
|
139
|
-
- **Логи запусков** (`runLog`): включены по умолчанию. Каждый запуск записывает след в формате JSONL в `.rlm/runs/` (по умолчанию) с ограничением `maxRuns` (50). Поддерживает **снимки** (`sandbox.pkl`) и **возобновление** прерванных запусков через `/rlm-resume`. Снимки защищены сессионным `nonce` для предотвращения повторов между сессиями.
|
|
140
137
|
|
|
141
138
|
## Безопасность
|
|
142
139
|
|
|
@@ -150,21 +147,19 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
150
147
|
|
|
151
148
|
```
|
|
152
149
|
src/
|
|
153
|
-
sandbox/ worker.py
|
|
154
|
-
bridge/ model.ts (
|
|
155
|
-
core/ engine.ts (
|
|
156
|
-
prompts/
|
|
157
|
-
text/
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
ui/ виджет-дерева · статус · выбор-модели · панель-конфигурации · вступление · тема
|
|
150
|
+
sandbox/ py/ (worker.py · guards · retrieval · tasks) · sandbox.ts · interrupts · protocol · sandbox-manager · context-file
|
|
151
|
+
bridge/ model.ts (single completion) · subcall-handlers.ts (the one llm/rlm impl) · ask-user · library
|
|
152
|
+
core/ engine.ts (the loop) · iteration · limits · resource-limits · answer · compaction · history · types
|
|
153
|
+
prompts/ glossary (shared REPL vocabulary) · system (headless) · native · user
|
|
154
|
+
text/ parsing (repl blocks) · tokens · preview
|
|
155
|
+
tool/ repl-tool · repl-result · repl-render · rlm-tool · rlm-events · rlm-aggregator · subcall-store · background-tasks
|
|
156
|
+
config/ defaults · settings (rlm.json persistence + validation)
|
|
157
|
+
context/ native walker + anydoc document conversion + add_context
|
|
158
|
+
ui/ status · model-picker · config-panel · intro · theme
|
|
163
159
|
commands/ rlm · rlm-config
|
|
164
|
-
mode/ rlm-mode (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
test/ фазы 1–9 · native-smoke · native-mode · помощники
|
|
160
|
+
mode/ rlm-mode (controller) · worker-model (cheapest pick) · native-guards
|
|
161
|
+
util/ errors · concurrency · trace
|
|
162
|
+
test/ phase suites · native-smoke · native-mode · helpers
|
|
168
163
|
```
|
|
169
164
|
|
|
170
165
|
## Тесты
|
package/README.zh-CN.md
CHANGED
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
|
|
34
34
|
- **根编排器**模型逐轮驱动一个**持久化的 Python REPL**。
|
|
35
35
|
- 长上下文工作通过 `llm_query` / `llm_query_batched` **委派**给廉价的工作模型。
|
|
36
|
-
- 困难的子问题通过 `rlm_query` **递归**到子 RLM
|
|
36
|
+
- 困难的子问题通过 `rlm_query` **递归**到子 RLM 中(设有深度限制)。子 RLM 继承父级的 `context`
|
|
37
|
+
——已加载的文件以及通过 `add_context()` 追加的来源——因此可以在相同的路径上使用相同的检索原语。
|
|
38
|
+
继承不消耗额外的 token:内容存放在沙箱中,模型只看到一行大小信息。
|
|
37
39
|
- 所有内容均**在进程内**运行 —— 唯一的外部进程是一个本地的 `python3` worker。
|
|
38
40
|
|
|
39
41
|
> 这是 RLM 方法的 Pi 插件重新实现(参见 [RLM 论文](https://arxiv.org/abs/2512.24601))。
|
|
@@ -56,7 +58,7 @@ pi 进程 (TypeScript)
|
|
|
56
58
|
当沙箱代码调用 `llm_query` 时,worker 在 stdout 上写入请求并在 stdin 上阻塞;
|
|
57
59
|
Pi 在进程内提供服务并将回复写回。**供应商 API 密钥绝不会进入沙箱。**
|
|
58
60
|
- 沙箱公开了 `context`, `llm_query`, `llm_query_batched`, `rlm_query`,
|
|
59
|
-
`rlm_query_batched`, `SHOW_VARS()`, `
|
|
61
|
+
`rlm_query_batched`, `SHOW_VARS()`, `ask_user_question()` 以及一个 `answer` 字典。
|
|
60
62
|
模型通过设置 `answer["ready"] = True` 来提交最终结果。
|
|
61
63
|
|
|
62
64
|
## 安装
|
|
@@ -96,9 +98,6 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
96
98
|
| `/rlm` | `Ctrl+Shift+R` | 切换持久化 RLM 模式 (通过 RLM 引擎路由普通提示词) |
|
|
97
99
|
| `/rlm-stop` | | 终止正在运行的任务 |
|
|
98
100
|
| `/rlm-config` | | 选择 smart + worker 模型并调整运行设置 |
|
|
99
|
-
| `/rlm-resume` | | 恢复被中断的任务 (默认 `@latest`) |
|
|
100
|
-
| `/rlm-runs` | | 列出最近的任务 |
|
|
101
|
-
| `/rlm-help` | | 显示启动指南和速查表 |
|
|
102
101
|
|
|
103
102
|
在任务激活期间,一个**实时树**会显示根编排器和每个子 LLM /
|
|
104
103
|
递归子节点的状态、模型、成本、token 和持续时间。最终答案将以 markdown 形式发布
|
|
@@ -114,9 +113,8 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
114
113
|
| `llm_query` | `(prompt, model=None) -> str` | 单次子 LLM 调用 (worker 模型) |
|
|
115
114
|
| `llm_query_batched` | `(prompts, model=None) -> list[str]` | 并发子 LLM 调用 (池上限) |
|
|
116
115
|
| `llm_query_chunked` | `(text, prompt, model=None) -> list[str]` | 将大文本拆分为不超过上限的块并通过子 LLM 处理 |
|
|
117
|
-
| `rlm_query` | `(prompt, model=None) -> str` | 具有自有沙箱的递归子 RLM (设有深度限制) |
|
|
118
|
-
| `rlm_query_batched` | `(prompts, model=None) -> list[str]` | 并发递归子 RLM |
|
|
119
|
-
| `todo` | `(action, **kwargs) -> str` | 任务列表:`create`/`update`/`list`/`get`/`delete`/`clear` |
|
|
116
|
+
| `rlm_query` | `(prompt, model=None, paths=None) -> str` | 具有自有沙箱的递归子 RLM (设有深度限制)。继承父级的 `context`;`paths` 按前缀缩小范围 |
|
|
117
|
+
| `rlm_query_batched` | `(prompts, model=None, paths=None) -> list[str]` | 并发递归子 RLM,共享同一个 `paths` 切片 |
|
|
120
118
|
| `ask_user_question` | `(questions) -> list[dict]` | 向用户提出结构化问题 (仅限深度 0) |
|
|
121
119
|
| `SHOW_VARS` | `() -> str` | 列出当前定义的变量及其类型 |
|
|
122
120
|
| `answer` | `dict` | 设置 `answer["content"]=...; answer["ready"]=True` 以结束 |
|
|
@@ -137,7 +135,6 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
137
135
|
| Trajectory compaction | on (0.85) | 当历史记录接近上下文窗口时进行总结 |
|
|
138
136
|
| `yolo` | off | 立即应用建议的修改,跳过审核弹出窗 |
|
|
139
137
|
| `askUserQuestion` | on | 向模型公开 `ask_user_question()` |
|
|
140
|
-
| `todo` | on | 向模型公开 `todo()` |
|
|
141
138
|
|
|
142
139
|
> **并发注意:** 每个 `rlm_query` 子节点都会启动自己的 `python3` worker (冷启动约 50–150 毫秒)。
|
|
143
140
|
> 最坏情况下的并发解释器数量 ≈ `maxConcurrentSubcalls`^(depth−1);在
|
|
@@ -146,12 +143,6 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
146
143
|
|
|
147
144
|
## 运行日志
|
|
148
145
|
|
|
149
|
-
- **运行日志** (`runLog`):默认始终开启。每次运行将 JSONL 轨迹写入 `.rlm/runs/`
|
|
150
|
-
(默认),上限为 `maxRuns` (50)。支持通过 `/rlm-resume` 进行**快照** (`sandbox.pkl`) 和**恢复**
|
|
151
|
-
被中断的任务。快照受每个会话的 `nonce` 保护,以防止跨会话重放。
|
|
152
|
-
|
|
153
|
-
## 安全性
|
|
154
|
-
|
|
155
146
|
- **密钥隔离**:供应商密钥仅存在于 TypeScript (`AuthStorage`) 中;沙箱
|
|
156
147
|
接收提示词并返回文本 —— 绝不接触密钥。
|
|
157
148
|
- **环境清理**:在 worker 启动前会剥离敏感环境变量 (API 密钥, token)。
|
|
@@ -170,21 +161,19 @@ rm -rf ~/.pi/agent/extensions/rlm
|
|
|
170
161
|
|
|
171
162
|
```
|
|
172
163
|
src/
|
|
173
|
-
sandbox/ worker.py
|
|
174
|
-
bridge/ model.ts (
|
|
175
|
-
core/ engine.ts (the loop) · iteration · limits · answer · compaction ·
|
|
176
|
-
prompts/
|
|
177
|
-
text/ parsing (repl blocks) · tokens · preview
|
|
178
|
-
|
|
179
|
-
tool/ repl-tool · rlm-events · aggregator · propose-edits · emitter-listener
|
|
164
|
+
sandbox/ py/ (worker.py · guards · retrieval · tasks) · sandbox.ts · interrupts · protocol · sandbox-manager · context-file
|
|
165
|
+
bridge/ model.ts (single completion) · subcall-handlers.ts (the one llm/rlm impl) · ask-user · library
|
|
166
|
+
core/ engine.ts (the loop) · iteration · limits · resource-limits · answer · compaction · history · types
|
|
167
|
+
prompts/ glossary (shared REPL vocabulary) · system (headless) · native · user
|
|
168
|
+
text/ parsing (repl blocks) · tokens · preview
|
|
169
|
+
tool/ repl-tool · repl-result · repl-render · rlm-tool · rlm-events · rlm-aggregator · subcall-store · background-tasks
|
|
180
170
|
config/ defaults · settings (rlm.json persistence + validation)
|
|
181
|
-
context/
|
|
182
|
-
ui/
|
|
171
|
+
context/ native walker + anydoc document conversion + add_context
|
|
172
|
+
ui/ status · model-picker · config-panel · intro · theme
|
|
183
173
|
commands/ rlm · rlm-config
|
|
184
|
-
mode/ rlm-mode (controller) ·
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
test/ phase1–phase9 · native-smoke · native-mode · helpers
|
|
174
|
+
mode/ rlm-mode (controller) · worker-model (cheapest pick) · native-guards
|
|
175
|
+
util/ errors · concurrency · trace
|
|
176
|
+
test/ phase suites · native-smoke · native-mode · helpers
|
|
188
177
|
```
|
|
189
178
|
|
|
190
179
|
## 测试
|
package/package.json
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hicaru/pi-rlm",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "Save 99% tokens, Recursive Language Model (RLM) for the Pi",
|
|
6
|
-
"license": "MIT",
|
|
3
|
+
"version": "0.3.0",
|
|
7
4
|
"author": "hicaru",
|
|
8
5
|
"repository": {
|
|
9
6
|
"type": "git",
|
|
10
7
|
"url": "git+https://github.com/openzebra/rlm.pi.git"
|
|
11
8
|
},
|
|
12
|
-
"
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"typescript": "^5.0.0"
|
|
11
|
+
},
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"@earendil-works/pi-ai": "*",
|
|
14
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
15
|
+
"@earendil-works/pi-tui": "*",
|
|
16
|
+
"typebox": "*"
|
|
17
|
+
},
|
|
13
18
|
"bugs": {
|
|
14
19
|
"url": "https://github.com/openzebra/rlm.pi/issues"
|
|
15
20
|
},
|
|
21
|
+
"description": "Save 99% tokens, Recursive Language Model (RLM) for the Pi",
|
|
16
22
|
"files": [
|
|
17
23
|
"src/",
|
|
18
24
|
"README.md",
|
|
19
25
|
"LICENSE"
|
|
20
26
|
],
|
|
27
|
+
"homepage": "https://github.com/openzebra/rlm.pi",
|
|
21
28
|
"keywords": [
|
|
22
29
|
"pi-package",
|
|
23
30
|
"pi-extension",
|
|
@@ -25,11 +32,7 @@
|
|
|
25
32
|
"recursive",
|
|
26
33
|
"ai-agent"
|
|
27
34
|
],
|
|
28
|
-
"
|
|
29
|
-
"check": "tsc --noEmit",
|
|
30
|
-
"test": "bun run test/smoke.ts",
|
|
31
|
-
"prepublishOnly": "npm run check"
|
|
32
|
-
},
|
|
35
|
+
"license": "MIT",
|
|
33
36
|
"pi": {
|
|
34
37
|
"extensions": [
|
|
35
38
|
"./src/index.ts"
|
|
@@ -38,16 +41,16 @@
|
|
|
38
41
|
"publishConfig": {
|
|
39
42
|
"access": "public"
|
|
40
43
|
},
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"typebox": "*"
|
|
44
|
+
"scripts": {
|
|
45
|
+
"check": "tsc --noEmit",
|
|
46
|
+
"test": "bun run test/smoke.ts",
|
|
47
|
+
"prepublishOnly": "npm run check"
|
|
46
48
|
},
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
+
"type": "module",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
49
52
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@firecrawl/anydoc": "^0.1.7"
|
|
52
55
|
}
|
|
53
56
|
}
|