wj-pi-auto-compact
Automatic context compaction extension for Pi
Package details
Install wj-pi-auto-compact from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:wj-pi-auto-compact- Package
wj-pi-auto-compact- Version
1.0.4- Published
- Aug 30, 2026
- Downloads
- 780/mo · 22/wk
- Author
- bxqyher
- License
- MIT
- Types
- extension
- Size
- 53.4 KB
- Dependencies
- 1 dependency · 1 peer
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
wj-pi-auto-compact
wj-pi-auto-compact 是一个面向 Pi 的上下文自动压缩扩展。当当前模型的上下文使用率达到指定百分比后,扩展会在合适的生命周期节点调用 Pi 公共扩展 API 触发压缩;如果逻辑任务仍在执行,压缩成功后会尝试继续该任务。
扩展可以独立运行,不依赖、导入或探测任何子代理扩展。其他有状态扩展可以按需接入通用协调协议,在压缩前后暂停并恢复自己的会话状态。
功能
- 按百分比触发:基于
ctx.getContextUsage().percent判断,默认阈值为90%。 - 区分任务状态:最终答复结束后只执行空闲压缩;工具任务尚未完成时,压缩成功后尝试继续同一逻辑任务。
- 避免重复压缩:识别 Pi 已经发起的
threshold或overflow原生压缩,不再重复调用ctx.compact()。 - 保守处理并发事件:外部手动压缩、来源不明确的压缩记录和
Already compacted错误不会被误判为本次压缩成功。 - 扩展间协调屏障:通过 Pi EventBus 提供
discover、prepare和complete三阶段协调协议。 - 严格配置校验:拒绝非法 UTF-8、非法 JSON、未知字段、错误类型和越界阈值。
- 运行时兼容门禁:Pi 版本不满足要求时不注册压缩处理器,并在宿主支持 extension UI 时显示一次警告。
- 适配多种运行模式:TUI、RPC、JSON 和 print 模式下均执行相同的压缩逻辑。
本扩展不会注册命令、工具、快捷键、widget 或设置界面。安装并启用后,正常使用 Pi 即可。
运行要求
| 项目 | 最低要求 |
|---|---|
| Node.js | 22.19.0 |
| Pi | >=0.84.1,包名为 @earendil-works/pi-coding-agent;已验证至 0.84.2 |
| Git | 从 Git 仓库安装时需要 |
扩展从 Pi 公开导出的 VERSION 获取实际版本,并使用严格的 SemVer 规则检查 >=0.84.1。该范围按 semver 默认规则排除预发布版本,例如 0.84.1-beta.1 不会通过检查。
Pi 扩展以当前用户权限运行,可以访问本机文件和进程。安装任何第三方扩展前都应先检查其源码。
安装
用户级安装
对当前用户的所有 Pi 项目启用:
pi install npm:wj-pi-auto-compact
Pi 会克隆仓库、安装生产依赖,并把包写入用户级设置。
项目级安装
只为当前项目启用:
pi install npm:wj-pi-auto-compact -l
项目级安装会写入当前项目的 .pi/settings.json。其他使用者信任该项目后,Pi 会自动安装缺失的包。
临时试用
只在本次 Pi 进程中加载,不修改持久设置:
pi -e npm:wj-pi-auto-compact
固定到标签或提交的包不会被 pi update --extensions 自动移动到其他版本。
管理安装
# 查看已安装的 Pi 包
pi list
# 更新本扩展
pi update --extension npm:wj-pi-auto-compact
# 删除用户级安装
pi remove npm:wj-pi-auto-compact
# 删除当前项目的安装
pi remove npm:wj-pi-auto-compact -l
使用方法
安装完成后启动 Pi,不需要执行额外命令:
pi
默认情况下,扩展会在某个 turn 结束且上下文使用率达到或超过 90% 时记录一次阈值命中,并根据任务状态选择处理方式:
| 场景 | 行为 |
|---|---|
| 助手已经给出最终答复 | 等待真实的 agent_settled,压缩成功后保持会话空闲,不创建新 turn |
| 助手刚完成工具调用,且 Pi 随后开始了真实的新 turn | 建立协调屏障并中断当前 run;Pi 静止后执行压缩,成功时尝试注入一次用户可见的 continuation |
工具调用后没有出现后继 turn_start |
按已结束任务处理,只压缩,不猜测任务需要继续 |
| 使用率低于阈值,或 Pi 无法提供百分比 | 不触发压缩,也不自行估算 token 百分比 |
TUI 或支持 extension UI 的 RPC 宿主会在开始自动压缩时显示一次信息通知,其中包含触发时的上下文使用率、配置阈值、已用 token、上下文窗口 token 和阈值对应的 token 数。示例:
Context usage is 95% (95,000 / 100,000 tokens). Auto-compaction threshold is 90% (90,000 tokens). Preparing to compact.
JSON、print 或其他 ctx.hasUI === false 的宿主不会增加替代文本输出。
配置
配置文件固定为:
<用户主目录>/.pi/agent/wj-pi-auto-compact.json
这是用户级配置,目前不支持项目级配置、环境变量或命令行覆盖。文件不存在时直接使用默认值,无需手动创建。
完整配置示例:
{
"enabled": true,
"maxContextPercent": 90,
"customInstructions": "请优先保留当前任务目标、已完成的修改、未解决的问题、关键文件路径和下一步计划。"
}
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled |
boolean |
true |
是否启用本扩展的自动触发逻辑 |
maxContextPercent |
number |
90 |
触发阈值,必须是有限数值,且 0 < value <= 100;允许小数 |
customInstructions |
string |
未配置 | 传给 Pi 原生压缩的补充指令;空字符串或全空白字符串不产生附加指令 |
三个字段都可以省略,省略时使用对应默认值。例如 {} 等价于不配置自定义指令的默认配置。
配置校验
配置必须满足以下条件:
- 文件内容是有效 UTF-8。
- 根值是 JSON 对象,不能是数组、字符串或
null。 - 只能包含
enabled、maxContextPercent和customInstructions。 - 每个字段的类型和值域必须正确。
customInstructions 会透传给 Pi 的 ctx.compact({ customInstructions }),作为摘要时的补充指令;Pi 仍然使用自己的默认摘要提示词,不会被本字段完全替换。该配置只影响本扩展触发的自动压缩,不影响 Pi 原生的 threshold/overflow 自动压缩。
配置文件存在但校验失败时,扩展会禁用当前扩展实例,而不是带着部分配置继续运行。宿主支持 extension UI 时会显示一次具体原因。修正配置后,在 Pi 中执行 /reload 或重新启动 Pi;配置只在扩展加载时读取,不会在每个 turn 中重复读取。
运行机制
一次典型事务的流程如下:
turn_end 检查使用率
-> 根据任务状态等待 agent_end 或后继 turn_start
-> discover / prepare 协调参与者
-> 等待 agent_settled
-> 复用 Pi 原生压缩,或调用 ctx.compact()
-> complete 协调参与者
-> 必要时发送用户可见的 continuation
空闲压缩
最终答复结束后达到阈值时,扩展会等待 Pi 的真实 agent_settled 再触发压缩。成功后不会发送 continuation,也不会创建额外的模型轮次。
工具任务续跑
扩展不会仅凭助手消息中存在 toolCall 就认定任务尚未结束。只有成功的工具 turn 后又观察到真实的 turn_start,才会建立协调屏障并调用 ctx.abort() 中断当前 run。
压缩和协调都成功后,扩展通过 pi.sendMessage() 发送一次对用户和模型均可见的 continuation:
[wj-pi-auto-compact/v1]
Auto-compaction completed. Continue the interrupted task from the compacted context.
该消息使用 display: true 和 triggerTurn: true,并通过 details.coordinationRequestId 关联本次协调事务。它继续的是同一逻辑任务,但 Pi 会创建一个新的物理 turn。
扩展会在 5 秒内等待该消息对应的真实 message_start。超时只表示“启动未确认”,不会证明消息没有入队,也不会反向发送错误补偿;迟到的 message_start 仍可完成本地匹配。只有 sendMessage() 同步抛错时,扩展才能确定 continuation 未提交。
与 Pi 原生压缩的关系
本扩展不会关闭或替换 Pi 自带的 threshold/overflow 自动压缩。两者的配置彼此独立:
maxContextPercent控制本扩展何时准备压缩。customInstructions只用于本扩展最终调用ctx.compact()的自动压缩请求;缺失或为空时使用 Pi 默认摘要指令。- Pi 的
reserveTokens、keepRecentTokens等设置仍控制 Pi 自身的压缩策略和摘要内容。 - 当前事务中观察到同一 branch 上明确的
threshold或overflowsession_compact后,本扩展认为原生压缩已经完成,不再调用ctx.compact()。 overflow事件带有willRetry: true时,Pi 已承诺原生重试,本扩展不会再发送 continuation。- Pi 已尝试原生压缩但失败或取消时,本扩展不会额外包一层重试。
- 用户或其他扩展触发的 manual compaction 不会被当成本事务的成功证据。
压缩摘要、进度指示、取消处理、重试次数和退避逻辑均复用 Pi 的原生实现。
协调协议
扩展通过 Pi EventBus 公开协议 wj-pi-auto-compact/coordination/v1,供其他有状态扩展在压缩前后建立屏障。独立运行时不需要任何参与者。
| 阶段 | 请求事件 | 响应事件 | 用途 |
|---|---|---|---|
| 发现 | .../discover |
.../discovered |
查找当前 session 中需要屏障的参与者 |
| 准备 | .../prepare |
.../prepared |
要求固定参与者暂停或保存状态 |
| 完成 | .../complete |
.../completed |
通知压缩结果并释放屏障 |
事件完整前缀为 wj-pi-auto-compact/coordination/v1/。协议只传递协议版本、请求 ID、不透明的参与者 ID、屏障标记、业务确认和压缩结果,不传递其他扩展的任务身份或运行时领域数据。
关键语义:
- 每个事务都会重新发现参与者,
session_start的预发现结果只用于预热。 - 发现窗口为 100 毫秒;prepare 和 complete 的业务确认期限分别为 12 秒。
- 只有
requiresBarrier: true的参与者会进入本次固定成员集合。 - EventBus 的底层投递成功不能代替
prepared或completed业务确认。 - prepare 被拒绝、超时或状态不确定时,会向全部目标发送幂等的
not_started以释放潜在屏障。 - complete 采用全体确认语义;任一固定参与者未确认时,不会发送 continuation,并向全体成员补发
not_started。 succeeded只表示压缩已经成功,不保证 continuation 已经交付或模型最终执行成功。
协议类型、解析规则和常量见 src/coordination-protocol.ts,客户端事务实现见 src/coordination-client.ts。
许可证
本项目使用 MIT License,Copyright (c) 2026 WJ。
已知限制
这些限制来自 Pi 当前公开扩展 API,扩展只能保守处理,无法完全消除:
- manual
session_before_compact和session_compact没有请求 ID。本扩展只能结合当前 branch、非 manual 原因和本次ctx.compact()的专属回调判断归属。 ctx.compact()没有公开取消句柄或 Promise。正常 session 中,本扩展会持续等待本次调用的onComplete或onError;session shutdown/reload 只能停止本地等待并释放协调事务,不能保证底层摘要工作已经停止。pi.sendMessage()的公开返回类型是void,没有投递回调或撤销 API。匹配的message_start只能证明 Pi 已经开始处理,不能保证后续 provider 请求或模型 turn 最终成功。