@henryqw/pi-auto-compact 0.2.0 → 0.2.2
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.md +2 -2
- package/extensions/auto-compact.ts +13 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,10 +41,10 @@ Threshold must be at least 25% and below 100%; lower values are not meaningful.
|
|
|
41
41
|
## Behavior
|
|
42
42
|
|
|
43
43
|
- Refuses activation with an error when Pi's effective `compaction.enabled` setting is not `false`; competing automatic compactors can start duplicate summaries.
|
|
44
|
-
- Checks `turn_start`, tool-call `turn_end`, `context`, and resumed/forked `session_start`.
|
|
44
|
+
- Checks `turn_start`, tool-call `turn_end`, `agent_end`, `context`, and resumed/forked `session_start`.
|
|
45
45
|
- Uses Pi's default `ctx.compact()` summary and session persistence.
|
|
46
46
|
- Keeps newest 15% as temporary emergency context while compaction runs.
|
|
47
|
-
- Sends a follow-up message after compaction so task execution continues.
|
|
47
|
+
- Sends a follow-up message after mid-task compaction so task execution continues; final-answer compaction stays idle.
|
|
48
48
|
- Compacts above configured `autoCompactThreshold` percentage (50% by default).
|
|
49
49
|
|
|
50
50
|
`ctx.compact()` aborts current low-level run. Extension hides that empty internal abort message, then starts new run with current task resume message. Other aborts and provider errors remain visible.
|
|
@@ -13,13 +13,14 @@ import type {
|
|
|
13
13
|
type AgentMessage = Parameters<typeof estimateTokens>[0];
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Proactive compaction runs at
|
|
16
|
+
* Proactive compaction runs at four points:
|
|
17
17
|
* - turn_start: catch sessions already over threshold before next request.
|
|
18
18
|
* - turn_end: catch growth caused by tool results before next LLM turn.
|
|
19
|
+
* - agent_end: catch growth from the final provider turn.
|
|
19
20
|
* - context: last-resort guard with a temporary keep-recent context.
|
|
20
21
|
*
|
|
21
|
-
* Pi's ctx.compact() aborts active low-level run internally.
|
|
22
|
-
*
|
|
22
|
+
* Pi's ctx.compact() aborts active low-level run internally. Mid-task
|
|
23
|
+
* compaction sends a follow-up user message to resume work after summary.
|
|
23
24
|
*/
|
|
24
25
|
const DEFAULT_COMPACT_THRESHOLD_PERCENT = 50;
|
|
25
26
|
const MIN_COMPACT_THRESHOLD_PERCENT = 25;
|
|
@@ -119,16 +120,17 @@ function hasToolCall(message: AgentMessage): boolean {
|
|
|
119
120
|
export default function (pi: ExtensionAPI) {
|
|
120
121
|
let active = false;
|
|
121
122
|
let autoCompactThreshold = DEFAULT_COMPACT_THRESHOLD_PERCENT;
|
|
122
|
-
// Prevent
|
|
123
|
+
// Prevent lifecycle hooks from starting duplicate summaries.
|
|
123
124
|
let compactionPending = false;
|
|
124
125
|
let compactionAbortExpected = false;
|
|
125
126
|
|
|
126
|
-
const runCompaction = (ctx: ExtensionContext) => {
|
|
127
|
+
const runCompaction = (ctx: ExtensionContext, resumeTask = true) => {
|
|
127
128
|
compactionAbortExpected = Boolean(ctx.signal && !ctx.signal.aborted);
|
|
128
129
|
ctx.compact({
|
|
129
130
|
onComplete: () => {
|
|
130
131
|
compactionPending = false;
|
|
131
132
|
compactionAbortExpected = false;
|
|
133
|
+
if (!resumeTask) return;
|
|
132
134
|
// Pi may flush queued input during compaction_end. Wait one macrotask
|
|
133
135
|
// before checking idle, otherwise follow-up can race that flush.
|
|
134
136
|
setImmediate(() => {
|
|
@@ -142,14 +144,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
142
144
|
});
|
|
143
145
|
};
|
|
144
146
|
|
|
145
|
-
const compactIfNeeded = (ctx: ExtensionContext) => {
|
|
147
|
+
const compactIfNeeded = (ctx: ExtensionContext, resumeTask = true) => {
|
|
146
148
|
if (!active || compactionPending) return;
|
|
147
149
|
|
|
148
150
|
const usage = ctx.getContextUsage();
|
|
149
151
|
if (usage?.percent == null || usage.percent <= autoCompactThreshold) return;
|
|
150
152
|
|
|
151
153
|
compactionPending = true;
|
|
152
|
-
runCompaction(ctx);
|
|
154
|
+
runCompaction(ctx, resumeTask);
|
|
153
155
|
};
|
|
154
156
|
|
|
155
157
|
// Hide only empty abort produced when ctx.compact() cancels active run.
|
|
@@ -176,12 +178,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
176
178
|
// Pre-turn catches resumed/queued work before provider request starts.
|
|
177
179
|
pi.on("turn_start", (_event, ctx) => compactIfNeeded(ctx));
|
|
178
180
|
|
|
179
|
-
// Only tool-call turns need mid-run compaction.
|
|
180
|
-
// receive an unsolicited continuation message.
|
|
181
|
+
// Only tool-call turns need mid-run compaction.
|
|
181
182
|
pi.on("turn_end", (event, ctx) => {
|
|
182
183
|
if (hasToolCall(event.message)) compactIfNeeded(ctx);
|
|
183
184
|
});
|
|
184
185
|
|
|
186
|
+
// Catch threshold crossings caused by the final provider turn.
|
|
187
|
+
pi.on("agent_end", (_event, ctx) => compactIfNeeded(ctx, false));
|
|
188
|
+
|
|
185
189
|
// Runs before every provider request. Temporary truncation protects request
|
|
186
190
|
// size while asynchronous default compaction summarizes persisted history.
|
|
187
191
|
pi.on("context", (event, ctx) => {
|