pi-goosedump 0.12.17 → 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 CHANGED
@@ -98,12 +98,14 @@ that call tools. The countdown is restored when a session resumes and appears in
98
98
  the footer with a status dot (green when >25% turns remain, yellow when ≤25%, red
99
99
  when ≤12.5%) followed by a hexadecimal countdown. `● GD:0A` means ten turns
100
100
  remain, `● GD:00` is ready to compact, and `● GD:--` is disabled. The footer
101
- adds `queued` while compaction is waiting for the active agent run to settle and
102
- `compacting` while the summary is being built. Pi remains the sole scheduler for
103
- its normal context threshold. Whichever limit is reached first compacts once,
104
- and every successful compaction resets the countdown. A failed or cancelled
105
- compaction leaves the counter armed at zero and is not retried in the same
106
- settlement.
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
@@ -1411,6 +1411,8 @@ function createGoosedumpIntegration(options = {}) {
1411
1411
  let operationGeneration = 0;
1412
1412
  let activeSessionFile = null;
1413
1413
  let sessionActive = false;
1414
+ let activePi = null;
1415
+ let resumeAfterCompaction = false;
1414
1416
  const rememberQueue = [];
1415
1417
  let rememberRunning = null;
1416
1418
  function enqueueRemember(target, reportError) {
@@ -1482,6 +1484,37 @@ function createGoosedumpIntegration(options = {}) {
1482
1484
  updateStatus(ctx);
1483
1485
  queueTurnCompaction(ctx, settlementGeneration + 1);
1484
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
+ }
1485
1518
  function checkGoosedump(ctx) {
1486
1519
  try {
1487
1520
  execFileSync(process.execPath, [resolveGoosedumpBinary(), "--version"], { stdio: "ignore" });
@@ -1533,7 +1566,7 @@ function createGoosedumpIntegration(options = {}) {
1533
1566
  }
1534
1567
  });
1535
1568
  }
1536
- function startQueuedCompaction(ctx) {
1569
+ function startQueuedCompaction(ctx, options2 = {}) {
1537
1570
  if (compactionState.phase !== "queued")
1538
1571
  return false;
1539
1572
  const request = compactionState.request;
@@ -1541,7 +1574,9 @@ function createGoosedumpIntegration(options = {}) {
1541
1574
  setCompactionState(ctx, { phase: "idle" });
1542
1575
  return false;
1543
1576
  }
1544
- if (!ctx.isIdle() || ctx.hasPendingMessages())
1577
+ if (ctx.hasPendingMessages())
1578
+ return false;
1579
+ if (!options2.allowActiveRun && !ctx.isIdle())
1545
1580
  return false;
1546
1581
  if (!requestHasCompactableHistory(ctx, request.keep)) {
1547
1582
  setCompactionState(ctx, { phase: "idle" });
@@ -1550,6 +1585,8 @@ function createGoosedumpIntegration(options = {}) {
1550
1585
  const operation = ++operationGeneration;
1551
1586
  const generation = request.sessionGeneration;
1552
1587
  const sessionFile = request.sessionFile;
1588
+ const resumeAfter = options2.resumeAfter === true;
1589
+ resumeAfterCompaction = resumeAfter;
1553
1590
  setCompactionState(ctx, {
1554
1591
  phase: "running",
1555
1592
  request,
@@ -1563,12 +1600,20 @@ function createGoosedumpIntegration(options = {}) {
1563
1600
  onComplete: () => {
1564
1601
  if (!runningOperationIsCurrent(operation, generation, sessionFile))
1565
1602
  return;
1603
+ const shouldResume = resumeAfterCompaction;
1604
+ resumeAfterCompaction = false;
1566
1605
  setCompactionState(ctx, { phase: "idle" });
1606
+ syncCompactCounters(ctx);
1607
+ updateStatus(ctx);
1608
+ resumeAfterSuccessfulCompaction(ctx, shouldResume);
1567
1609
  },
1568
1610
  onError: (error) => {
1569
1611
  if (!runningOperationIsCurrent(operation, generation, sessionFile))
1570
1612
  return;
1613
+ resumeAfterCompaction = false;
1571
1614
  setCompactionState(ctx, { phase: "idle" });
1615
+ syncCompactCounters(ctx);
1616
+ updateStatus(ctx);
1572
1617
  const message = error instanceof Error ? error.message : String(error);
1573
1618
  if (ctx.hasUI)
1574
1619
  ctx.ui.notify(`goosedump compaction failed: ${message}`, "error");
@@ -1604,6 +1649,7 @@ function createGoosedumpIntegration(options = {}) {
1604
1649
  return startQueuedCompaction(ctx) ? "started" : "queued";
1605
1650
  }
1606
1651
  function register(pi) {
1652
+ activePi = pi;
1607
1653
  if (shouldRegisterTool) {
1608
1654
  pi.registerTool(defineTool({
1609
1655
  name: "goose_remember",
@@ -1955,6 +2001,8 @@ ${lines.join(`
1955
2001
  if (!goosedumpAvailable || !shouldOverrideDefaultCompaction)
1956
2002
  return;
1957
2003
  settlementGeneration += 1;
2004
+ syncCompactCounters(ctx);
2005
+ updateStatus(ctx);
1958
2006
  if (compactionState.phase === "running" && compactionState.owner === "pi") {
1959
2007
  const request = compactionState.request;
1960
2008
  setCompactionState(ctx, request && requestIsCurrent(request) ? {
@@ -1978,6 +2026,7 @@ ${lines.join(`
1978
2026
  settlementGeneration = 0;
1979
2027
  activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
1980
2028
  sessionActive = true;
2029
+ resumeAfterCompaction = false;
1981
2030
  compactionState = { phase: "idle" };
1982
2031
  goosedumpAvailable = checkGoosedump(ctx);
1983
2032
  notifyInvalidSettings(ctx);
@@ -1991,8 +2040,21 @@ ${lines.join(`
1991
2040
  settlementGeneration = 0;
1992
2041
  activeSessionFile = null;
1993
2042
  sessionActive = false;
2043
+ resumeAfterCompaction = false;
1994
2044
  compactionState = { phase: "idle" };
1995
2045
  });
2046
+ pi.on("session_tree", async (_event, ctx) => {
2047
+ sessionGeneration += 1;
2048
+ settlementGeneration = 0;
2049
+ activeSessionFile = ctx.sessionManager.getSessionFile?.() ?? null;
2050
+ sessionActive = true;
2051
+ resumeAfterCompaction = false;
2052
+ compactionState = { phase: "idle" };
2053
+ syncCompactCounters(ctx);
2054
+ updateStatus(ctx);
2055
+ queueTurnCompaction(ctx, 1);
2056
+ deferQueuedCompaction(ctx);
2057
+ });
1996
2058
  pi.on("agent_start", async (_event, ctx) => {
1997
2059
  if (compactionState.phase !== "running" || compactionState.owner !== "pi")
1998
2060
  return;
@@ -2005,6 +2067,8 @@ ${lines.join(`
2005
2067
  pi.on("turn_end", async (event, ctx) => {
2006
2068
  if (isCompletedAssistant(event.message))
2007
2069
  noteCompletedTurn(ctx);
2070
+ if (event.toolResults.length > 0)
2071
+ tryMidRunCounterCompaction(ctx);
2008
2072
  });
2009
2073
  pi.on("agent_settled", async (_event, ctx) => {
2010
2074
  handleAgentSettled(ctx);
@@ -2148,6 +2212,7 @@ ${lines.join(`
2148
2212
  }
2149
2213
  });
2150
2214
  pi.on("session_compact", async (event, ctx) => {
2215
+ resumeAfterCompaction = false;
2151
2216
  if (!shouldOverrideDefaultCompaction)
2152
2217
  return;
2153
2218
  if (!contextIsCurrent(ctx))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.12.17",
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.17",
41
+ "@jarkkojs/goosedump": "^0.12.19",
42
42
  "@sinclair/typebox": "^0.34.49"
43
43
  },
44
44
  "devDependencies": {