@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.
Files changed (79) hide show
  1. package/README.md +28 -47
  2. package/README.ru.md +18 -23
  3. package/README.zh-CN.md +17 -28
  4. package/package.json +22 -19
  5. package/src/bridge/add-context.ts +322 -0
  6. package/src/bridge/subcall-handlers.ts +63 -17
  7. package/src/commands/rlm-config.ts +47 -18
  8. package/src/commands/rlm.ts +3 -152
  9. package/src/config/defaults.ts +8 -18
  10. package/src/config/settings.ts +13 -34
  11. package/src/context/anydoc.ts +67 -0
  12. package/src/context/listing.ts +70 -0
  13. package/src/context/md-cache.ts +112 -0
  14. package/src/context/merge.ts +97 -0
  15. package/src/context/namespace.ts +180 -0
  16. package/src/context/resolve.ts +122 -0
  17. package/src/context/source-dir.ts +166 -0
  18. package/src/context/source-doc.ts +71 -0
  19. package/src/context/source-git.ts +51 -0
  20. package/src/context/source-text.ts +45 -0
  21. package/src/context/types.ts +88 -0
  22. package/src/context/walk.ts +250 -0
  23. package/src/core/engine.ts +61 -345
  24. package/src/core/history.ts +1 -1
  25. package/src/core/limits.ts +5 -12
  26. package/src/core/resource-limits.ts +0 -2
  27. package/src/core/types.ts +10 -38
  28. package/src/index.ts +92 -54
  29. package/src/mode/llm-model.ts +54 -0
  30. package/src/mode/rlm-mode.ts +28 -58
  31. package/src/prompts/glossary.ts +290 -0
  32. package/src/prompts/native.ts +127 -0
  33. package/src/prompts/system.ts +15 -408
  34. package/src/sandbox/context-file.ts +154 -0
  35. package/src/sandbox/interrupts.ts +160 -0
  36. package/src/sandbox/protocol.ts +20 -75
  37. package/src/sandbox/py/__pycache__/guards.cpython-314.pyc +0 -0
  38. package/src/sandbox/py/__pycache__/retrieval.cpython-314.pyc +0 -0
  39. package/src/sandbox/py/__pycache__/tasks.cpython-314.pyc +0 -0
  40. package/src/sandbox/py/guards.py +150 -0
  41. package/src/sandbox/py/retrieval.py +265 -0
  42. package/src/sandbox/py/tasks.py +129 -0
  43. package/src/sandbox/py/worker.py +856 -0
  44. package/src/sandbox/sandbox-manager.ts +24 -9
  45. package/src/sandbox/sandbox.ts +99 -193
  46. package/src/text/tokens.ts +31 -5
  47. package/src/tool/repl-details.ts +2 -2
  48. package/src/tool/repl-render.ts +58 -0
  49. package/src/tool/repl-result.ts +70 -0
  50. package/src/tool/repl-tool.ts +60 -170
  51. package/src/tool/rlm-aggregator.ts +2 -10
  52. package/src/tool/rlm-details.ts +0 -2
  53. package/src/tool/rlm-events.ts +0 -14
  54. package/src/tool/rlm-tool.ts +2 -13
  55. package/src/ui/config-panel.ts +12 -20
  56. package/src/ui/intro.ts +1 -2
  57. package/src/ui/model-picker.ts +34 -10
  58. package/src/ui/status.ts +3 -7
  59. package/src/util/concurrency.ts +9 -5
  60. package/src/bridge/fallback-todo.ts +0 -148
  61. package/src/bridge/interactive.ts +0 -65
  62. package/src/bridge/library.ts +0 -155
  63. package/src/bridge/pi-interactive.ts +0 -41
  64. package/src/context/library-context.ts +0 -266
  65. package/src/context/repomix-context.ts +0 -204
  66. package/src/core/artifacts.ts +0 -89
  67. package/src/core/critique.ts +0 -92
  68. package/src/core/gates.ts +0 -301
  69. package/src/core/pipeline-handlers.ts +0 -319
  70. package/src/core/pipeline.ts +0 -268
  71. package/src/prompts/phases.ts +0 -104
  72. package/src/sandbox/worker.py +0 -1456
  73. package/src/state/index.ts +0 -24
  74. package/src/state/internal.ts +0 -46
  75. package/src/state/paths.ts +0 -44
  76. package/src/state/reads.ts +0 -133
  77. package/src/state/resume.ts +0 -173
  78. package/src/state/rows.ts +0 -123
  79. 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]` | Repository packed as `[{"path","content","tokens"}, ...]` — the full codebase |
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
- | `todo` | `(action, **kwargs) -> str` | Task list: `create`/`update`/`list`/`get`/`delete`/`clear` |
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
- ### Loading external libraries
122
+ ### Adding context
127
123
 
128
- When the task needs an **external library, another source tree, or standalone docs** that are
129
- not in the packed repo `context`, the model calls `load_library(source)` mid-run:
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 = load_library("../some-lib") # local directory → packed + appended
133
- info = load_library("docs/api.md") # single file → one entry in context
134
- info = load_library("https://github.com/x/y.git") # shallow clone, then pack + append
135
- # Files land in the SAME `context` list under lib/<source_id>/…
136
- # info == {"source_id", "path_prefix", "files", "chars", "context_len", "already_loaded", …}
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
- libraries do not collide. Toggle via `/rlm-config` → **Library loader** (`libraryLoader`,
142
- default on). On headless runs with persistence, each load writes a resume sidecar
143
- (`context.<N>.json`) that is **merged back into `context`** on resume.
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 | `4` | concurrency pool size for `*_batched` |
168
- | Budget ceiling (USD) | none | total spend cap for the whole recursive tree |
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
- | `askUserQuestion` | on | expose `ask_user_question()` to the model |
180
- | `todo` | on | expose `todo()` to the model |
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). Worst-case concurrent interpreters `maxConcurrentSubcalls`^(depth−1); at
185
- > defaults (depth 4, conc 4) that's = 64 in the pathological case. Budget and error
186
- > caps (above) bound total spend regardless of fan-out.
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()`, `todo()`, `ask_user_question()` и словарь `answer`.
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 + JSONL stdio driver (PythonSandbox) · protocol.ts · sandbox-manager.ts
154
- bridge/ model.ts (одноразовое завершение) · llm-query.ts · rlm-query.ts (рекурсия)
155
- core/ engine.ts (цикл) · iteration · limits · answer · compaction · pipeline · types
156
- prompts/ системные промпты и промпты для каждого шага (перенесены из Python-референса)
157
- text/ парсинг (repl-блоки) · токены · превью · правки
158
- state/ чтения/записи · возобновление · пути · строки
159
- tool/ repl-tool · rlm-events · агрегатор · предложение-правок · emitter-listener
160
- config/ значения по умолчанию · настройки (сохранение и валидация rlm.json)
161
- context/ упаковка репозитория на базе repomix + кеширование
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
- patch/ применение · всплывающее-окно · индекс
166
- util/ ошибки · параллелизм
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()`, `todo()`, `ask_user_question()` 以及一个 `answer` 字典。
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 + JSONL stdio driver (PythonSandbox) · protocol.ts · sandbox-manager.ts
174
- bridge/ model.ts (one-shot completion) · llm-query.ts · rlm-query.ts (recursion)
175
- core/ engine.ts (the loop) · iteration · limits · answer · compaction · pipeline · types
176
- prompts/ system + per-turn prompts (ported from the Python reference)
177
- text/ parsing (repl blocks) · tokens · preview · edits
178
- state/ reads/writes · resume · paths · rows
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/ repomix-based repository packing + caching
182
- ui/ tree-widget · status · model-picker · config-panel · intro · theme
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) · input-router
185
- patch/ apply · popup · index
186
- util/ errors · concurrency
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.2.1",
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
- "homepage": "https://github.com/openzebra/rlm.pi",
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
- "scripts": {
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
- "peerDependencies": {
42
- "@earendil-works/pi-ai": "*",
43
- "@earendil-works/pi-coding-agent": "*",
44
- "@earendil-works/pi-tui": "*",
45
- "typebox": "*"
44
+ "scripts": {
45
+ "check": "tsc --noEmit",
46
+ "test": "bun run test/smoke.ts",
47
+ "prepublishOnly": "npm run check"
46
48
  },
47
- "dependencies": {
48
- "repomix": "^1.15.0"
49
+ "type": "module",
50
+ "engines": {
51
+ "node": ">=20"
49
52
  },
50
- "devDependencies": {
51
- "typescript": "^5.0.0"
53
+ "dependencies": {
54
+ "@firecrawl/anydoc": "^0.1.7"
52
55
  }
53
56
  }