pi-goosedump 0.12.18 → 0.12.19
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 +13 -11
- package/dist/index.ts +70 -69
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -93,17 +93,19 @@ Optional settings live under `goosedump` in:
|
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
`turnsBeforeCompact` is an integer from 0 to 255. `0` disables scheduled
|
|
96
|
-
compaction. Each
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
the
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
compaction. Each completed model response counts as one turn, including responses
|
|
97
|
+
that call tools. The countdown is restored when a session resumes and appears in
|
|
98
|
+
the footer with a status dot (green when >25% turns remain, yellow when ≤25%, red
|
|
99
|
+
when ≤12.5%) followed by a hexadecimal countdown. `● GD:0A` means ten turns
|
|
100
|
+
remain, `● GD:00` is ready to compact, and `● GD:--` is disabled. The footer
|
|
101
|
+
adds `queued` while compaction is waiting to start and `compacting` while the
|
|
102
|
+
summary is being built. When the counter hits zero mid tool-loop, compaction
|
|
103
|
+
starts immediately after the current tool batch is persisted and the task is
|
|
104
|
+
resumed automatically. When the counter hits zero on a terminal turn, compaction
|
|
105
|
+
starts after the agent has settled. Pi remains the sole scheduler for its normal
|
|
106
|
+
context threshold. Whichever limit is reached first compacts once, and every
|
|
107
|
+
successful compaction resets the countdown. A failed or cancelled compaction
|
|
108
|
+
leaves the counter armed at zero and retries on the next tool turn or settlement.
|
|
107
109
|
|
|
108
110
|
`summaryMaxTokens` is an integer from 512 to 65536 (default 4096). The effective
|
|
109
111
|
summary budget is the lower of this value and 80% of Pi's `compaction.reserveTokens`,
|
package/dist/index.ts
CHANGED
|
@@ -590,26 +590,11 @@ function currentSessionTarget(ctx) {
|
|
|
590
590
|
function isCompactionEntry(entry) {
|
|
591
591
|
return entry.type === "compaction";
|
|
592
592
|
}
|
|
593
|
-
var COMPLETED_AGENT_RUN_ENTRY = "goosedump-completed-agent-run";
|
|
594
593
|
function isMessageEntry(entry) {
|
|
595
594
|
return entry.type === "message";
|
|
596
595
|
}
|
|
597
|
-
function
|
|
598
|
-
|
|
599
|
-
return false;
|
|
600
|
-
if (message.stopReason !== "stop" && message.stopReason !== "length")
|
|
601
|
-
return false;
|
|
602
|
-
return !(Array.isArray(message.content) && message.content.some((part) => isRecord(part) && part.type === "toolCall"));
|
|
603
|
-
}
|
|
604
|
-
function completedAgentRunData(entry) {
|
|
605
|
-
if (entry.type !== "custom" || entry.customType !== COMPLETED_AGENT_RUN_ENTRY)
|
|
606
|
-
return;
|
|
607
|
-
if (!isRecord(entry.data) || entry.data.version !== 1)
|
|
608
|
-
return;
|
|
609
|
-
const startedAfterEntryId = entry.data.startedAfterEntryId;
|
|
610
|
-
if (startedAfterEntryId !== null && typeof startedAfterEntryId !== "string")
|
|
611
|
-
return;
|
|
612
|
-
return { version: 1, startedAfterEntryId };
|
|
596
|
+
function isCompletedAssistant(message) {
|
|
597
|
+
return message.role === "assistant" && message.stopReason !== "error" && message.stopReason !== "aborted";
|
|
613
598
|
}
|
|
614
599
|
var SUMMARIZABLE_ENTRY_TYPES = new Set(["message", "custom_message", "branch_summary"]);
|
|
615
600
|
function piKeepRecentTokens(cwd, includeProject) {
|
|
@@ -681,7 +666,7 @@ function activeHistoryStartIndex(branchEntries) {
|
|
|
681
666
|
const compaction = latestCompaction(branchEntries);
|
|
682
667
|
return compaction ? compactionBoundaryStartIndex(branchEntries, compaction) : 0;
|
|
683
668
|
}
|
|
684
|
-
function
|
|
669
|
+
function completedTurnsSinceCompaction(branchEntries) {
|
|
685
670
|
let start = 0;
|
|
686
671
|
for (let i = branchEntries.length - 1;i >= 0; i -= 1) {
|
|
687
672
|
if (isCompactionEntry(branchEntries[i])) {
|
|
@@ -689,27 +674,10 @@ function completedRunsSinceCompaction(branchEntries) {
|
|
|
689
674
|
break;
|
|
690
675
|
}
|
|
691
676
|
}
|
|
692
|
-
const firstMarkerIndex = branchEntries.findIndex((entry, index) => index >= start && completedAgentRunData(entry) !== undefined);
|
|
693
|
-
if (firstMarkerIndex < 0) {
|
|
694
|
-
let completed2 = 0;
|
|
695
|
-
for (let i = start;i < branchEntries.length; i += 1) {
|
|
696
|
-
const entry = branchEntries[i];
|
|
697
|
-
if (isMessageEntry(entry) && isTerminalAssistant(entry.message))
|
|
698
|
-
completed2 += 1;
|
|
699
|
-
}
|
|
700
|
-
return completed2;
|
|
701
|
-
}
|
|
702
|
-
const firstMarker = completedAgentRunData(branchEntries[firstMarkerIndex]);
|
|
703
|
-
const boundaryIndex = firstMarker?.startedAfterEntryId ? branchEntries.findIndex((entry) => entry.id === firstMarker.startedAfterEntryId) : start - 1;
|
|
704
|
-
const legacyEnd = boundaryIndex >= start ? boundaryIndex + 1 : start;
|
|
705
677
|
let completed = 0;
|
|
706
|
-
for (let i = start;i <
|
|
678
|
+
for (let i = start;i < branchEntries.length; i += 1) {
|
|
707
679
|
const entry = branchEntries[i];
|
|
708
|
-
if (isMessageEntry(entry) &&
|
|
709
|
-
completed += 1;
|
|
710
|
-
}
|
|
711
|
-
for (let i = firstMarkerIndex;i < branchEntries.length; i += 1) {
|
|
712
|
-
if (completedAgentRunData(branchEntries[i]) !== undefined)
|
|
680
|
+
if (isMessageEntry(entry) && isCompletedAssistant(entry.message))
|
|
713
681
|
completed += 1;
|
|
714
682
|
}
|
|
715
683
|
return completed;
|
|
@@ -877,7 +845,7 @@ async function runSettingsEditor(ctx) {
|
|
|
877
845
|
const specs = [
|
|
878
846
|
{
|
|
879
847
|
key: "turnsBeforeCompact",
|
|
880
|
-
description: "
|
|
848
|
+
description: "LLM turns before compaction; 0 disables.",
|
|
881
849
|
min: TURNS_BEFORE_COMPACT_MIN,
|
|
882
850
|
max: TURNS_BEFORE_COMPACT_MAX
|
|
883
851
|
},
|
|
@@ -1443,8 +1411,8 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1443
1411
|
let operationGeneration = 0;
|
|
1444
1412
|
let activeSessionFile = null;
|
|
1445
1413
|
let sessionActive = false;
|
|
1446
|
-
let
|
|
1447
|
-
let
|
|
1414
|
+
let activePi = null;
|
|
1415
|
+
let resumeAfterCompaction = false;
|
|
1448
1416
|
const rememberQueue = [];
|
|
1449
1417
|
let rememberRunning = null;
|
|
1450
1418
|
function enqueueRemember(target, reportError) {
|
|
@@ -1482,9 +1450,9 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1482
1450
|
}
|
|
1483
1451
|
function syncCompactCounters(ctx) {
|
|
1484
1452
|
compactSettings = resolveGoosedumpSettings(ctx.cwd, projectSettingsTrusted(ctx));
|
|
1485
|
-
const
|
|
1486
|
-
turnsRemaining = Math.max(0, compactSettings.turnsBeforeCompact -
|
|
1487
|
-
counterTriggered = compactSettings.turnsBeforeCompact > 0 &&
|
|
1453
|
+
const completedTurns = completedTurnsSinceCompaction(ctx.sessionManager.getBranch());
|
|
1454
|
+
turnsRemaining = Math.max(0, compactSettings.turnsBeforeCompact - completedTurns);
|
|
1455
|
+
counterTriggered = compactSettings.turnsBeforeCompact > 0 && completedTurns >= compactSettings.turnsBeforeCompact;
|
|
1488
1456
|
}
|
|
1489
1457
|
function updateStatus(ctx) {
|
|
1490
1458
|
if (!goosedumpAvailable)
|
|
@@ -1509,13 +1477,44 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1509
1477
|
compactionState = state;
|
|
1510
1478
|
updateStatus(ctx);
|
|
1511
1479
|
}
|
|
1512
|
-
function
|
|
1480
|
+
function noteCompletedTurn(ctx) {
|
|
1513
1481
|
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
|
|
1514
1482
|
return;
|
|
1515
1483
|
syncCompactCounters(ctx);
|
|
1516
1484
|
updateStatus(ctx);
|
|
1517
1485
|
queueTurnCompaction(ctx, settlementGeneration + 1);
|
|
1518
1486
|
}
|
|
1487
|
+
function resumeAfterSuccessfulCompaction(ctx, resume) {
|
|
1488
|
+
if (!resume || !activePi || ctx.hasPendingMessages())
|
|
1489
|
+
return;
|
|
1490
|
+
activePi.sendMessage({
|
|
1491
|
+
customType: "goosedump-autocompact-resume",
|
|
1492
|
+
content: "The session was compacted to reduce context size. Continue the task you were working on from where you left off.",
|
|
1493
|
+
display: false
|
|
1494
|
+
}, { triggerTurn: true });
|
|
1495
|
+
}
|
|
1496
|
+
function tryMidRunCounterCompaction(ctx) {
|
|
1497
|
+
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
|
|
1498
|
+
return false;
|
|
1499
|
+
if (!counterTriggered)
|
|
1500
|
+
return false;
|
|
1501
|
+
if (ctx.hasPendingMessages())
|
|
1502
|
+
return false;
|
|
1503
|
+
if (!hasCompactableHistory(ctx))
|
|
1504
|
+
return false;
|
|
1505
|
+
if (compactionState.phase === "idle") {
|
|
1506
|
+
queueTurnCompaction(ctx, settlementGeneration);
|
|
1507
|
+
} else if (compactionState.phase === "queued") {
|
|
1508
|
+
setCompactionState(ctx, {
|
|
1509
|
+
phase: "queued",
|
|
1510
|
+
request: {
|
|
1511
|
+
...compactionState.request,
|
|
1512
|
+
eligibleSettlement: Math.min(compactionState.request.eligibleSettlement, settlementGeneration)
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
return startQueuedCompaction(ctx, { resumeAfter: true, allowActiveRun: true });
|
|
1517
|
+
}
|
|
1519
1518
|
function checkGoosedump(ctx) {
|
|
1520
1519
|
try {
|
|
1521
1520
|
execFileSync(process.execPath, [resolveGoosedumpBinary(), "--version"], { stdio: "ignore" });
|
|
@@ -1567,7 +1566,7 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1567
1566
|
}
|
|
1568
1567
|
});
|
|
1569
1568
|
}
|
|
1570
|
-
function startQueuedCompaction(ctx) {
|
|
1569
|
+
function startQueuedCompaction(ctx, options2 = {}) {
|
|
1571
1570
|
if (compactionState.phase !== "queued")
|
|
1572
1571
|
return false;
|
|
1573
1572
|
const request = compactionState.request;
|
|
@@ -1575,7 +1574,9 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1575
1574
|
setCompactionState(ctx, { phase: "idle" });
|
|
1576
1575
|
return false;
|
|
1577
1576
|
}
|
|
1578
|
-
if (
|
|
1577
|
+
if (ctx.hasPendingMessages())
|
|
1578
|
+
return false;
|
|
1579
|
+
if (!options2.allowActiveRun && !ctx.isIdle())
|
|
1579
1580
|
return false;
|
|
1580
1581
|
if (!requestHasCompactableHistory(ctx, request.keep)) {
|
|
1581
1582
|
setCompactionState(ctx, { phase: "idle" });
|
|
@@ -1584,6 +1585,8 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1584
1585
|
const operation = ++operationGeneration;
|
|
1585
1586
|
const generation = request.sessionGeneration;
|
|
1586
1587
|
const sessionFile = request.sessionFile;
|
|
1588
|
+
const resumeAfter = options2.resumeAfter === true;
|
|
1589
|
+
resumeAfterCompaction = resumeAfter;
|
|
1587
1590
|
setCompactionState(ctx, {
|
|
1588
1591
|
phase: "running",
|
|
1589
1592
|
request,
|
|
@@ -1597,12 +1600,20 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1597
1600
|
onComplete: () => {
|
|
1598
1601
|
if (!runningOperationIsCurrent(operation, generation, sessionFile))
|
|
1599
1602
|
return;
|
|
1603
|
+
const shouldResume = resumeAfterCompaction;
|
|
1604
|
+
resumeAfterCompaction = false;
|
|
1600
1605
|
setCompactionState(ctx, { phase: "idle" });
|
|
1606
|
+
syncCompactCounters(ctx);
|
|
1607
|
+
updateStatus(ctx);
|
|
1608
|
+
resumeAfterSuccessfulCompaction(ctx, shouldResume);
|
|
1601
1609
|
},
|
|
1602
1610
|
onError: (error) => {
|
|
1603
1611
|
if (!runningOperationIsCurrent(operation, generation, sessionFile))
|
|
1604
1612
|
return;
|
|
1613
|
+
resumeAfterCompaction = false;
|
|
1605
1614
|
setCompactionState(ctx, { phase: "idle" });
|
|
1615
|
+
syncCompactCounters(ctx);
|
|
1616
|
+
updateStatus(ctx);
|
|
1606
1617
|
const message = error instanceof Error ? error.message : String(error);
|
|
1607
1618
|
if (ctx.hasUI)
|
|
1608
1619
|
ctx.ui.notify(`goosedump compaction failed: ${message}`, "error");
|
|
@@ -1638,6 +1649,7 @@ function createGoosedumpIntegration(options = {}) {
|
|
|
1638
1649
|
return startQueuedCompaction(ctx) ? "started" : "queued";
|
|
1639
1650
|
}
|
|
1640
1651
|
function register(pi) {
|
|
1652
|
+
activePi = pi;
|
|
1641
1653
|
if (shouldRegisterTool) {
|
|
1642
1654
|
pi.registerTool(defineTool({
|
|
1643
1655
|
name: "goose_remember",
|
|
@@ -1989,6 +2001,8 @@ ${lines.join(`
|
|
|
1989
2001
|
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
|
|
1990
2002
|
return;
|
|
1991
2003
|
settlementGeneration += 1;
|
|
2004
|
+
syncCompactCounters(ctx);
|
|
2005
|
+
updateStatus(ctx);
|
|
1992
2006
|
if (compactionState.phase === "running" && compactionState.owner === "pi") {
|
|
1993
2007
|
const request = compactionState.request;
|
|
1994
2008
|
setCompactionState(ctx, request && requestIsCurrent(request) ? {
|
|
@@ -2012,8 +2026,7 @@ ${lines.join(`
|
|
|
2012
2026
|
settlementGeneration = 0;
|
|
2013
2027
|
activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
|
|
2014
2028
|
sessionActive = true;
|
|
2015
|
-
|
|
2016
|
-
agentRunStartEntryId = null;
|
|
2029
|
+
resumeAfterCompaction = false;
|
|
2017
2030
|
compactionState = { phase: "idle" };
|
|
2018
2031
|
goosedumpAvailable = checkGoosedump(ctx);
|
|
2019
2032
|
notifyInvalidSettings(ctx);
|
|
@@ -2027,8 +2040,7 @@ ${lines.join(`
|
|
|
2027
2040
|
settlementGeneration = 0;
|
|
2028
2041
|
activeSessionFile = null;
|
|
2029
2042
|
sessionActive = false;
|
|
2030
|
-
|
|
2031
|
-
agentRunStartEntryId = null;
|
|
2043
|
+
resumeAfterCompaction = false;
|
|
2032
2044
|
compactionState = { phase: "idle" };
|
|
2033
2045
|
});
|
|
2034
2046
|
pi.on("session_tree", async (_event, ctx) => {
|
|
@@ -2036,8 +2048,7 @@ ${lines.join(`
|
|
|
2036
2048
|
settlementGeneration = 0;
|
|
2037
2049
|
activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
|
|
2038
2050
|
sessionActive = true;
|
|
2039
|
-
|
|
2040
|
-
agentRunStartEntryId = null;
|
|
2051
|
+
resumeAfterCompaction = false;
|
|
2041
2052
|
compactionState = { phase: "idle" };
|
|
2042
2053
|
syncCompactCounters(ctx);
|
|
2043
2054
|
updateStatus(ctx);
|
|
@@ -2045,10 +2056,6 @@ ${lines.join(`
|
|
|
2045
2056
|
deferQueuedCompaction(ctx);
|
|
2046
2057
|
});
|
|
2047
2058
|
pi.on("agent_start", async (_event, ctx) => {
|
|
2048
|
-
if (!agentRunObserved) {
|
|
2049
|
-
agentRunObserved = true;
|
|
2050
|
-
agentRunStartEntryId = ctx.sessionManager.getBranch().at(-1)?.id ?? null;
|
|
2051
|
-
}
|
|
2052
2059
|
if (compactionState.phase !== "running" || compactionState.owner !== "pi")
|
|
2053
2060
|
return;
|
|
2054
2061
|
const request = compactionState.request;
|
|
@@ -2057,20 +2064,13 @@ ${lines.join(`
|
|
|
2057
2064
|
request: { ...request, eligibleSettlement: settlementGeneration + 1 }
|
|
2058
2065
|
} : { phase: "idle" });
|
|
2059
2066
|
});
|
|
2067
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
2068
|
+
if (isCompletedAssistant(event.message))
|
|
2069
|
+
noteCompletedTurn(ctx);
|
|
2070
|
+
if (event.toolResults.length > 0)
|
|
2071
|
+
tryMidRunCounterCompaction(ctx);
|
|
2072
|
+
});
|
|
2060
2073
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
2061
|
-
if (agentRunObserved) {
|
|
2062
|
-
const countRun = shouldOverrideDefaultCompaction && compactSettings.turnsBeforeCompact > 0;
|
|
2063
|
-
if (countRun) {
|
|
2064
|
-
pi.appendEntry(COMPLETED_AGENT_RUN_ENTRY, {
|
|
2065
|
-
version: 1,
|
|
2066
|
-
startedAfterEntryId: agentRunStartEntryId
|
|
2067
|
-
});
|
|
2068
|
-
}
|
|
2069
|
-
agentRunObserved = false;
|
|
2070
|
-
agentRunStartEntryId = null;
|
|
2071
|
-
if (countRun)
|
|
2072
|
-
noteCompletedRun(ctx);
|
|
2073
|
-
}
|
|
2074
2074
|
handleAgentSettled(ctx);
|
|
2075
2075
|
});
|
|
2076
2076
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
@@ -2212,6 +2212,7 @@ ${lines.join(`
|
|
|
2212
2212
|
}
|
|
2213
2213
|
});
|
|
2214
2214
|
pi.on("session_compact", async (event, ctx) => {
|
|
2215
|
+
resumeAfterCompaction = false;
|
|
2215
2216
|
if (!shouldOverrideDefaultCompaction)
|
|
2216
2217
|
return;
|
|
2217
2218
|
if (!contextIsCurrent(ctx))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.19",
|
|
4
4
|
"description": "Pi extension for goosedump session search, durable memory, and compaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compaction",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@earendil-works/pi-tui": "^0.82.1",
|
|
41
|
-
"@jarkkojs/goosedump": "^0.12.
|
|
41
|
+
"@jarkkojs/goosedump": "^0.12.19",
|
|
42
42
|
"@sinclair/typebox": "^0.34.49"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|