@caupulican/pi-agent-core 0.93.17 → 0.93.18

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.
@@ -201,11 +201,9 @@ export function buildSessionContext(entries, leafId, byId) {
201
201
  compaction = entry;
202
202
  }
203
203
  }
204
- // Build messages and collect corresponding entries
205
- // When there's a compaction, we need to:
206
- // 1. Emit summary first (entry = compaction)
207
- // 2. Emit kept messages (from firstKeptEntryId up to compaction)
208
- // 3. Emit messages after compaction
204
+ // Build messages and collect corresponding entries. Standard compaction emits the summary followed
205
+ // by a contiguous recent tail. Session replacement instead retains one sparse original-user anchor
206
+ // before the summary, matching providers whose compactor atomically replaces the live transcript.
209
207
  const messages = [];
210
208
  const appendMessage = (entry) => {
211
209
  if (entry.type === "message") {
@@ -219,19 +217,28 @@ export function buildSessionContext(entries, leafId, byId) {
219
217
  }
220
218
  };
221
219
  if (compaction) {
222
- // Emit summary first
223
- messages.push(retainSynthesizedSessionContextMessage(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp)));
224
220
  // Find compaction index in path
225
221
  const compactionIdx = path.findIndex((e) => e.type === "compaction" && e.id === compaction.id);
226
- // Emit kept messages (before compaction, starting from firstKeptEntryId)
227
- let foundFirstKept = false;
228
- for (let i = 0; i < compactionIdx; i++) {
229
- const entry = path[i];
230
- if (entry.id === compaction.firstKeptEntryId) {
231
- foundFirstKept = true;
232
- }
233
- if (foundFirstKept) {
234
- appendMessage(entry);
222
+ const originalUserEntry = compaction.retention?.mode === "original-user"
223
+ ? path
224
+ .slice(0, compactionIdx)
225
+ .find((entry) => entry.id === compaction.retention?.userEntryId &&
226
+ entry.type === "message" &&
227
+ entry.message.role === "user")
228
+ : undefined;
229
+ if (originalUserEntry)
230
+ appendMessage(originalUserEntry);
231
+ messages.push(retainSynthesizedSessionContextMessage(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp)));
232
+ if (!compaction.retention) {
233
+ // Emit the standard contiguous tail before compaction, starting from firstKeptEntryId.
234
+ let foundFirstKept = false;
235
+ for (let i = 0; i < compactionIdx; i++) {
236
+ const entry = path[i];
237
+ if (entry.id === compaction.firstKeptEntryId) {
238
+ foundFirstKept = true;
239
+ }
240
+ if (foundFirstKept)
241
+ appendMessage(entry);
235
242
  }
236
243
  }
237
244
  // Emit messages after compaction
@@ -1120,24 +1127,42 @@ export class SessionManager {
1120
1127
  const leaf = this.leafId ? this.byId.get(this.leafId) : undefined;
1121
1128
  visitSessionAncestry(leaf, this.byId, (current) => {
1122
1129
  if (current.type === "compaction") {
1123
- this._releaseCompactedMessagePayloads(current.firstKeptEntryId, current.parentId);
1130
+ this._releaseCompactedMessagePayloads(current.firstKeptEntryId, current.parentId, current.retention, current.id);
1124
1131
  return false;
1125
1132
  }
1126
1133
  });
1127
1134
  }
1128
- _releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId) {
1135
+ _releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId, retention, compactionEntryId) {
1129
1136
  if (!this.persist || !this.flushed || !this.sessionFile)
1130
1137
  return;
1131
1138
  const keptEntryIds = new Set();
1132
1139
  let foundFirstKept = false;
1133
1140
  const compactionParent = compactionParentId ? this.byId.get(compactionParentId) : undefined;
1134
- visitSessionAncestry(compactionParent, this.byId, (current) => {
1135
- keptEntryIds.add(current.id);
1136
- if (current.id === firstKeptEntryId) {
1137
- foundFirstKept = true;
1138
- return false;
1139
- }
1140
- });
1141
+ if (retention?.mode === "original-user") {
1142
+ visitSessionAncestry(compactionParent, this.byId, (current) => {
1143
+ if (current.id === retention.userEntryId && current.type === "message" && current.message.role === "user") {
1144
+ keptEntryIds.add(current.id);
1145
+ foundFirstKept = true;
1146
+ return false;
1147
+ }
1148
+ });
1149
+ const leaf = this.leafId ? this.byId.get(this.leafId) : undefined;
1150
+ visitSessionAncestry(leaf, this.byId, (current) => {
1151
+ if (current.id === compactionEntryId)
1152
+ return false;
1153
+ if (current.type === "message")
1154
+ keptEntryIds.add(current.id);
1155
+ });
1156
+ }
1157
+ else {
1158
+ visitSessionAncestry(compactionParent, this.byId, (current) => {
1159
+ keptEntryIds.add(current.id);
1160
+ if (current.id === firstKeptEntryId) {
1161
+ foundFirstKept = true;
1162
+ return false;
1163
+ }
1164
+ });
1165
+ }
1141
1166
  if (!foundFirstKept)
1142
1167
  return;
1143
1168
  const retainedIds = new Set();
@@ -1288,7 +1313,7 @@ export class SessionManager {
1288
1313
  return entry.id;
1289
1314
  }
1290
1315
  /** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */
1291
- appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage) {
1316
+ appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook, usage, retention) {
1292
1317
  const compactionParentId = this.leafId;
1293
1318
  const entry = {
1294
1319
  type: "compaction",
@@ -1298,12 +1323,13 @@ export class SessionManager {
1298
1323
  summary,
1299
1324
  firstKeptEntryId,
1300
1325
  tokensBefore,
1326
+ retention,
1301
1327
  details,
1302
1328
  usage,
1303
1329
  fromHook,
1304
1330
  };
1305
1331
  this._appendEntry(entry);
1306
- this._releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId);
1332
+ this._releaseCompactedMessagePayloads(firstKeptEntryId, compactionParentId, retention, entry.id);
1307
1333
  return entry.id;
1308
1334
  }
1309
1335
  /** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */