summaryrefslogtreecommitdiff
path: root/libpanto/src/session_manager.zig
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-02 15:00:44 -0600
committert <t@tjp.lol>2026-06-02 16:37:32 -0600
commit8b88b886346460b1ab29edb03ad85bc3bb565a45 (patch)
tree13b9ab56061a722641389b5fc8ac1113d09b66e5 /libpanto/src/session_manager.zig
parent7268c0b8e8bcf4b325581fabe7476a394f167738 (diff)
compaction
Diffstat (limited to 'libpanto/src/session_manager.zig')
-rw-r--r--libpanto/src/session_manager.zig69
1 files changed, 68 insertions, 1 deletions
diff --git a/libpanto/src/session_manager.zig b/libpanto/src/session_manager.zig
index 9e8e2c8..c6256e0 100644
--- a/libpanto/src/session_manager.zig
+++ b/libpanto/src/session_manager.zig
@@ -750,7 +750,13 @@ fn appendMessageToConv(
.user => .user,
.assistant => .assistant,
};
- try conv.messages.append(allocator, .{ .role = role, .content = content });
+ // Carry the recorded usage forward so compaction can size the retention
+ // window after a session is reopened (it's null for user/system).
+ try conv.messages.append(allocator, .{
+ .role = role,
+ .content = content,
+ .usage = disk_msg.usage,
+ });
}
// =============================================================================
@@ -1621,3 +1627,64 @@ test "resolveSessionId: unique prefix → match, ambiguous → error" {
try testing.expectError(error.SessionNotFound, resolveSessionId(testing.allocator, io, sessions, "ffffffff"));
}
+
+test "compaction summary round-trips through persist + resume + rebuild" {
+ const io = testing.io;
+
+ var td = try TmpSessionDir.init(testing.allocator);
+ defer td.deinit(testing.allocator);
+ const sessions = try std.fs.path.join(testing.allocator, &.{ td.abs_path, "sessions" });
+ defer testing.allocator.free(sessions);
+
+ const session_file: []u8 = blk: {
+ var mgr = try SessionManager.init(testing.allocator, io, sessions, "/c");
+ defer mgr.deinit();
+
+ // System + an old turn that will be superseded.
+ const sys = try testing.allocator.alloc(DiskContentBlock, 1);
+ sys[0] = .{ .text = .{ .text = try testing.allocator.dupe(u8, "you are helpful") } };
+ _ = try mgr.appendMessage(.{ .role = .system, .content = sys }, null, null);
+
+ const uo = try testing.allocator.alloc(DiskContentBlock, 1);
+ uo[0] = .{ .text = .{ .text = try testing.allocator.dupe(u8, "old q") } };
+ _ = try mgr.appendMessage(.{ .role = .user, .content = uo }, "openai", "gpt-4o");
+ const ao = try testing.allocator.alloc(DiskContentBlock, 1);
+ ao[0] = .{ .text = .{ .text = try testing.allocator.dupe(u8, "old a") } };
+ _ = try mgr.appendMessage(.{ .role = .assistant, .content = ao }, null, null);
+
+ // Compaction: summary message + duplicated kept suffix.
+ const cs = try testing.allocator.alloc(DiskContentBlock, 1);
+ cs[0] = .{ .compaction_summary = .{ .text = try testing.allocator.dupe(u8, "SUMMARY") } };
+ _ = try mgr.appendMessage(.{ .role = .user, .content = cs }, "openai", "gpt-4o");
+
+ const ur = try testing.allocator.alloc(DiskContentBlock, 1);
+ ur[0] = .{ .text = .{ .text = try testing.allocator.dupe(u8, "recent q") } };
+ _ = try mgr.appendMessage(.{ .role = .user, .content = ur }, "openai", "gpt-4o");
+
+ break :blk try testing.allocator.dupe(u8, mgr.getSessionFile());
+ };
+ defer testing.allocator.free(session_file);
+
+ var resumed = try SessionManager.open(testing.allocator, io, session_file);
+ defer resumed.deinit();
+ var conv = try resumed.rebuildConversation();
+ defer conv.deinit();
+
+ // The compaction summary block survived as a CompactionSummary.
+ const anchor = conversation_mod.latestCompactionIndex(conv.messages.items).?;
+ try testing.expectEqualStrings(
+ "SUMMARY",
+ conv.messages.items[anchor].content.items[0].CompactionSummary.text.items,
+ );
+
+ // The active window is [summary, recent q].
+ const window = conversation_mod.activeMessageWindow(conv.messages.items);
+ try testing.expectEqual(@as(usize, 2), window.len);
+ try testing.expectEqualStrings("recent q", window[1].content.items[0].Text.items);
+
+ // System prompt survives (derived independently).
+ var sys_blocks = try conversation_mod.effectiveSystemBlocks(testing.allocator, conv.messages.items);
+ defer sys_blocks.deinit(testing.allocator);
+ try testing.expectEqual(@as(usize, 1), sys_blocks.items.len);
+ try testing.expectEqualStrings("you are helpful", sys_blocks.items[0]);
+}