@lienat/pi-jev-compaction 0.1.0 → 0.1.1
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.
- package/README.en.md +54 -37
- package/README.md +22 -10
- package/package.json +2 -2
- package/src/adapter.ts +26 -14
package/README.en.md
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# pi-jev-compaction
|
|
2
2
|
|
|
3
3
|
A [Pi](https://github.com/badlogic/pi-mono) extension for context compaction.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
It uses `fast-jev-compaction@0.4.0` for Jev's tool-call decisions and adapts
|
|
5
|
+
those decisions to Pi's native message and compaction lifecycle.
|
|
6
|
+
|
|
7
|
+
The `0.4.0` dependency is the
|
|
8
|
+
[`aleksvega/fast-jev-compaction`](https://github.com/aleksvega/fast-jev-compaction)
|
|
9
|
+
fork based on
|
|
10
|
+
[`tamaratran/fast-jev-compaction`](https://github.com/tamaratran/fast-jev-compaction).
|
|
11
|
+
This project is a **Pi adapter**, not a replacement for Pi's compaction system:
|
|
12
|
+
Jev decides which eligible tool calls and results to keep, drop, or shorten;
|
|
13
|
+
Pi still creates the summary, compaction entry, file-operation details, and
|
|
14
|
+
retained recent context.
|
|
12
15
|
|
|
13
16
|
## Demo
|
|
14
17
|
|
|
@@ -43,17 +46,17 @@ Jev reviews eligible tool call/result pairs
|
|
|
43
46
|
```
|
|
44
47
|
|
|
45
48
|
Rather than serializing Jev's simplified transcript back into Pi, the adapter
|
|
46
|
-
maps Jev's decisions onto the original Pi messages.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
maps Jev's decisions onto the original Pi messages. Pi's thinking blocks,
|
|
50
|
+
images, tool-call metadata, and other native message data therefore remain
|
|
51
|
+
native in the final preparation.
|
|
49
52
|
|
|
50
53
|
The adapter only modifies:
|
|
51
54
|
|
|
52
55
|
- `messagesToSummarize`
|
|
53
56
|
- `turnPrefixMessages`
|
|
54
57
|
|
|
55
|
-
All other compaction metadata remains
|
|
56
|
-
|
|
58
|
+
All other compaction metadata remains owned by Pi and is never touched by this
|
|
59
|
+
extension, including:
|
|
57
60
|
|
|
58
61
|
- `firstKeptEntryId`
|
|
59
62
|
- `tokensBefore`
|
|
@@ -62,23 +65,42 @@ by this extension, including:
|
|
|
62
65
|
- `settings`
|
|
63
66
|
- `isSplitTurn`
|
|
64
67
|
|
|
68
|
+
Pi computes some of this metadata before the hook runs. Consequently, if Jev
|
|
69
|
+
removes an old `write` or `edit` call, `fileOps` may still describe that call;
|
|
70
|
+
the extension does not recalculate Pi's native metadata.
|
|
71
|
+
|
|
65
72
|
### What can be filtered
|
|
66
73
|
|
|
67
74
|
Only paired, text-only tool calls and tool results within the same native
|
|
68
|
-
compaction input are eligible.
|
|
75
|
+
compaction input are eligible. `messagesToSummarize` and
|
|
76
|
+
`turnPrefixMessages` are processed independently; they are never combined for
|
|
77
|
+
Jev decisions. Pi's separately retained recent region and messages outside
|
|
78
|
+
these two arrays are not sent to Jev.
|
|
79
|
+
|
|
80
|
+
The adapter leaves the following native messages or content untouched:
|
|
69
81
|
|
|
70
82
|
- user and assistant prose;
|
|
71
|
-
- thinking blocks and image content;
|
|
83
|
+
- thinking blocks and image content in the original Pi messages;
|
|
72
84
|
- image-bearing tool results;
|
|
73
85
|
- incomplete or duplicate call/result pairs;
|
|
74
86
|
- pairs crossing the two native input boundaries;
|
|
75
87
|
- Pi's separately retained recent region;
|
|
76
88
|
- tool results without a valid matching call.
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
Ineligible tool results—unpaired results, duplicate IDs, image-bearing results,
|
|
91
|
+
or pairs crossing the two compaction inputs—are not converted into ordinary
|
|
92
|
+
user messages, and their text is excluded from Jev's temporary decision state.
|
|
93
|
+
The original Pi messages remain preserved.
|
|
94
|
+
|
|
95
|
+
A `drop_call` decision removes the call and its paired result. A `drop_result`
|
|
96
|
+
decision keeps the call. With the default `truncateHeadChars` of 300, a result
|
|
97
|
+
is shortened only when it is longer than 420 characters; shorter results stay
|
|
98
|
+
unchanged. Longer results keep their first 300 characters and receive a note.
|
|
99
|
+
Pi then summarizes the filtered native messages normally.
|
|
100
|
+
|
|
101
|
+
The `reviewed` count in notifications includes only tool calls actually queried
|
|
102
|
+
through Jev. It excludes calls kept by upstream protection rules (pinned) and
|
|
103
|
+
is not a count of questions or request batches.
|
|
82
104
|
|
|
83
105
|
## Compatibility
|
|
84
106
|
|
|
@@ -86,12 +108,11 @@ normally.
|
|
|
86
108
|
- Node.js `>=24`
|
|
87
109
|
- `fast-jev-compaction` `0.4.0`
|
|
88
110
|
|
|
89
|
-
The extension has a strict Pi `0.85.1` version guard because the adapter
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
compaction.
|
|
111
|
+
The extension has a strict Pi `0.85.1` version guard because the adapter relies
|
|
112
|
+
on the mutable `session_before_compact` preparation object used by that release.
|
|
113
|
+
This is not a formally documented extension API for replacing native
|
|
114
|
+
preparation arrays. On any other Pi version the extension leaves the
|
|
115
|
+
preparation untouched and Pi falls back to ordinary native compaction.
|
|
95
116
|
|
|
96
117
|
This package does not modify Pi's source code or call Pi's exported
|
|
97
118
|
`compact()` function itself.
|
|
@@ -147,8 +168,8 @@ use this extension if you are comfortable sending that information to TypeSafe.
|
|
|
147
168
|
|
|
148
169
|
### Timeout
|
|
149
170
|
|
|
150
|
-
`PI_FAST_JEV_TIMEOUT_MS` controls the total time allowed for
|
|
151
|
-
|
|
171
|
+
`PI_FAST_JEV_TIMEOUT_MS` controls the total time allowed for one Jev attempt,
|
|
172
|
+
including both native preparation arrays. It defaults to 15 seconds:
|
|
152
173
|
|
|
153
174
|
```sh
|
|
154
175
|
export PI_FAST_JEV_TIMEOUT_MS=15000
|
|
@@ -177,11 +198,6 @@ npm run typecheck
|
|
|
177
198
|
npm test
|
|
178
199
|
```
|
|
179
200
|
|
|
180
|
-
Tests use injected Jev askers and timers and make no calls to TypeSafe or any
|
|
181
|
-
main model. Coverage includes message mapping, tool-call/result pairing, image
|
|
182
|
-
and thinking preservation, split compaction inputs, timeout and cancellation,
|
|
183
|
-
native fallback, and Pi hook behavior.
|
|
184
|
-
|
|
185
201
|
Build the package:
|
|
186
202
|
|
|
187
203
|
```sh
|
|
@@ -196,11 +212,12 @@ npm pack --ignore-scripts
|
|
|
196
212
|
|
|
197
213
|
## Acknowledgements and attribution
|
|
198
214
|
|
|
199
|
-
This adapter
|
|
200
|
-
[`fast-jev-compaction`](https://github.com/
|
|
201
|
-
[
|
|
202
|
-
|
|
203
|
-
adapter integrates with native Pi
|
|
215
|
+
This adapter uses `fast-jev-compaction@0.4.0`, the
|
|
216
|
+
[`aleksvega/fast-jev-compaction`](https://github.com/aleksvega/fast-jev-compaction)
|
|
217
|
+
fork based on [`fast-jev-compaction`](https://github.com/tamaratran/fast-jev-compaction)
|
|
218
|
+
by [Tamara Tran](https://github.com/tamaratran). The upstream project provides
|
|
219
|
+
the Jev decision logic that this Pi adapter integrates with native Pi
|
|
220
|
+
compaction.
|
|
204
221
|
|
|
205
222
|
If you believe this repository contains material that infringes your rights,
|
|
206
223
|
or if the attribution needs to be corrected, please open an issue at
|
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# pi-jev-compaction
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
English version: [README.en.md](README.en.md)
|
|
5
4
|
|
|
6
|
-
一个用于上下文压缩之前 [Pi](https://github.com/badlogic/pi-mono)
|
|
5
|
+
一个用于上下文压缩之前 [Pi](https://github.com/badlogic/pi-mono) 的扩展,核心判断逻辑复用了来源于[`fast-jev-compaction`](https://github.com/tamaratran/fast-jev-compaction)原作者的原生 claude code 的插件,针对 pi 的情况进行了适配。它会在 Pi 执行原生上下文压缩前,筛选不再需要的工具调用和工具结果,最终的压缩逻辑还是交给 Pi 原生的 `/compact()` 管理。
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
里面的决策策略由 Jev 模型负责判断哪些工具调用应保留、删除或截短,本插件不修改 Pi 源码,也不会自行调用 Pi 导出的 `compact()` 函数。
|
|
9
8
|
|
|
10
9
|
## 视频演示
|
|
11
10
|
|
|
@@ -13,6 +12,7 @@ English version: [README.en.md](README.en.md)
|
|
|
13
12
|
|
|
14
13
|
视频来源:[Tamara Tran 在 X 发布的视频](https://x.com/tamarajtran/status/2100694549362553153)。GIF 仅作为项目演示素材保留,版权归原作者所有。
|
|
15
14
|
|
|
15
|
+
|
|
16
16
|
## 工作方式
|
|
17
17
|
|
|
18
18
|
手动执行 `/compact` 或 Pi 自动触发压缩时,流程如下:
|
|
@@ -23,14 +23,21 @@ Pi 准备压缩
|
|
|
23
23
|
session_before_compact
|
|
24
24
|
↓
|
|
25
25
|
Jev 检查符合条件的工具调用/结果对
|
|
26
|
+
│
|
|
26
27
|
├─ 成功:只替换 Pi 原生的待摘要消息数组
|
|
27
28
|
│ ↓
|
|
28
29
|
│ Pi 原生 compact()
|
|
30
|
+
│
|
|
29
31
|
└─ 超时、报错或响应无效:保持原始数组不变
|
|
30
32
|
↓
|
|
31
33
|
Pi 原生 compact()
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
|
|
37
|
+
## 数据管理
|
|
38
|
+
|
|
39
|
+
Jev 并不会看到完整的 Pi 会话。它只处理 Pi 本次压缩提供的 `messagesToSummarize` 和 `turnPrefixMessages`,且这两组消息分别处理。
|
|
40
|
+
|
|
34
41
|
适配层不会把 Jev 的简化 transcript 重新拼回 Pi,而是将 Jev 的决策映射回原始 Pi 消息。因此,Pi 的 thinking、图片、工具调用元数据和其他原生消息数据不会因为适配而被转换成普通文字。
|
|
35
42
|
|
|
36
43
|
适配层只会修改:
|
|
@@ -60,17 +67,22 @@ Jev 检查符合条件的工具调用/结果对
|
|
|
60
67
|
- Pi 单独保留的近期消息区域;
|
|
61
68
|
- 没有有效调用对应的工具结果。
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
不符合筛选条件的工具结果(未配对、重复 ID、包含图片,或配对跨越两组压缩输入)不会被转换成普通用户消息,其文本也不会进入 Jev 的临时决策状态;原始 Pi 消息仍然保留。
|
|
71
|
+
|
|
72
|
+
如果 Jev 返回 `drop_call`,扩展会删除调用及其对应结果;
|
|
73
|
+
如果返回 `drop_result`,则保留调用。如果 Jev 判断只需保留工具调用而不需要完整结果,扩展会沿用上游规则:默认情况下,只有结果超过 420 个字符时才会截短为前 300 个字符并追加说明;较短结果会保持原文。
|
|
74
|
+
|
|
75
|
+
处理完成后,Pi 仍会照常生成原生摘要。
|
|
76
|
+
|
|
77
|
+
通知中的 `reviewed` 只统计实际向 Jev 询问的工具调用,不包含被上游保护规则固定保留的调用(pinned),也不是问题数或请求批次数。
|
|
64
78
|
|
|
65
79
|
## 兼容性
|
|
66
80
|
|
|
67
81
|
- Pi `0.85.1`
|
|
68
82
|
- Node.js `>=24`
|
|
69
|
-
- `fast-jev-compaction` `0.4.0`
|
|
70
83
|
|
|
71
|
-
扩展对 Pi 版本进行严格检查,因为当前适配依赖 Pi `0.85.1` 的 `session_before_compact` preparation
|
|
84
|
+
扩展对 Pi 版本进行严格检查,因为当前适配依赖 Pi `0.85.1` 的 `session_before_compact` preparation 对象可变行为;并没有替换原生压缩输入的扩展接口。所以使用其他 Pi 版本时,扩展不会修改压缩输入,Pi 会安全地回退到原生压缩。
|
|
72
85
|
|
|
73
|
-
本项目不修改 Pi 源码,也不会自行调用 Pi 导出的 `compact()` 函数。
|
|
74
86
|
|
|
75
87
|
## 安装
|
|
76
88
|
|
|
@@ -124,7 +136,7 @@ API Key 只在运行时读取,并只用于认证 Jev 请求;不会写入本
|
|
|
124
136
|
export PI_FAST_JEV_TIMEOUT_MS=15000
|
|
125
137
|
```
|
|
126
138
|
|
|
127
|
-
如果 API Key 缺失、Pi 版本不支持、Jev 超时、请求失败或响应无效,扩展会显示简短提示并保持原始压缩输入不变,然后由 Pi
|
|
139
|
+
如果 API Key 缺失、Pi 版本不支持、Jev 超时、请求失败或响应无效,扩展会显示简短提示并保持原始压缩输入不变,然后由 Pi 执行普通原生压缩。
|
|
128
140
|
|
|
129
141
|
用户主动取消压缩时,取消信号会传递给 Jev,扩展不会替换或修改原生压缩输入。
|
|
130
142
|
|
|
@@ -143,8 +155,6 @@ npm run typecheck
|
|
|
143
155
|
npm test
|
|
144
156
|
```
|
|
145
157
|
|
|
146
|
-
测试使用注入的 Jev asker 和计时器,不会访问 TypeSafe,也不会调用主模型。测试覆盖消息映射、工具调用/结果配对、图片和 thinking 保留、两组压缩输入、超时、取消、原生回退和 Pi hook 行为。
|
|
147
|
-
|
|
148
158
|
构建:
|
|
149
159
|
|
|
150
160
|
```sh
|
|
@@ -165,6 +175,8 @@ npm pack --ignore-scripts
|
|
|
165
175
|
如果你认为本仓库包含侵犯你权利的内容,或署名信息需要修正,请在
|
|
166
176
|
[GitHub Issues](https://github.com/Jul1en-Lin/pi-jev-compaction/issues) 联系维护者。我们会审核请求,并在适当情况下删除或修订相关内容。
|
|
167
177
|
|
|
178
|
+
欢迎大家使用并指出指导性意见,感谢!
|
|
179
|
+
|
|
168
180
|
## 许可证
|
|
169
181
|
|
|
170
182
|
本适配层使用 MIT License。使用时也请查看上游
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lienat/pi-jev-compaction",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Pi extension that uses TypeSafe Jev to prune eligible historical tool calls before native compaction, preserving native messages and falling back safely on failure.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
package/src/adapter.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compact,
|
|
3
|
+
resolveOptions,
|
|
3
4
|
buildJevRequest,
|
|
4
5
|
parseJevResponse,
|
|
5
6
|
type CallDecision,
|
|
@@ -217,17 +218,23 @@ function toJevMessages(messages: readonly AgentMessage[], pairs: readonly Pair[]
|
|
|
217
218
|
};
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
if (message.role === "toolResult"
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
221
|
+
if (message.role === "toolResult") {
|
|
222
|
+
if (eligible.has(message.toolCallId)) {
|
|
223
|
+
return {
|
|
224
|
+
role: "user",
|
|
225
|
+
text: "",
|
|
226
|
+
toolUses: [],
|
|
227
|
+
toolResults: [{
|
|
228
|
+
tool_use_id: message.toolCallId,
|
|
229
|
+
text: contentText(message.content),
|
|
230
|
+
isError: message.isError,
|
|
231
|
+
}],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Unpaired or ineligible results must not become user text or goals in
|
|
236
|
+
// Jev's state; the original Pi message is preserved on output.
|
|
237
|
+
return { role: "user", text: "", toolUses: [] };
|
|
231
238
|
}
|
|
232
239
|
|
|
233
240
|
return { role: "user", text: messageText(message), toolUses: [] };
|
|
@@ -345,13 +352,18 @@ export async function filterMessages(
|
|
|
345
352
|
return { messages: [...messages], changed: false, candidateCalls: 0, droppedCalls: 0, truncatedResults: 0 };
|
|
346
353
|
}
|
|
347
354
|
|
|
348
|
-
const compactOptions = options.compactOptions ?? {};
|
|
355
|
+
const compactOptions = resolveOptions(options.compactOptions ?? {});
|
|
349
356
|
const result = await rejectOnAbort(
|
|
350
357
|
compact(toJevMessages(messages, pairs), options.asker, compactOptions),
|
|
351
358
|
options.signal,
|
|
352
359
|
);
|
|
353
|
-
const
|
|
354
|
-
return applyActions(
|
|
360
|
+
const reviewedCalls = result.decisions.filter((decision) => decision.reason !== "pinned").length;
|
|
361
|
+
return applyActions(
|
|
362
|
+
messages,
|
|
363
|
+
decisionActions(result.decisions, pairs),
|
|
364
|
+
compactOptions.truncateHeadChars,
|
|
365
|
+
reviewedCalls,
|
|
366
|
+
);
|
|
355
367
|
}
|
|
356
368
|
|
|
357
369
|
/** Filter Pi's two native summary inputs independently; their boundaries stay intact. */
|