pi-blackhole 0.2.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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +373 -0
  3. package/example-config.json +115 -0
  4. package/index.ts +39 -0
  5. package/package.json +55 -0
  6. package/src/commands/memory.ts +191 -0
  7. package/src/commands/pi-vcc.ts +94 -0
  8. package/src/commands/vcc-recall.ts +112 -0
  9. package/src/core/brief.ts +390 -0
  10. package/src/core/build-sections.ts +85 -0
  11. package/src/core/content.ts +60 -0
  12. package/src/core/filter-noise.ts +42 -0
  13. package/src/core/format-recall.ts +27 -0
  14. package/src/core/format.ts +76 -0
  15. package/src/core/lineage.ts +26 -0
  16. package/src/core/load-messages.ts +41 -0
  17. package/src/core/normalize.ts +79 -0
  18. package/src/core/recall-scope.ts +14 -0
  19. package/src/core/render-entries.ts +56 -0
  20. package/src/core/report.ts +237 -0
  21. package/src/core/sanitize.ts +5 -0
  22. package/src/core/search-entries.ts +227 -0
  23. package/src/core/settings.ts +34 -0
  24. package/src/core/skill-collapse.ts +35 -0
  25. package/src/core/summarize.ts +213 -0
  26. package/src/core/tool-args.ts +14 -0
  27. package/src/core/unified-config.ts +285 -0
  28. package/src/details.ts +13 -0
  29. package/src/extract/commits.ts +69 -0
  30. package/src/extract/files.ts +80 -0
  31. package/src/extract/goals.ts +79 -0
  32. package/src/extract/preferences.ts +55 -0
  33. package/src/hooks/before-compact.ts +345 -0
  34. package/src/om/agents/dropper/agent.ts +204 -0
  35. package/src/om/agents/dropper/prompts.ts +48 -0
  36. package/src/om/agents/observer/agent.ts +256 -0
  37. package/src/om/agents/observer/prompts.ts +119 -0
  38. package/src/om/agents/reflector/agent.ts +161 -0
  39. package/src/om/agents/reflector/prompts.ts +77 -0
  40. package/src/om/clipboard.ts +63 -0
  41. package/src/om/compaction-hook.ts +63 -0
  42. package/src/om/compaction-trigger.ts +92 -0
  43. package/src/om/config.ts +22 -0
  44. package/src/om/consolidation.ts +514 -0
  45. package/src/om/cooldown.ts +130 -0
  46. package/src/om/debug-log.ts +55 -0
  47. package/src/om/ids.ts +5 -0
  48. package/src/om/ledger/fold.ts +106 -0
  49. package/src/om/ledger/index.ts +6 -0
  50. package/src/om/ledger/progress.ts +225 -0
  51. package/src/om/ledger/projection.ts +237 -0
  52. package/src/om/ledger/recall.ts +243 -0
  53. package/src/om/ledger/render-summary.ts +44 -0
  54. package/src/om/ledger/types.ts +206 -0
  55. package/src/om/model-budget.ts +9 -0
  56. package/src/om/pending.ts +225 -0
  57. package/src/om/reverse-recall.ts +130 -0
  58. package/src/om/runtime.ts +241 -0
  59. package/src/om/serialize.ts +224 -0
  60. package/src/om/tokens.ts +33 -0
  61. package/src/sections.ts +18 -0
  62. package/src/tools/recall.ts +212 -0
  63. package/src/types.ts +19 -0
  64. package/vitest.config.ts +41 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 k0valik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # pi-blackhole
