pi-jev-compaction

Pi Coding Agent extension that replaces LLM-summary compaction with TypeSafe Jev keep/drop/truncate decisions.

Packages

Package details

extension

Install pi-jev-compaction from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-jev-compaction
Package
pi-jev-compaction
Version
1.0.0
Published
Sep 18, 2026
Downloads
761/mo · 761/wk
Author
each1024
License
MIT
Types
extension
Size
279.4 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./src/extension.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-jev-compaction

中文文档

Pi Coding Agent extension that replaces (or augments) Pi’s default LLM-summary compaction with TypeSafe Jev keep / drop / truncate decisions. UI strings and toasts are English only.

Score tool calls and results, drop or truncate stale ones, keep user/assistant text verbatim. Fails soft to Pi’s built-in compaction.

Algorithm and question format adapted from fast-jev-compaction (MIT). That repo’s Claude Code plugin can replace the entire message list; Pi cannot — see Approach below.

Quick start (30 seconds)

  1. pi install npm:pi-jev-compaction
  2. To pin this release, use pi install npm:pi-jev-compaction@1.0.0 (or use @latest for the latest release).
  3. Get a personal TypeSafe key at https://console.typesafe.ai/settings/keys
  4. Persist the key (see Key setup), then restart Pi or /reload
  5. Expect a ready toast, or run /jev-status

Cost & fallback

Jev calls the TypeSafe API when compacting. Without a key, on network/auth/errors, when history cannot fit, when reduction is too small, or when aborted, the extension falls back to Pi’s built-in summary — no hard failure.

# From a local clone (no publish needed)
git clone <this-repo>
cd pi-jev-compaction
npm install
pi install /absolute/path/to/pi-jev-compaction

# Project-level install from npm (writes .pi/settings.json; shares the extension, not the key)
pi install -l npm:pi-jev-compaction

# Project-level install from a local clone
pi install -l /absolute/path/to/pi-jev-compaction

# Try for this session only
pi -e /absolute/path/to/pi-jev-compaction/src/extension.ts

Registry install note: Pi treats bare package names as local paths; always use the npm: prefix for registry packages (for example, npm:pi-jev-compaction).

On session start the extension toasts once (in-memory flag only; not written to disk; /reload does not repeat it):

  • TYPESAFE_API_KEY detected: pi-jev-compaction: ready…
  • Missing: numbered steps (get key → export or env file → reload → /jev-status)

Key setup

Each user brings their own TypeSafe key. Do not commit personal TYPESAFE_API_KEY values to the repo, settings files, or share them with colleagues.

Who What to do
You Prefer export TYPESAFE_API_KEY in your shell profile, or create ~/.config/pi-jev-compaction/env (see below).
Colleagues / OSS contributors Each person applies for their own TypeSafe key. This extension does not and should not ship or forward someone else’s key.
CI Inject TYPESAFE_API_KEY from a runner secret. Without a key the extension falls back to Pi’s built-in summary.

Do not put the key in ~/.config/pi-jev-compaction/config.json. That file accepts thresholds only; parsing and /jev-setup strip any apiKey field.

Persist the key

Option A — shell profile (preferred):

# zsh example (~/.zshrc)
echo 'export TYPESAFE_API_KEY="sk-..."' >> ~/.zshrc && source ~/.zshrc

Option B — env file (used only when TYPESAFE_API_KEY is unset in the process environment):

~/.config/pi-jev-compaction/env (or $XDG_CONFIG_HOME/pi-jev-compaction/env)

mkdir -p ~/.config/pi-jev-compaction
printf 'TYPESAFE_API_KEY=sk-...\n' > ~/.config/pi-jev-compaction/env
chmod 600 ~/.config/pi-jev-compaction/env

