@hheei/pi-ext-memory0.2.1
Observational memory extension for Pi — cache-friendly tiered compaction with observations and reflections.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
@hheei/pi-ext-memory
Make Pi sessions feel endless.
@hheei/pi-ext-memory 是 HEPI Monorepo 中基于 pi-observational-memory 构建与维护的会话观测式记忆扩展。
它通过分层的 Observations(观测)与 Reflections(反思)机制,在后台持续提炼会话中的关键事实与决策,从而在执行上下文压缩(Compaction)时保持会话连贯性,显著减少模型上下文退化。
核心特性
- 后台渐进式记忆提炼:在后台异步捕获会话中的具体事件(Observations),并提炼为长期稳定的事实(Reflections),避免在压缩时临时耗时总结。
- 瞬时 Compaction 渲染:压缩触发时,直接渲染已准备好的记忆块,压缩过程几乎瞬时完成。
- 证据可溯源(Source-backed Recall):每条观测和反思附带 12 字符的 ID,Agent 可使用
recall工具快速检索对应原始会话片段证据。 - 活跃记忆修剪(Dropper):后台基于覆盖率、时效性和重要度自动修剪活跃观测池,防止记忆自身发生膨胀。
- Monorepo 统一集成:完全接入当前工程的统一类型校验(
pnpm run typecheck)与测试套件(pnpm test),无需独立维护工具链。
开发与使用
构建与打包
在仓库根目录运行:
# 全局类型检查(包含该包)
pnpm run typecheck
# 运行本包测试
pnpm exec vitest run packages/pi-ext-memory/test/
# 构建扩展产物
pnpm --filter @hheei/pi-ext-memory run build
加载扩展
在启动 Pi 时显式加载扩展入口:
pi --extension ./packages/pi-ext-memory/dist/extension.js
# 或在开发模式下直接加载源码:
pi --extension ./packages/pi-ext-memory/src/index.ts
配置说明
Settings live under the pi-ext-memory namespace in either:
- Global:
~/.pi/agent/ext_settings.json - Project-local:
<cwd>/.pi/ext_settings.json
Project settings override global settings.
The namespace was renamed from observational-memory to pi-ext-memory. The old key is no longer read, so rename it in both files after upgrading.
PI_OBSERVATIONAL_MEMORY_PASSIVE can override only passive.
A typical config:
{
"pi-ext-memory": {
"observeAfterTokens": 10000,
"reflectAfterTokens": 20000,
"compactAfterTokens": 81000,
"compactAfterTokensMode": "calibrated",
"compactAfterTokensRatio": 0.68,
"observationsPoolMaxTokens": 20000,
"observationsPoolTargetTokens": 10000,
"agentMaxTurns": 16,
"model": {
"provider": "openrouter",
"id": "google/gemma-4-31b-it",
"thinking": "low"
},
"showWorkerNotifications": true,
"passive": false,
"debugLog": false
}
}
Most users can start with the defaults and tune only if they have a specific reason.
If your memory model is a local llama.cpp server, size agentMaxTokens so that a worst-case request (observer chunk + prior memory + system prompt + the full response budget) fits inside the server's context: slot KV is shared between the main session's retained cache and concurrent sub-agent requests, so an over-budget sub-agent request fails with 500 "Context size has been exceeded." and the affected memory run aborts. For example, on a 64K-slot server, pairing "agentMaxTokens": 8192 with a low observerChunkMaxTokens keeps sub-agent requests well inside the window.
Scaling compaction to the model's context window
By default compactAfterTokensMode is "calibrated", so the proactive
compaction trigger uses the fixed compactAfterTokens estimated source-entry
threshold (81,000 by default). This preserves the pre-PR #40 compaction metric
for typical ~128K–200K context models.
On a large-context model (e.g. 1M tokens) the calibrated default preempts
compaction at ~81K, wasting most of the window. Switch to "ratio" mode to let
the trigger scale with the active model's contextWindow:
{
"pi-ext-memory": {
"compactAfterTokens": 81000,
"compactAfterTokensMode": "ratio",
"compactAfterTokensRatio": 0.5
}
}
In ratio mode the effective threshold is
floor(model.contextWindow * compactAfterTokensRatio) (clamped to a minimum of
1). With the example above, a 1,000,000-token window compacts after about
500,000 estimated source-entry tokens after the latest compaction boundary; a
200,000-token window uses about 100,000. The threshold counts source entries,
not Pi's system prompt, tool schemas, or provider accounting. Pi's native
window-pressure compaction remains independent.
compactAfterTokensRatio is user-tunable precisely because context window ≠
attention. Some models advertise a large window but degrade at long range; set
a lower ratio (e.g. 0.4) to compact earlier on those, or a higher ratio
(e.g. 0.7) on models that stay sharp. The default ratio is 0.68.
compactAfterTokens is always retained as the fallback: in "calibrated"
mode it is the threshold directly, and in "ratio" mode it is used whenever
the active model's contextWindow is unavailable (undefined, 0, or negative),
so compaction still triggers safely. /om status shows the resolved threshold
on the Next compaction line regardless of mode.
Defaults
| Setting | Default | Meaning |
|---|---|---|
observeAfterTokens |
10000 |
Raw/source token threshold for observation runs. |
observerChunkMaxTokens |
derived | Max estimated tokens serialized into one observer chunk (minimum 256). Unset: floor(contextWindow * 0.2) of the resolved memory model, or 60000 when the window is unknown. Larger backlogs drain oldest-first; a single over-budget source is sent as a marked head/tail excerpt while the original source remains in the session ledger. |
reflectAfterTokens |
20000 |
Raw/source token threshold for reflection runs; successful reflection creates dropper opportunities. |
compactAfterTokens |
81000 |
Estimated source-entry threshold for proactive auto-compaction, counted after the latest compaction boundary. |
compactAfterTokensMode |
"calibrated" |
"calibrated" uses compactAfterTokens directly. "ratio" scales the source-entry threshold by the active model's contextWindow. |
compactAfterTokensRatio |
0.68 |
In "ratio" mode, the threshold is floor(contextWindow * ratio). Tunable because large windows do not always mean strong long-range attention. Must be in (0, 1). |
observationsPoolMaxTokens |
20000 |
Observation-token budget used for compaction full-fold pressure. |
observationsPoolTargetTokens |
half of max | Active observation target used by post-reflection dropper maintenance and by the pool enforcer, and the observation share of the rendered memory budget. |
memoryMaxTokens |
derived | Hard upper bound on how many tokens of memory stay visible. Unset: min(floor(effective trigger * 0.5), floor(contextWindow * 0.1)), never below 4000. Caps the rendered compaction summary, the dropper's target and what the memory agents read. See Memory budget. |
agentMaxTurns |
16 |
Shared turn cap for background memory-agent loops. |
agentMaxTokens |
32000 |
Maximum output tokens requested for memory-agent loops (observer/reflector/dropper), clamped to the model's own maxTokens when available. Lower it for local servers with a modest context window, e.g. 8192. |
model |
session model | Optional memory-worker model override: { provider, id, thinking }. |
showWorkerNotifications |
true |
Shows routine observer, reflector, and dropper progress notifications. Warnings and errors are unaffected. |
passive |
false |
Disables proactive background observation, reflection, maintenance, and auto-compaction triggers. |
debugLog |
false |
Writes opt-in per-session extension debug events to Pi's agent directory. |
Valid model.thinking values are:
offminimallowmediumhighxhighmax
If no model is configured, memory workers use the session model, including custom pi.registerProvider APIs such as cursor-sdk. You do not need a second built-in provider (OpenAI, OpenRouter, …) for observational memory to run. Set model only when you want cheaper or faster workers than the coding agent.
Set showWorkerNotifications to false to hide routine worker start and completion messages (including deliberate-empty observer info messages). Model fallback/unavailability, worker failures (including observer stream errors), compaction notifications, the pool enforcer's reclaim notice (a memory change with no model in the loop), and explicit /om subcommand output remain visible.
observationsPoolMaxTokens and observationsPoolTargetTokens intentionally describe different pools. Max tokens control when compaction performs a full fold over visible memory. Target tokens control the folded active observation pool that the dropper maintains after successful reflection, and the observation share of the rendered memory budget. If the target is omitted, it defaults to half of max.
Memory budget
Rendered memory is bounded, so compaction always shrinks the context instead of replacing it with a summary that can be larger than the window. Without that bound a long session drifts into a loop: the deterministic summary grows past the trigger, Pi compacts again immediately, and the request eventually overflows and aborts.
The budget is derived at compaction time:
softLimit = min(compactAfterTokens, contextWindow − Pi's reserveTokens)
available = softLimit − retained tail tokens − system prompt tokens
renderBudget = clamp(available × 0.5, 4000, memoryMaxTokens)
Pi reports the tail it keeps after the cut (firstKeptEntryId onward), so a session retaining a large tail gets a smaller memory budget; an overflow-recovery compaction halves it again. memoryMaxTokens pins the cap when the derived one is wrong for a workload. Inside the budget, selection is deterministic — uncovered observations first, then relevance, then newest; reflections keep the session's first eight entries as anchors and then the newest — and trimmed lines are not deleted, only hidden until recalled by id.
The same view is what the memory agents read, so their prompts stay bounded too; the dropper's drop budget is still sized from the real active pool, so visibility never disables the model-judged pass. /om status reports the cap, active memory against it, and the last render's tokens, trimmed lines, and retained tail; the compaction entry records it as details.budget. A trim that costs a quarter or more of the memory lines reports one notification.
Trimmed lines stay in the ledger, so the ledger is bounded too: above half again the cap, a model-free enforcer reclaims non-critical observations down to their target and writes one om.observations.dropped entry. It ranks by observation kind first — progress narration leaves before facts, and both before user assertions and decisions — which is also the order the renderer prefers to trim in.
Reflections have no eviction path: they leave active memory only when the reflector replaces them. In the same record_reflections call that proposes a merged reflection it lists the ids it replaces in supersedes, and the stage writes one om.reflections.dropped tombstone. A reflection therefore never leaves active memory without a replacement — an invalid proposal produces no tombstone, unknown ids are ignored, and proposing content identical to an existing reflection still carries its supersedes, so the pool can converge on wording that already exists. Superseded reflections keep their ledger records (/om view full still shows them) but stop counting toward the cap and stop providing coverage; the surviving reflection keeps its own supporting observation ids (the ledger has no update path), so the replaced reflection's observations just lose their coverage — which makes them harder, not easier, to trim. A merge that proposes new content inherits the supporting ids of what it replaces, so merging still has evidence when no observation is left to cite, and each proposal's supersedes stands on its own: one proposal whose replacement can never become active is skipped while the other merges in the same call still retire theirs. The reflector is given its share of the render budget (REFLECTION BUDGET), measured against the whole active pool rather than the trimmed view, and is told to merge before adding when it is over.
Dropper pruning balances age, relevance, and reflection coverage. Relevance is importance/resistance, not a permanent active-memory pin: critical observations require the strongest evidence but can be dropped when they are older and safely represented by reflections, superseded by newer memory, redundant, or obsolete. Dropper input annotates each active observation with deterministic coverage evidence: none, partial, or strong; coverage guides model judgment and is not an automatic drop rule. Dropping removes observations from active memory, not ledger history.
When debugLog is enabled, debug events are written as local NDJSON files under Pi's agent directory. Normal sessions write to observational-memory/debug/<session-id>.ndjson; contexts without a session id fall back to observational-memory/debug.ndjson. Debug rows include sessionId and per-consolidation runId, so a session file can still be filtered to one observer/reflector/dropper run.
For details and tuning guidance, see docs/configuration.md.
Commands and agent tool
| Surface | What it does |
|---|---|
/om |
Reports whether observational memory is on or off for this session. |
/om on / /om off |
Turns the session gate on or off. The state is a ledger entry on the current branch, so /tree switches and /resume restore it automatically. |
/om status |
Shows gate/passive mode, memory counts (observations recorded/dropped/active/visible, reflections recorded/superseded/active/visible, plain +N / -N visible/full drift suffixes), progress clocks, visible and active observation pool pressure, memory budget, worker spend, in-flight state, last worker errors, and a timeline strip of the branch. |
/om consolidate |
Runs one consolidation cycle now (observer → reflector → dropper) instead of waiting for the token thresholds. |
/om compact |
Compacts the session now instead of waiting for the compaction threshold or the idle timer, using the memory summary rather than Pi's native summarizer. |
/om view |
Shows current visible memory and attempts to copy the rendered memory text to the clipboard. |
/om view full |
Shows the full current memory state for the branch and attempts to copy the rendered memory text to the clipboard. |
recall agent tool |
Recovers source evidence for a 12-character observation/reflection id on the current branch. It is not semantic search or a transcript browser. |
mcp__hindsight__* tools |
Opt-in cross-session long-term memory via native MCP server (see Hindsight long-term memory). When hindsight.enabled is true, registers the hindsight MCP server with direct exposure for key knowledge tools (get_knowledge_base_tree, search_knowledge_base, get_knowledge_page, recall, reflect, retain) and deferred exposure for all other server tools. Withdrawn when disabled. |
Tab completion after /om offers these subcommands (and full after /om view ), through the shared
subcommandCompletions helper of @hheei/pi-ext-core.
The recall result body reuses the shared status glyphs instead of ASCII marks: its first line is
success · N observations · M sources · ~K tokens, a result that came back short says what stopped
it ( not found, disabled), every returned item gets an aligned reflection / observation /
source row, and every caveat gets an note row (a dropped observation, a missing source, an id
collision). The frame above the body draws the same glyph for the same result.
Session gate vs. passive mode
The two switches are orthogonal:
- Gate (
/om on//om off) decides whether observational memory runs at all in this session. While it is off, the hooks return immediately, idle timers are dropped, andrecallanswers with a disabled notice instead of a memory. The gate is stored as anom.gateledger entry on the branch, so switching branches with/treeor resuming a session restores the state that branch recorded. A branch that never recorded one is on. passiveis a configuration value. With the gate on andpassive: true, automatic background workers and auto-compaction stay idle while/om consolidate,/om compact,/om view, andrecallremain available.
Manual commands
/om consolidate shares the same in-flight lock as the automatic path: it declines while another consolidation or a compaction is running, and it declines when there is nothing uncovered and no memory yet. It ignores the observeAfterTokens / reflectAfterTokens thresholds, but the dropper still only removes observations when the active pool is over observationsPoolTargetTokens.
/om compact waits for an in-flight consolidation to finish (so the summary covers the newest memories), then refuses to start when nothing new arrived since the last compaction or when the fold holds no observations and no reflections. That refusal is deliberate: an empty projection makes the compaction hook decline ownership and Pi would fall back to its slow, unbounded native summarizer.
Worker spend and timeline
/om status reports provider-reported worker spend for the session (usage.cost.total accumulated per worker call) and appends a timeline strip of the current branch:
timeline legend: ▓ compacted ▒ memory pool ░ raw backlog ┊ cut ▶ tip
▓ is history a compaction already replaced with a memory summary, ▒ is history the observer has covered that still lives as observations, ░ is raw backlog waiting for the observer, ┊ marks a compaction cutoff, and ▶ is the branch tip. The strip is scaled to the terminal width, and cost is run-time telemetry only: it is never written to the ledger and never rolls back on a /tree switch, because the API calls it accounts for already happened.
/om view copies only the rendered memory content. The success/failure line shown in Pi is not included in the clipboard text. Copying goes through Pi's own clipboard helper, so a remote SSH session reaches the client clipboard over OSC 52 and a Linux desktop without wl-clipboard/xclip/xsel still prints the memory view with a warning that names the missing tool. Before the first V3 compaction, visible memory can be empty because nothing has been folded into om.folded details; use /om view full to inspect recorded branch memory.
How it works in 60 seconds
flowchart TD
Turn[turn_end]
Observe[Capture observations]
Reflect[Distill reflections]
AgentSettled[agent_settled]
Trigger[auto-compaction trigger]
Compact[session_before_compact]
Summary[visible memory for Pi]
Turn -->|observation due| Observe
Turn -->|reflection due| Reflect
AgentSettled -->|compactAfterTokens and idle| Trigger --> Compact --> Summary
The high-level lifecycle:
- Pi session continues normally.
- The extension captures observations from the session as work happens.
- Durable reflections are distilled in the background.
- When compaction time arrives, Pi receives prepared memory quickly.
- The agent continues with a compact but useful view of the work so far.
The important part: compaction does not need to rethink the whole session from scratch.
The proactive compaction threshold counts estimated source-entry tokens after
the latest compaction boundary. It includes source entries retained by
firstKeptEntryId and newer source entries, while memory ledger entries and
compaction metadata contribute zero. /om status uses the same metric. Pi's
own window-pressure compaction remains independent.
Current V3 behavior
Current behavior:
- Observation-centered memory. The extension records useful session observations while you work.
- Durable reflections. The extension distills stable facts that help the agent stay oriented over time.
- Fast compaction. When prepared V3 memory exists,
session_before_compactrenders it without calling a model or waiting for background workers. An empty V3 projection delegates to Pi's native summarizer instead of replacing prior context with an empty summary. - Background memory work. Observation and reflection work run from
turn_endwhen their token clocks are due; dropper work runs only after successful reflection and prunes the folded active observation ledger towardobservationsPoolTargetTokens. - Source-backed recall. Observations and reflections can be traced back through the
recalltool. - Visible/full views.
/om viewshows visible memory and/om view fullshows the full current memory state. Use/om statusfor visible-vs-full drift and for the separate visible observation pool vs active observation pool. - No V2 compatibility layer. Old V2 settings and memory entries are ignored rather than migrated.
Hindsight long-term memory
Observational memory is session-scoped: it compacts the conversation you are in. Hindsight adds cross-session, repository-level memory on top of it, and is off unless you explicitly turn it on (enabled: true). When the option is disabled, pi-ext-memory registers no extension-owned MCP server, reads no Hindsight config file, and makes no network requests.
External file-configured MCP servers (e.g. configured in ~/.pi/agent/mcp.json or project .pi/mcp.json) remain completely independent and functional regardless of whether pi-ext-memory's Hindsight feature is enabled or disabled.
Prerequisites
- Requires Pi >= 1.0.1.
- Requires Pi's
builtin:mcpextension enabled.
Configuration
{
"pi-ext-memory": {
"hindsight": {
"enabled": false,
"apiUrl": "https://api.hindsight.vectorize.io",
"mcpUrl": "https://api.hindsight.vectorize.io/mcp",
"apiToken": "",
"bankId": "",
"autoRecall": true,
"retainSessions": true,
"readTimeoutMs": 15000,
"maxMemoryChars": 8000,
"configPath": "~/.hindsight/coding-agent.json"
}
}
}
Values are resolved in this order, each layer overriding the ones below it:
pi-ext-memory.hindsightin projectext_settings.jsonpi-ext-memory.hindsightin globalext_settings.jsonHINDSIGHT_API_URL,HINDSIGHT_API_TOKEN,HINDSIGHT_BANK_ID,HINDSIGHT_MCP_URL,HINDSIGHT_CONFIGbanks.<bankId>in the fallback file (itsretainTagsandretainMetadataare inherited)- The fallback file's top-level
apiUrl/mcpUrl/bankId - The defaults above
enabled is only read from settings, never from the environment.
- Independent MCP endpoint and ports:
mcpUrlconfigures the streamable HTTP MCP endpoint (Pi streamable HTTP MCP transport, not SSE). It defaults to<apiUrl>/mcp. The ports forapiUrlandmcpUrlare independent and are not inferred from each other. If your REST API runs on port 38888 and your MCP endpoint on port 38887, setmcpUrl(orHINDSIGHT_MCP_URL) explicitly to the MCP endpoint (e.g.http://host:38887/mcporhttp://host:38887). - Session bank routing: The extension dynamically pins the session MCP connection to the single-bank endpoint
/mcp/{bank_id}/.
Bank routing and repository isolation
The bank is chosen by the first rule that applies:
hindsight.bankIdmapPathToBankin the fallback file, longest matching path prefixbankIdTemplatein the fallback file, with{gitProject}replaced by the repository name- The fallback file's
bankId coding-agent::{gitProject}, derived from the git root
The repository name is the git root directory name, so every subdirectory of a checkout resolves the same way.
A bank derived per repository (rules 3 and 5) is a dedicated bank. Any other bank is treated as a shared bank.
- Dedicated banks: Provide strong repository isolation by keeping memory, knowledge pages, and notes in physically distinct banks.
- Shared banks (no repo filter on MCP tools or knowledge pages): Native MCP tools (
mcp__hindsight__*) communicate directly with/mcp/{bank_id}/and operate bank-wide without repository filtering. Similarly, automatic SDK knowledge-page search in Hindsight is bank-wide (Hindsight knowledge pages have no repository tag filter). Only automatic SDK background session writeback stamps turns with arepo:<name>tag. Therefore, shared banks are not repository-isolated for knowledge pages or MCP tool operations. Always use dedicated banks when complete isolation between repositories is required. - Diagnostics: Run
/om statusto inspect effective bank routing, isolation mode, endpoints, token status, external file config overrides, auto-recall, retention, and writeback state. Never logs or prints auth tokens.
Behavior
- Stable guide. The preamble explaining the memory and its tools goes into its own
hindsight-preambleprompt section, together with a snapshot of the knowledge-page index. Every turn supplies the same text so Pi keeps the section. Resume reuses the active branch's persisted guide when its repository, bank, scope, and guidance still match; otherwise a new guide is built. Remote page changes do not rewrite an existing guide on resume. - Later turns. With
autoRecall, a knowledge-page search runs for the prompt and up tomaxMemoryCharscharacters of escaped, untrusted-by-construction hits land in ahindsight-recallsection inside a<memory>container. Pi sends a section only when its text changed, and an unchanged section is never repeated as a prompt update — the request itself still carries whatever the host and provider keep in context. Retrieval failures are silent. Deepmcp__hindsight__reflectsynthesis is never automatic: it stays an explicit tool call. - Injection log. Every turn that injects something appends a
memory-infotranscript entry naming what went in. It lists the recalled page titles (for a page that did reach the prompt), expands (Ctrl+O) to each page id and the recalled snippet the model was given, and marks a container that had to be cut tomaxMemoryCharswith awarning row. It is native Pi territory: visible immediately, kept by resume, and never part of the model's context. - Native write cache invalidation. Whenever a mutating MCP tool (such as
mcp__hindsight__retainor custom authoring tools withoutreadOnlyHint) is invoked,pi-ext-memoryautomatically invalidates the auto-recall cache so subsequent turns immediately reflect the new memory. - Error normalization. Business errors returned inside MCP
CallToolResultpayloads are detected and normalized toisError: trueon both the outer event and the inner structured content wrapper. - Turn end. The run's user/assistant turns are reduced to a compact transcript (tool results and injected memory dropped, failed or aborted responses skipped) and written back in order, one request at a time. The operation id is derived from the bank, session, and batch content, so a retry or a repeated
agent_endfolds server-side instead of duplicating. - Session end. Pending writeback is flushed within a five-second grace period, then cancelled. A failed writeback is recorded and never interrupts the conversation.
Tools
Tools are provided by the native Hindsight MCP server under the mcp__hindsight__ namespace.
- Upstream authoritative server: The Hindsight server is the sole authority for tool authoring, definitions, schemas, and execution logic.
pi-ext-memorydoes not author or wrap tools, enabling future server-side tool additions to work out of the box without extension changes. - Exposure:
- Direct exposure (directly available in the model's context):
mcp__hindsight__get_knowledge_base_tree: Page hierarchy and structure of the knowledge base.mcp__hindsight__search_knowledge_base: Semantic search across the bank's knowledge vault.mcp__hindsight__get_knowledge_page: Fetch full markdown content of a page by path.mcp__hindsight__recall: Fact and turn recall from long-term memory.mcp__hindsight__reflect: Deep agentic reflection and cross-conversation synthesis over memory.mcp__hindsight__retain: Store durable facts, decisions, and corrections (with content starting withCorrection: <topic>).
- Deferred exposure: All other tools provided by the Hindsight server are registered as
deferred(loaded on demand viatool_searchor callable via codemode scripts).
- Direct exposure (directly available in the model's context):
- Execution & timeout: MCP tool calls run through Pi's native MCP client with a 60-second timeout (
timeout: 60), accommodating deep reflection queries without client-side budget hacks.
Migrating from V2
V3 is not backwards compatible with V2 memory or settings.
What this means in practice:
- Update your settings. V2 keys are silently ignored by V3. Keeping the old names will make V3 fall back to defaults.
- Start a new clean Pi session after upgrading. Existing sessions may still contain old visible compaction-summary text until a new V3 compaction replaces what the agent sees, so a clean session is the safest migration path.
- Do not expect rollback continuity. If you create V3 memory entries and then roll back to V2, V2 will not understand the V3 memory format. Treat that as memory reset/visibility loss.
Settings migration table
| V2 setting | V3 setting | What to do |
|---|---|---|
observationThresholdTokens |
observeAfterTokens |
Rename. Same rough role: observation cadence based on raw/source tokens. |
compactionThresholdTokens |
compactAfterTokens |
Rename. Same rough role: proactive compaction cadence. |
reflectionThresholdTokens |
reflectAfterTokens, observationsPoolMaxTokens, and/or observationsPoolTargetTokens |
Split. Use reflectAfterTokens for reflection scheduling, observationsPoolMaxTokens for compaction full-fold pressure, and observationsPoolTargetTokens for dropper active observation maintenance. |
compactionModel |
model |
Move { provider, id } to model. |
thinkingLevel |
model.thinking |
Move under model. |
observerMaxTurnsPerRun |
agentMaxTurns |
Replace with the shared memory-agent turn cap. |
reflectorMaxTurnsPerPass |
agentMaxTurns |
Replace with the shared memory-agent turn cap. |
prunerMaxTurnsPerPass |
agentMaxTurns |
Replace with the shared memory-agent turn cap. |
compactionMaxToolCalls |
none | Remove. There is no V3 alias. |
passive |
passive |
Keep if desired. |
debugLog |
debugLog |
Keep if desired. |
Example V2 config:
{
"observational-memory": {
"observationThresholdTokens": 1000,
"compactionThresholdTokens": 50000,
"reflectionThresholdTokens": 30000,
"compactionModel": { "provider": "openrouter", "id": "google/gemma-4-31b-it" },
"thinkingLevel": "low",
"observerMaxTurnsPerRun": 8,
"reflectorMaxTurnsPerPass": 12,
"prunerMaxTurnsPerPass": 12,
"passive": false
}
}
V3 equivalent:
{
"pi-ext-memory": {
"observeAfterTokens": 10000,
"reflectAfterTokens": 20000,
"compactAfterTokens": 81000,
"observationsPoolMaxTokens": 20000,
"observationsPoolTargetTokens": 10000,
"agentMaxTurns": 12,
"model": {
"provider": "openrouter",
"id": "google/gemma-4-31b-it",
"thinking": "low"
},
"passive": false
}
}
More docs
docs/concepts.md— vocabulary and V3 mental model.docs/how-it-works.md— lifecycle, memory shapes, projections, and recall flow.docs/configuration.md— all V3 settings and migration notes.
Credits
Inspired by Mastra's Observational Memory research.
This is an independent implementation built for Pi's extension system.
License
MIT