2
+
3
+ Algorithmic compaction + session-aware observational memory for [Pi](https://github.com/badlogic/pi-mono), in one extension.
4
+
5
+ Combines [pi-vcc](https://github.com/sting8k/pi-vcc) and [pi-observational-memory](https://github.com/elpapi42/pi-observational-memory) with unified configuration, per-worker model fallback chains, persisted cooldowns, and a manual flush mode.
6
+
7
+ > This is a frankenmerge. I liked both extensions but they were not compatible - observational memory hooked into Pi's default compaction and prevented pi-vcc from working. So I merged them, made them share the same hook and output, and added the things both were missing: fallback chains, cooldowns, and a toggle between them.
8
+
9
+ #### For easy setup pass the [`llms.txt`](llms.txt) llms.txt to your agent and it will guide you through the config without needing to read all the docs if you're as lazy as me
10
+
11
+ # Demo
12
+
13
+ - /blackhole collapses a 94k context-size conversation into a ~7.8k (for my settings) next input, shows the current stats for /blackhole-memory and /blackhole-recall (can be called by agent as well) augmenting the relevant neighbour observations and exact conversations so the agent can expand when it needs to remember previous conversation
14
+
15
+ https://github.com/user-attachments/assets/ab7c5787-1bbd-466f-a231-0818e68e9f39
16
+
17
+ ---
18
+
19
+ ## The problem
20
+
21
+ Long AI engineering sessions inevitably degrade. Pi's native compaction relies on an LLM to generate free-form prose summaries recursively. Pi compacts the conversation — then compacts that summary — then compacts again. After enough cycles, small but load-bearing details disappear: why a decision was made, what approaches were already rejected, what the user clarified earlier in the session.
22
+
23
+ The session is still alive. The agent is no longer carrying the real context.
24
+
25
+ The two upstream projects solve different halves of this:
26
+
27
+ - **pi-vcc** replaces Pi's LLM-based compaction with a deterministic, zero-cost algorithmic summary. Fast, reproducible, no hallucination risk. But the compacted output is still a summary — repeated compactions still erode detail.
28
+ - **pi-observational-memory** captures observations and reflections in a session ledger that survives compactions. But its compaction path still calls an LLM.
29
+
30
+ **pi-blackhole** puts vcc in the compaction slot and OM in the memory layer, where each does what it's designed for.
31
+
32
+ ---
33
+
34
+ ## Feature Comparison
35
+
36
+ | | pi-blackhole | pi-vcc | pi-obs-memory | Pi default |
37
+ |---|---|---|---|---|
38
+ | Algorithmic compaction (no LLM) | ✓ | ✓ | — | — |
39
+ | Deterministic output | ✓ | ✓ | — | — |
40
+ | Structured summary sections | ✓ | ✓ | — | — |
41
+ | Observations + reflections | ✓ | — | ✓ | — |
42
+ | Context survives across compactions | ✓ | — | ✓ | — |
43
+ | Background workers | ✓ | — | ✓ | — |
44
+ | Searchable history after compaction | ✓ | ✓ | partial | — |
45
+ | Per-worker model config | ✓ | — | — | — |
46
+ | Fallback model chains + persisted cooldowns | ✓ | — | — | — |
47
+ | Manual flush mode (`noAutoCompact`) | ✓ | — | — | — |
48
+ | Memory toggle (`/blackhole om-off`) | ✓ | — | — | — |
49
+ | Unified single-file config | ✓ | — | — | — |
50
+
51
+ ---
52
+
53
+ ## How it works
54
+
55
+ On `/blackhole`, the vcc pipeline analyzes the transcript tail and produces a structured summary: session goal, file changes, commits, outstanding blockers, user preferences, and a rolling brief transcript. Accumulated observations and reflections from the session ledger are rendered and appended below it. The agent receives a deterministic recap of recent work and durable facts from the full session history in a single replacement block.
56
+
57
+ Three background workers from `pi-observational-memory` run during the session:
58
+
59
+ - **Observer** — reads conversation since the last observation marker and extracts timestamped facts: events, decisions, preferences. Input is capped to `observerChunkMaxTokens` newest-first to prevent context blowup on long sessions.
60
+ - **Reflector** — distills new observations into durable reflections: stable facts, patterns, and constraints that survive future compactions.
61
+ - **Dropper** — prunes low-value observations from active memory when the pool exceeds `observationsPoolMaxTokens`, while keeping reflections and other long-term elements safely in the session ledger.
62
+
63
+ ```
64
+ [Conversation turn] ──> observeAfterTokens threshold
65
+
66
+ v
67
+ 1. OBSERVER
68
+ (extracts observations)
69
+
70
+ v
71
+ 2. REFLECTOR
72
+ (distills reflections)
73
+
74
+ v
75
+ 3. DROPPER
76
+ (prunes observations, keeps reflections)
77
+ ```
78
+
79
+ The pipeline runs in order: observer -> reflector -> dropper. If any stage fails, remaining stages are skipped and the pipeline retries on the next `agent_start` or `turn_end`. A minimum 30-second interval is enforced between failed runs.
80
+
81
+ ### What the agent sees after compaction
82
+
83
+ ```
84
+ [Session Goal]
85
+ - Fix the authentication bug in login flow
86
+ - [Scope change]
87
+ - Also update the session token refresh logic
88
+
89
+ [Files And Changes]
90
+ - Modified: src/auth/session.ts
91
+ - Created: tests/auth-refresh.test.ts
92
+
93
+ [Commits]
94
+ - a1b2c3d: fix(auth): refresh token after password reset
95
+
96
+ [Outstanding Context]
97
+ - lint check still failing on line 42
98
+
99
+ [User Preferences]
100
+ - Prefer Vietnamese responses
101
+ - Always run tests before committing
102
+
103
+ [user]
104
+ Fix the auth bug...
105
+
106
+ [assistant]
107
+ Root cause is a missing token refresh...
108
+ ...transcript continues...
109
+
110
+ ---
111
+
112
+ [a1b2c3d4e5f6] 2026-05-23 [high] User decided to switch from REST to GraphQL; motivation was reducing over-fetching.
113
+ [b2c3d4e5f6a1] 2026-05-23 [medium] GraphQL migration completed; user confirmed working.
114
+ [c3d4e5f6a1b2] Reflection: User is building Acme Dashboard on Next.js 15 with Supabase auth.
115
+ ```
116
+
117
+ Sections appear only when relevant — a session with no git commits won't have `[Commits]`.
118
+
119
+ ---
120
+
121
+ ## Compaction modes
122
+
123
+ Two modes, one shared goal: keep your agent's context sharp without manual housekeeping.
124
+
125
+ - **Auto mode (default):** install and forget. Workers run, observations are appended as invisible conversation markers, compaction fires automatically when tokens exceed threshold.
126
+ - **Manual mode (`noAutoCompact: true` — the maintainer's setup):** same workers, same pipeline. But observations go to a disk buffer and compaction only happens when you run `/blackhole`. Cleaner conversation, manual schedule.
127
+
128
+ The tradeoff is simplicity vs cleanliness:
129
+
130
+ | | Auto (default) | Manual (`noAutoCompact: true`) |
131
+ |---|---|---|
132
+ | Workers run? | Yes | Yes |
133
+ | Observations go to | Conversation markers (invisible in TUI) | Disk (`pending.json`) |
134
+ | Auto-compact on `agent_end` | Yes | No |
135
+ | `/blackhole` | Optional — use it whenever you want | Required to flush + compact |
136
+ | Conversation history | OM marker entries between turns (they exist but do not clutter the display) | Clean — nothing between turns |
137
+ | Use case | "I don't want to think about it" | "I want to control when context gets compressed" |
138
+
139
+ **Does `/blackhole` work like a single `/compact` that Just Works?**
140
+
141
+ Yes, that's exactly the idea, especially in manual mode. When you feel context is getting full or accuracy is slipping, type `/blackhole`. It flushes any accumulated observations from disk, runs algorithmic vcc compaction (zero LLM cost), and injects your durable reflections into the replacement block. One command, everything gets compressed while keeping your long-term memory alive.
142
+
143
+ The difference from Pi's built-in `/compact`:
144
+ - `/compact` calls an LLM to write a free-form summary — costly, lossy, no memory layer.
145
+ - `/blackhole` uses algorithmic section extraction (goals, files, commits, preferences...) plus injects observations/reflections from the session ledger. No LLM involved in the compaction itself. Fast, deterministic, memory-preserving.
146
+
147
+ ### Without observational memory
148
+
149
+ Set `memory: false` or run `/blackhole om-off` for pure pi-vcc compaction — no background workers, no memory injection. Re-enable with `/blackhole om-on` or `memory: true`.
150
+
151
+ ---
152
+
153
+ ## Commands
154
+
155
+ | Command | What it does |
156
+ |---|---|
157
+ | `/blackhole` | Compact. `om-off` / `om-on` toggle observational memory. |
158
+ | `/blackhole-memory` | Pipeline status: token progress, worker counts, last errors |
159
+ | `/blackhole-memory view` | Visible observations and reflections, copied to clipboard |
160
+ | `/blackhole-memory full` | Complete recorded memory, copied to clipboard |
161
+ | `/blackhole-recall <query>` | Search session history. Supports `page:N`, `scope:all` |
162
+
163
+ ## Tools
164
+
165
+ | Tool | Input | Returns |
166
+ |---|---|---|
167
+ | `recall` | `[12char hex]` — source evidence for an observation/reflection; `#N` — transcript entry by index; free text — BM25+regex ranked search | Source message(s) with timestamps |
168
+
169
+ ---
170
+
171
+ ## Configuration
172
+
173
+ All settings in **`~/.pi/agent/pi-blackhole-config.json`** — auto-created with defaults on first startup. See [`CONFIG.md`](CONFIG.md) for the full reference and tuning guidance.
174
+
175
+ Quick start with custom models:
176
+
177
+ ```json
178
+ {
179
+ "observerModel": { "provider": "openrouter", "id": "qwen/qwen3-next-80b-a3b-instruct:free" },
180
+ "reflectorModel": { "provider": "cerebras", "id": "gpt-oss-120b" },
181
+ "dropperModel": { "provider": "cerebras", "id": "gpt-oss-120b" }
182
+ }
183
+ ```
184
+
185
+ ### Settings at a glance
186
+
187
+ | Setting | Default (medium) | What it controls |
188
+ |---|---|---|
189
+ | `overrideDefaultCompaction` | `false` | Route all Pi compactions through blackhole, not just explicit `/blackhole` |
190
+ | `noAutoCompact` | `false` | Manual mode: save to disk, disable auto-compaction |
191
+ | `memory` | `true` | `false` = pi-vcc only, no workers, no OM injection |
192
+ | `passive` | `false` | Disable all workers and auto-compaction entirely |
193
+ | `model` | — | Base fallback model for all workers |
194
+ | `observerModel` / `observerFallbackModels` | — / `[]` | Primary + fallbacks for observer |
195
+ | `reflectorModel` / `reflectorFallbackModels` | — / `[]` | Primary + fallbacks for reflector |
196
+ | `dropperModel` / `dropperFallbackModels` | — / `[]` | Primary + fallbacks for dropper |
197
+ | `observeAfterTokens` | `10000` | Token cadence between observer runs |
198
+ | `reflectAfterTokens` | `20000` | Token cadence for reflector and dropper |
199
+ | `compactAfterTokens` | `81000` | Auto-compaction threshold |
200
+ | `observerChunkMaxTokens` | `40000` | Max observer input per run (newest-first) |
201
+ | `observationsPoolMaxTokens` | `20000` | Max active observation pool before dropper prunes |
202
+ | `reflectorInputMaxTokens` | `80000` | Max reflector input budget |
203
+ | `dropperInputMaxTokens` | `80000` | Max dropper input budget |
204
+ | `agentMaxTurns` | `16` | Max turns per worker agent loop |
205
+ | `debug` | `false` | Pre-compaction snapshot to `/tmp/pi-blackhole-debug.json` |
206
+ | `debugLog` | `false` | Continuous JSONL log to `~/.pi/agent/pi-blackhole/debug.ndjson` |
207
+
208
+ Env override: `PI_BLACKHOLE_PASSIVE=true` disables all workers without touching the config file.
209
+
210
+ ### Configuration presets
211
+
212
+ The defaults above target a **medium-context** setup (~128k context window, e.g. GPT-4o, Claude Sonnet).
213
+ Paste the appropriate block into your config to match your model's context size.
214
+
215
+ #### Low context (~32k-64k — older models, fast budget models)
216
+
217
+ ```json
218
+ {
219
+ "observeAfterTokens": 5000,
220
+ "reflectAfterTokens": 10000,
221
+ "compactAfterTokens": 30000,
222
+ "observerChunkMaxTokens": 15000,
223
+ "observationsPoolMaxTokens": 8000,
224
+ "reflectorInputMaxTokens": 30000,
225
+ "dropperInputMaxTokens": 30000
226
+ }
227
+ ```
228
+
229
+ #### Medium context (~128k — GPT-4o, Claude Sonnet, Gemini Pro; this is the default)
230
+
231
+ Our built-in defaults already target this tier. If you reset your config, these are what you get:
232
+
233
+ ```json
234
+ {
235
+ "observeAfterTokens": 10000,
236
+ "reflectAfterTokens": 20000,
237
+ "compactAfterTokens": 81000,
238
+ "observerChunkMaxTokens": 40000,
239
+ "observationsPoolMaxTokens": 20000,
240
+ "reflectorInputMaxTokens": 80000,
241
+ "dropperInputMaxTokens": 80000
242
+ }
243
+ ```
244
+
245
+ #### High context (~200k+ — Claude Opus, Gemini Ultra, large local models)
246
+
247
+ ```json
248
+ {
249
+ "observeAfterTokens": 20000,
250
+ "reflectAfterTokens": 40000,
251
+ "compactAfterTokens": 180000,
252
+ "observerChunkMaxTokens": 80000,
253
+ "observationsPoolMaxTokens": 40000,
254
+ "reflectorInputMaxTokens": 160000,
255
+ "dropperInputMaxTokens": 160000
256
+ }
257
+ ```
258
+
259
+ **What to tune first:** `compactAfterTokens` should be significantly below your model's total context window — aim for ~60-70%. If you find the agent loses context before compaction fires, lower it. If compaction fires too often and breaks flow, raise it. The other thresholds scale proportionally with this value.
260
+
261
+ ---
262
+
263
+ ## Model fallback chains
264
+
265
+ Each worker has a primary model and an ordered fallback list. On any error — rate limit, timeout, API failure — the failed model is cooled down and the next candidate is tried. If all candidates are exhausted, the pipeline aborts and retries on the next trigger event. The session model is always the last resort and is never cooled down.
266
+
267
+ ```
268
+ [Worker fails: 429 / timeout / 5xx]
269
+
270
+ v
271
+ Add model to cooldown list
272
+
273
+ v
274
+ Try next fallback candidate
275
+
276
+ v
277
+ [All candidates exhausted?]
278
+ │ │
279
+ yes no ──> try next
280
+
281
+ v
282
+ Fall back to session model (never cooled down)
283
+ ```
284
+
285
+ Cooldowns are persisted to `~/.pi/agent/pi-blackhole/pi-blackhole-cooldown.json` and survive Pi restarts. Each entry records the model key, the triggering error, the responsible stage, and the expiry timestamp.
286
+
287
+ With a full config, resolution order looks like:
288
+
289
+ ```
290
+ Observer: qwen3-next-80b → gemma4:31b-cloud → gemma-4-31b-it:free → base model → session model
291
+ Reflector: gpt-oss-120b (cerebras) → glm-4.7 (z.ai) → gpt-oss-120b:free → base model → session model
292
+ Dropper: gpt-oss-120b (cerebras) → glm-4.7 (z.ai) → gpt-oss-120b:free → base model → session model
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Recall
298
+
299
+ Pi's default compaction discards old messages permanently — after compaction, the agent only sees the summary. Blackhole preserves searchable history through two surfaces.
300
+
301
+ ### `recall` tool (agent-facing)
302
+
303
+ Searches the raw session JSONL directly, bypassing compaction. Default scope is the active conversation lineage.
304
+
305
+ | Input | What it does |
306
+ |---|---|
307
+ | `[12char hex]` | Recover source evidence for an observation or reflection |
308
+ | `#N` | Expand a transcript entry by index |
309
+ | Free text | BM25-ranked OR search, rare terms weighted higher |
310
+ | Regex | Pattern search (e.g. `fork.*pi-vcc`, `hook\|inject`) |
311
+
312
+ ### `/blackhole-recall` command (user-facing)
313
+
314
+ Results are shown as a collapsible message and auto-fed to the agent as context.
315
+
316
+ ```
317
+ /blackhole-recall auth token # active-lineage search, ranked
318
+ /blackhole-recall auth token page:2 # paginated (5 results/page)
319
+ /blackhole-recall hook|inject # regex
320
+ /blackhole-recall fail.*build scope:all # regex across all lineages
321
+ /blackhole-recall # recent 25 entries
322
+ ```
323
+
324
+ ---
325
+
326
+ ## Install
327
+
328
+ ```bash
329
+ # From npm (recommended)
330
+ pi install npm:pi-blackhole
331
+
332
+ # Or directly from GitHub
333
+ pi install git:github.com/k0valik/pi-blackhole
334
+ ```
335
+
336
+ If you have standalone pi-vcc or pi-observational-memory installed, remove them first — they will conflict:
337
+
338
+ ```bash
339
+ pi uninstall https://github.com/sting8k/pi-vcc
340
+ pi uninstall https://github.com/elpapi42/pi-observational-memory
341
+ ```
342
+
343
+ Then `/reload` or restart Pi.
344
+
345
+ ### Standalone install (without Pi)
346
+
347
+ ```bash
348
+ npm install pi-blackhole
349
+ # or
350
+ pnpm add pi-blackhole
351
+ ```
352
+
353
+ ## Uninstall
354
+
355
+ ```bash
356
+ pi uninstall git:github.com/k0valik/pi-blackhole
357
+ rm -rf ~/.pi/agent/pi-blackhole ~/.pi/agent/pi-blackhole-config.json
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Credits
363
+
364
+ The bulk of this codebase comes from two upstream projects:
365
+
366
+ - **[pi-vcc](https://github.com/sting8k/pi-vcc)** by @sting8k — algorithmic conversation compaction
367
+ - **[pi-observational-memory](https://github.com/elpapi42/pi-observational-memory)** by @elpapi42 — session-ledger-based observation and reflection capture
368
+
369
+ pi-blackhole combines, configures, and extends them into a single extension and adds unified configuration, per-worker model fallback chains, persisted cooldowns, manual flush mode, and conflict resolution between the two, and better error detection.
370
+
371
+ ## License
372
+
373
+ MIT
@@ -0,0 +1,115 @@
1
+ {
2
+ "_comment": "blackhole unified configuration — ~/.pi/agent/pi-blackhole-config.json",
3
+ "_all_settings_in_one_file": true,
4
+
5
+ "overrideDefaultCompaction": false,
6
+ "noAutoCompact": false,
7
+ "debug": false,
8
+
9
+ "model": {
10
+ "_comment": "Base model (last fallback before session model).",
11
+ "provider": "openrouter",
12
+ "id": "google/gemma-4-31b-it:free",
13
+ "thinking": "low",
14
+ "cooldownHours": 6
15
+ },
16
+
17
+ "observerModel": {
18
+ "_comment": "Observer primary: Qwen3 Next 80B via OpenRouter free (strong extraction with reasoning).",
19
+ "provider": "openrouter",
20
+ "id": "qwen/qwen3-next-80b-a3b-instruct:free",
21
+ "thinking": "low",
22
+ "cooldownHours": 12
23
+ },
24
+ "observerFallbackModels": [
25
+ {
26
+ "_comment": "Observer fallback 1: Gemma 4 31B via Ollama Cloud.",
27
+ "provider": "ollama",
28
+ "id": "gemma4:31b-cloud",
29
+ "thinking": "off",
30
+ "cooldownHours": 6
31
+ },
32
+ {
33
+ "_comment": "Observer fallback 2: Gemma 4 31B via OpenRouter free tier.",
34
+ "provider": "openrouter",
35
+ "id": "google/gemma-4-31b-it:free",
36
+ "thinking": "off",
37
+ "cooldownHours": 6
38
+ }
39
+ ],
40
+
41
+ "reflectorModel": {
42
+ "_comment": "Reflector primary: GPT OSS 120B via Cerebras (strong reasoning for synthesis).",
43
+ "provider": "cerebras",
44
+ "id": "gpt-oss-120b",
45
+ "thinking": "low",
46
+ "cooldownHours": 12
47
+ },
48
+ "reflectorFallbackModels": [
49
+ {
50
+ "_comment": "Reflector fallback 1: GLM-4.7 via z.ai with thinking enabled.",
51
+ "provider": "zai",
52
+ "id": "glm-4.7",
53
+ "thinking": "low",
54
+ "cooldownHours": 6
55
+ },
56
+ {
57
+ "_comment": "Reflector fallback 2: GPT OSS 120B via OpenRouter free tier.",
58
+ "provider": "openrouter",
59
+ "id": "openai/gpt-oss-120b:free",
60
+ "thinking": "low",
61
+ "cooldownHours": 6
62
+ }
63
+ ],
64
+
65
+ "dropperModel": {
66
+ "_comment": "Dropper primary: GPT OSS 120B via Cerebras (judgment/prioritization).",
67
+ "provider": "cerebras",
68
+ "id": "gpt-oss-120b",
69
+ "thinking": "off",
70
+ "cooldownHours": 12
71
+ },
72
+ "dropperFallbackModels": [
73
+ {
74
+ "_comment": "Dropper fallback 1: GLM-4.7 via z.ai.",
75
+ "provider": "zai",
76
+ "id": "glm-4.7",
77
+ "thinking": "low",
78
+ "cooldownHours": 6
79
+ },
80
+ {
81
+ "_comment": "Dropper fallback 2: GPT OSS 120B via OpenRouter free tier.",
82
+ "provider": "openrouter",
83
+ "id": "openai/gpt-oss-120b:free",
84
+ "thinking": "low",
85
+ "cooldownHours": 6
86
+ }
87
+ ],
88
+
89
+ "observeAfterTokens": 10000,
90
+ "reflectAfterTokens": 20000,
91
+ "compactAfterTokens": 81000,
92
+ "observationsPoolMaxTokens": 20000,
93
+ "reflectorInputMaxTokens": 80000,
94
+ "dropperInputMaxTokens": 80000,
95
+ "observerChunkMaxTokens": 40000,
96
+ "agentMaxTurns": 16,
97
+
98
+ "passive": false,
99
+ "noAutoCompact": false,
100
+ "debugLog": false,
101
+
102
+ "_notes": [
103
+ "Model fallback chains per worker:",
104
+ " Observer: qwen3-next-80b → gemma4:31b-cloud → google/gemma-4-31b-it:free → base model → session",
105
+ " Reflector: gpt-oss-120b (cerebras) → glm-4.7 (z.ai) → openai/gpt-oss-120b:free → base model → session",
106
+ " Dropper: gpt-oss-120b (cerebras) → glm-4.7 (z.ai) → openai/gpt-oss-120b:free → base model → session",
107
+ "",
108
+ "On retryable error (429, 5xx, timeout), the model is cooled down for cooldownHours.",
109
+ "Cooled-down models are skipped on subsequent consolidation attempts until cooldown expires.",
110
+ "After all candidates exhausted, the stage aborts. 30s retry gate prevents spam.",
111
+ "Cooldowns persist in ~/.pi/agent/pi-blackhole/pi-blackhole-cooldown.json (survives pi restarts).",
112
+ "Valid thinking values: off, minimal, low, medium, high, xhigh.",
113
+ "Env override for passive mode: PI_BLACKHOLE_PASSIVE=true."
114
+ ]
115
+ }
package/index.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Unified entry point. Registers all pi-vcc + observational-memory
3
+ * commands, hooks, and tools.
4
+ *
5
+ * Upstream: https://github.com/elpapi42/pi-observational-memory (src/index.ts)
6
+ * https://github.com/sting8k/pi-vcc (index.ts)
7
+ * Merged and extended by pi-vcc-om.
8
+ */
9
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
10
+ import { scaffoldSettings } from "./src/core/settings";
11
+ import { registerBeforeCompactHook } from "./src/hooks/before-compact";
12
+ import { registerPiVccCommand } from "./src/commands/pi-vcc";
13
+ import { registerMemoryCommand } from "./src/commands/memory";
14
+ import { registerVccRecallCommand } from "./src/commands/vcc-recall";
15
+ import { registerConsolidationTrigger } from "./src/om/consolidation.js";
16
+ import { registerCompactionTrigger } from "./src/om/compaction-trigger.js";
17
+ import { registerRecallTool } from "./src/tools/recall";
18
+ import { Runtime } from "./src/om/runtime.js";
19
+
20
+ export default (pi: ExtensionAPI) => {
21
+ scaffoldSettings();
22
+
23
+ const omRuntime = new Runtime();
24
+
25
+ // Observational memory: background consolidation pipeline
26
+ registerConsolidationTrigger(pi, omRuntime); // agent_start + turn_end → observer/reflector/dropper
27
+ registerCompactionTrigger(pi, omRuntime); // agent_end → auto-compaction
28
+
29
+ // Pi-vcc: compaction + om injection
30
+ registerBeforeCompactHook(pi, omRuntime); // session_before_compact → pi-vcc + om content
31
+
32
+ // Commands
33
+ registerPiVccCommand(pi, omRuntime); // /pi-vcc (needs runtime for noAutoCompact flush)
34
+ registerMemoryCommand(pi, omRuntime); // /blackhole-memory [status|view|full]
35
+ registerVccRecallCommand(pi); // /blackhole-recall <query>
36
+
37
+ // Tools
38
+ registerRecallTool(pi); // unified recall (#N + [12char])
39
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "pi-blackhole",
3
+ "version": "0.2.0",
4
+ "description": "Unified compaction + observational memory extension for Pi — compresses conversation context while preserving durable observations and reflections",
5
+ "license": "MIT",
6
+ "main": "index.ts",
7
+ "files": [
8
+ "*.ts",
9
+ "src/**/*.ts",
10
+ "!src/**/*.test.ts",
11
+ "!tests/",
12
+ "LICENSE",
13
+ "README.md",
14
+ "example-config.json"
15
+ ],
16
+ "scripts": {
17
+ "check": "tsc --noEmit"
18
+ },
19
+ "keywords": [
20
+ "pi-package",
21
+ "pi-extension",
22
+ "pi",
23
+ "pi-coding-agent",
24
+ "pi-agent",
25
+ "pi-blackhole",
26
+ "blackhole",
27
+ "compact",
28
+ "compaction",
29
+ "observational-memory",
30
+ "recall",
31
+ "ai",
32
+ "agents",
33
+ "cli"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/k0valik/pi-blackhole.git"
38
+ },
39
+ "dependencies": {
40
+ "@earendil-works/pi-agent-core": "0.75.5",
41
+ "@earendil-works/pi-ai": "0.75.4",
42
+ "@earendil-works/pi-coding-agent": "0.75.4",
43
+ "@earendil-works/pi-tui": "0.75.5",
44
+ "typebox": "^1.1.38"
45
+ },
46
+ "pi": {
47
+ "extensions": [
48
+ "./index.ts"
49
+ ]
50
+ },
51
+ "devDependencies": {
52
+ "typescript": "^5.7.3",
53
+ "vitest": "^4.1.7"
54
+ }
55
+ }