# pi-midrun-compact

[![npm version](https://img.shields.io/npm/v/pi-midrun-compact.svg?color=60a5fa)](https://www.npmjs.com/package/pi-midrun-compact)
[![Pi package](https://img.shields.io/badge/Pi-package-fbbf24)](https://pi.dev/packages/pi-midrun-compact)
[![Pi compatibility](https://img.shields.io/badge/Pi-%3E%3D%200.80.0-8b5cf6)](https://github.com/earendil-works/pi)
[![License](https://img.shields.io/badge/license-MIT-22c55e)](https://github.com/leonfox28/pi-midrun-compact/blob/main/LICENSE)

**Safe mid-run compaction for long Pi tool loops.** Trigger Pi's official compaction pipeline between complete tool batches, then continue the interrupted task after compaction succeeds.

Long coding tasks can stay inside one user turn for many model → tools → model cycles. Large tool results may push the next model request close to the context limit before Pi's normal end-of-run compaction check gets a chance to run. `pi-midrun-compact` closes that gap.

> [!IMPORTANT]
> This extension coordinates **when to compact** and **when to resume**. It is not a compaction backend: it does not generate summaries, call provider compaction endpoints, or rewrite provider payloads.

## Highlights

- **Zero-config default** — starts checking at 75% context usage.
- **Safe tool boundaries** — triggers only after every result in the current tool batch is present.
- **Parallel-tool aware** — matches tool calls and results by exact ID, independent of completion order.
- **Pi-native delegation** — calls `ctx.compact()` and leaves compaction ownership to Pi and installed backend extensions.
- **Idle-aware continuation** — after successful compaction, waits for Pi to flush queued input and resumes only if the session is still idle.
- **Fail-safe behavior** — malformed configuration, unknown usage, stale callbacks, and repeated failures never cause blind compaction loops.
- **No runtime dependencies** — uses only Pi's extension API and Node.js built-ins.

## Install

Install from npm:

```bash
pi install npm:pi-midrun-compact
```

Try it for one run without installing:

```bash
pi -e npm:pi-midrun-compact
```

No configuration is required. Start Pi and inspect the active settings with:

```text
/midrun-compact status
```

Update or remove the package later with:

```bash
pi update npm:pi-midrun-compact
pi remove npm:pi-midrun-compact
```

## How it works

```text
assistant requests one or more tools
                 │
                 ▼
all matching tool results are complete
                 │
                 ▼
context hook before the next model request
                 │
       ┌─────────┴─────────┐
       │                   │
 usage below threshold   usage at/above threshold
       │                   │
       ▼                   ▼
 continue normally      ctx.compact()
                           │
                 ┌─────────┴─────────┐
                 │                   │
              success             failure
                 │                   │
                 ▼                   ▼
       wait for queued input    stop safely;
                 │              do not resume
        ┌────────┴────────┐
        │                 │
 session still idle   turn already active
        │                 │
        ▼                 ▼
 send continuation   send nothing extra
```

Automatic compaction is considered only when all of the following are true:

1. Pi has an active model and usable context-usage data.
2. The outgoing context ends with a complete assistant/tool-result batch.
3. Tool-call IDs and tool-result IDs are valid, unique, and match exactly.
4. Context usage is at or above `thresholdPercent`.
5. No compaction or continuation dispatch is already in progress.
6. The same approximate context state has not already produced a compaction failure.

This boundary prevents compaction while tools are still running or while a parallel batch is only partially complete.

## Responsibilities

| `pi-midrun-compact` owns | Pi or the compaction backend owns |
| --- | --- |
| Threshold timing | What history is kept or discarded |
| Complete-tool-batch validation | Summary generation |
| Starting `ctx.compact()` | Native provider compaction calls |
| Success/failure coordination | Compaction persistence and replay |
| Follow-up continuation | Backend-specific result details |

The extension deliberately does not register `session_before_compact` or `before_provider_request`, so it does not compete for compaction ownership.

## Compaction backend compatibility

| Setup | Compaction behavior |
| --- | --- |
| Pi only | Pi uses its built-in model-summary compaction. |
| Pi + [`@lll9p/pi-better-compaction`](https://github.com/lll9p/pi-better-compaction) | The request still goes through Pi's standard pipeline, allowing that extension to use native `/responses/compact` where supported or its configured fallback. |
| Pi + another compaction extension | That extension can participate through Pi's normal compaction hooks; `pi-midrun-compact` treats the result as opaque. |

A common pairing is:

```bash
pi install npm:pi-midrun-compact
pi install npm:@lll9p/pi-better-compaction
```

Loading order between these two packages does not determine compaction ownership.

## Configuration

The defaults work without a config file. To customize them, create either or both of:

- Global: `~/.pi/agent/extensions/pi-midrun-compact/config.json`
- Project: `<project>/.pi/extensions/pi-midrun-compact/config.json`

Project settings override global settings and are read only after the project is trusted. Run `/reload` or start a new Pi session after editing configuration.

Example:

```json
{
  "thresholdPercent": 70,
  "notify": true
}
```

### Options

| Option | Type | Default | Behavior |
| --- | --- | --- | --- |
| `enabled` | boolean | `true` | Enables automatic threshold triggering. Explicit commands remain available when false. |
| `thresholdPercent` | number | `75` | Triggers at or above this percentage. Must be finite and strictly between `0` and `100`. |
| `autoResume` | boolean | `true` | After successful compaction, resumes only if Pi remains idle after queued input is flushed. When false, compaction completes without starting another run. |
| `notify` | boolean | `true` | Shows informational notifications and footer status. Errors and command output remain visible when UI is available. |
| `customCompactionInstructions` | string | continuity-focused instructions | Passed to whichever backend owns the Pi compaction operation. An empty string passes no custom instruction. |

Default compaction instructions:

```text
Preserve the active user task, completed work, decisions, changed files, failures, pending tool-loop state, and exact next steps so execution can resume immediately after compaction.
```

Configuration is fail-safe:

- missing files use defaults;
- unknown keys are ignored with a warning;
- unreadable files, invalid JSON, or invalid known fields disable automatic triggering;
- a malformed project override cannot silently replace an invalid global safety configuration;
- explicit commands remain available for inspection and manual recovery.

## Commands

| Command | Description |
| --- | --- |
| `/midrun-compact` | Show status. |
| `/midrun-compact status` | Show runtime phase, effective settings, config paths, last trigger, and any failure guard. |
| `/midrun-compact now [instructions]` | Compact immediately, even below the configured threshold. |
| `/midrun-compact retry [instructions]` | Clear the recorded failure guard and retry after a compaction failure. |

Additional command instructions are appended to `customCompactionInstructions` for that operation only:

```text
/midrun-compact now Preserve the benchmark results and the unresolved regression in src/cache.ts.
```

## Failure and recovery

Compaction errors fail closed:

- the interrupted run is not resumed;
- no automatic retry is scheduled;
- another automatic attempt at nearly the same session/context size is blocked instead of looping;
- the error remains visible even when `notify` is false.

Inspect the state, fix the active compaction backend or provider, and retry explicitly:

```text
/midrun-compact status
/midrun-compact retry
```

Pending callbacks are tied to the session and runtime generation. Switching sessions, reloading, or shutting down invalidates stale continuation work.

## Continuation behavior

With `autoResume: true`, successful compaction waits until the next event-loop turn before deciding whether to resume. This gives Pi time to flush anything the user typed during compaction, as well as retries or continuation work started by another extension.

- If `ctx.isIdle()` is still `true`, the extension sends this protocol-marked user message and starts the continuation immediately:

  ```text
  [pi-midrun-compact/v1]
  Auto-compaction completed. Continue the interrupted task.
  ```

- If a turn or queued message is already active, the extension sends nothing. Existing input becomes the continuation, avoiding a duplicate synthetic user turn.

Operationally, this is:

```text
abort the old internal run → compact through Pi → wait for queued input → resume only if still idle
```

It is not an in-place continuation of the same internal agent run. Pi currently classifies extension calls through `ctx.compact()` as compaction reason `"manual"`, including automatic threshold triggers from this package.

## Privacy and scope

`pi-midrun-compact` makes no direct network requests. It checks context usage and message structure, then delegates compaction to Pi. Any summary generation, provider request, native compact endpoint, or persisted compaction data is controlled by Pi and the selected backend.

The extension does not prune, truncate, summarize, or otherwise rewrite tool output.

## Limitations

- One very large tool result can still jump past the usable limit before the next safe boundary. Tools should continue to truncate, paginate, or persist oversized output.
- The threshold is an early-warning policy, not a guarantee that every backend can compact a context of that size.
- A backend cannot necessarily recover once the context already exceeds its own input limit.
- Immediately after compaction, Pi may report context usage as unknown until a successful assistant response provides fresh usage. The extension intentionally skips that interval.
- If the active compaction backend is incompatible with a provider or proxy, this extension reports the failure rather than pretending recovery succeeded.

## Development

The target Pi runtime loads TypeScript extensions directly. For local development:

```bash
npm ci
npm run check
```

Useful test commands:

```bash
npm run test:unit
npm run test:smoke
```

Try a checkout in isolation:

```bash
pi --no-extensions -e /path/to/pi-midrun-compact
```

The test suite covers serial and parallel tool batches, threshold and configuration safety, single-flight and stale-session behavior, failure recovery, Pi RPC loading, built-in compaction, and coexistence with `pi-better-compaction` in either load order.

## License

MIT