Comments (# ...) and blank lines are ignored; surrounding quotes are stripped. /jev-setup never writes the key into config.json.

Commands

Command What it does
/jev-status Whether a key was detected (shows only detected/missing, never prints the secret), config + env-file paths, effective options, last compact outcome including why it fell back (no_key / jev_error / reduction_too_small / cannot_fit / aborted / …)
/jev-setup Walks through applying for a key + export / env file; writes thresholds to config.json. Interactive confirm, or /jev-setup defaults, or paste JSON (apiKey is stripped)
/jev-status
/jev-setup
/jev-setup defaults
/jev-setup {"keepThreshold":0.6,"minReductionRatio":0.3}

Options

Defaults match the Claude plugin.

Option Default Description
keepThreshold 0.5 Minimum Jev probability to keep a call / result
preserveRecentMessages 6 Newest N Jev messages are never changed (the first message is always kept too)
minReductionRatio 0.25 If character reduction is below this, fall back to Pi’s default summary
maxStateTokens 25000 Estimated cap for state sent to Jev
maxRequestTokens 30000 Estimated cap for a single request (state + questions)
truncateHeadChars 300 Head characters kept when a tool result is truncated
model jev-latest Jev model
baseUrl https://api.typesafe.ai/v1/systemone System One endpoint

Optional config file (thresholds only):

~/.config/pi-jev-compaction/config.json (or $XDG_CONFIG_HOME/pi-jev-compaction/config.json)

{
  "keepThreshold": 0.5,
  "preserveRecentMessages": 6,
  "minReductionRatio": 0.25,
  "maxStateTokens": 25000,
  "maxRequestTokens": 30000,
  "truncateHeadChars": 300,
  "model": "jev-latest"
}

Environment overrides: PI_JEV_MODEL, PI_JEV_BASE_URL, PI_JEV_KEEP_THRESHOLD, PI_JEV_PRESERVE_RECENT, PI_JEV_MIN_REDUCTION, PI_JEV_MAX_STATE_TOKENS, PI_JEV_MAX_REQUEST_TOKENS, PI_JEV_TRUNCATE_HEAD, PI_JEV_GOAL.

Fallback & toasts

In the cases below the extension does not return compaction, and Pi continues with its built-in LLM summary. Each path has a matching toast (including manual / threshold / overflow):

Path Toast
No key Fallback + how to configure (/jev-setup, signup URL, env file)
Jev network / auth / malformed response Reason + fallback
History does not fit state budget Reason + fallback
reductionRatio < minReductionRatio “not worth it” + fallback
Very short / no scorable tool calls Skip Jev, explain, then fallback
AbortSignal cancelled Silent on session_before_compact; short note on session_compact_failed
Success kept / truncated / dropped, approx. reduction %, elapsed time

/jev-status records the last outcome’s kind (e.g. reduction_too_small) so you can see why Jev did not take over.

session_compact then confirms whether the saved summary is the Jev verbatim encoding or Pi’s built-in summary.

Approach & limitations vs Claude Code

Pi compaction is summary + cut-point, not Claude Code’s full-list replace.

Verified against @earendil-works/pi-coding-agent@0.85.1:

  • Event: session_before_compact, payload SessionBeforeCompactEvent (preparation, branchEntries, reason: manual | threshold | overflow, signal).
  • Handler may return SessionBeforeCompactResult: { cancel?: boolean; compaction?: CompactionResult }.
  • CompactionResult: { summary, firstKeptEntryId, tokensBefore, estimatedTokensAfter?, usage?, details? }.
  • SessionManager is append-only: ctx.sessionManager is read-only; history entries cannot be rewritten or deleted. There is no API equivalent to Claude’s session.compact → { messages }.

So this extension:

  1. Converts messagesToSummarize + turnPrefixMessages + kept messages from firstKeptEntryId into Jev Message[] (plus optional previousSummary).
  2. Runs the same compact(): asks two noul questions per unpinned tool call (keep call / keep full result).
  3. Encodes only the compactable region after prune / truncate into a verbatim structured summary (user/assistant text kept as-is; dropped tool calls omitted; truncated results keep head + note).
  4. Returns { summary, firstKeptEntryId: preparation.firstKeptEntryId, tokensBefore, details }. Pi still sends entries after the cut-point to the model unchanged.

What it cannot do (vs the Claude plugin):

  • Cannot rewrite tool results in the “will be kept” region in place. Those messages sit after firstKeptEntryId and enter the next context verbatim. preserveRecentMessages pins them; Jev does not truncate them.
  • Cannot re-insert pruned older messages into the session tree; they only live inside the summary string.
  • No compactAtPercent / turn.complete auto-trigger — Pi owns when compaction runs (manual / threshold / overflow). Configure Pi’s own compaction thresholds; this extension only handles session_before_compact.
  • Therefore this is “lossless for text, lossy for tool bulk” summary encoding, not Claude-style object-level transcript replace.

Upstream parity (algorithm / config)

Upstream feature Status
Options & defaults (keepThreshold 0.5, preserveRecentMessages 6, budgets 25k/30k, truncateHeadChars 300, minReductionRatio 0.25, jev-latest) Matched
State fitting stages, token estimate, question batching, keep/drop/truncate decisions Matched (src/jev/)
Concurrent batched Jev requests, soft fallback on error / too-small reduction / no key Matched (adapted toasts + /jev-status)
Per-call decisions: diagnostic dump Matched (in verbatim summary + /jev-status)
Config file + env overrides for thresholds Matched (~/.config/pi-jev-compaction/, PI_JEV_*)
Full message-list replace via session.compact → { messages } Impossible on Pi (append-only SessionManager)
compactAtPercent turn-complete auto-compact Impossible / N/A — Pi triggers compaction itself
Claude plugin marketplace / function hooks N/A (Pi extension + pi install npm:pi-jev-compaction)

Library API

import {
  compactPiSession,
  compact,
  type JevAsker,
} from "pi-jev-compaction";

const outcome = await compactPiSession({
  messagesToSummarize,
  turnPrefixMessages,
  keptMessages,
  firstKeptEntryId: preparation.firstKeptEntryId,
  tokensBefore: preparation.tokensBefore,
  asker, // fake JevAsker in tests; omit to use TYPESAFE_API_KEY
});
if (outcome.ok) {
  return { compaction: outcome.compaction };
}
// else: let Pi compact

compact(messages, asker, options) matches upstream fast-jev-compaction. Tests should inject a JevAsker and not hit the network.

Development

npm install
npm test
npm run typecheck
npm run build

Unit tests use a fake JevAsker and do not call TypeSafe.

License

MIT. Jev core lives under src/jev/ and NOTICE (adapted from fast-jev-compaction).