diff options
Diffstat (limited to 'src/session_persist.zig')
| -rw-r--r-- | src/session_persist.zig | 153 |
1 files changed, 0 insertions, 153 deletions
diff --git a/src/session_persist.zig b/src/session_persist.zig deleted file mode 100644 index d5349bc..0000000 --- a/src/session_persist.zig +++ /dev/null @@ -1,153 +0,0 @@ -//! Session-log persistence helpers shared between the REPL loop -//! (`main.zig`) and slash-command handlers (e.g. `compaction.zig`). -//! -//! These were previously private to `main.zig`. They were lifted into -//! their own module so that command handlers living outside the root -//! source file can reuse them without depending on `main.zig` (which, -//! being the executable root, can't be imported as a normal module). - -const std = @import("std"); -const panto = @import("panto"); - -/// Append a single user-prompt message to the session log. -pub fn appendUserPromptToSession( - alloc: std.mem.Allocator, - mgr: *panto.session_manager.SessionManager, - text: []const u8, - provider: []const u8, - model: []const u8, -) !void { - const blocks = try alloc.alloc(panto.session_manager.DiskContentBlock, 1); - blocks[0] = .{ .text = .{ .text = try alloc.dupe(u8, text) } }; - _ = try mgr.appendMessage( - .{ .role = .user, .content = blocks }, - provider, - model, - ); -} - -/// After the agent loop has driven a turn to completion, persist every -/// new in-memory message at index `>= start_index` to the session log. -/// -/// Each in-memory message is mapped to disk: -/// - assistant → assistant entry with provider/model/stop_reason metadata -/// and Usage (from `per_message_usage`, one slot per assistant message in -/// completion order). -/// - user (with ToolResult blocks) → user entry stamped with provider/model. -/// -/// `stop_reason` is recorded as `"stop"` for now; surfacing the real wire -/// value requires plumbing it through the Receiver vtable (future work, -/// separate from token plumbing). -pub fn persistTurn( - alloc: std.mem.Allocator, - mgr: *panto.session_manager.SessionManager, - conv: *const panto.conversation.Conversation, - start_index: usize, - provider: []const u8, - model: []const u8, - per_message_usage: []const ?panto.session_manager.Usage, -) !void { - var batch_messages: std.ArrayList(panto.session_manager.DiskMessage) = .empty; - defer batch_messages.deinit(alloc); - var batch_providers: std.ArrayList(?[]const u8) = .empty; - defer batch_providers.deinit(alloc); - var batch_models: std.ArrayList(?[]const u8) = .empty; - defer batch_models.deinit(alloc); - - var i = start_index; - var assistant_seen: usize = 0; - while (i < conv.messages.items.len) : (i += 1) { - const msg = conv.messages.items[i]; - const blocks = try alloc.alloc(panto.session_manager.DiskContentBlock, msg.content.items.len); - var allocated: usize = 0; - errdefer { - for (blocks[0..allocated]) |b| b.deinit(alloc); - alloc.free(blocks); - } - for (msg.content.items) |block| { - blocks[allocated] = try panto.session.contentBlockToDisk(alloc, block); - allocated += 1; - } - if (msg.role == .assistant and hasToolUseWithoutFollowingResults(conv, i)) { - for (blocks[0..allocated]) |b| b.deinit(alloc); - alloc.free(blocks); - continue; - } - switch (msg.role) { - .system => { - // Mid-turn system messages aren't a thing in pantograph today. - // Treat as harmless and persist verbatim, sans stamps. - try batch_messages.append(alloc, .{ .role = .system, .content = blocks }); - try batch_providers.append(alloc, null); - try batch_models.append(alloc, null); - }, - .user => { - try batch_messages.append(alloc, .{ .role = .user, .content = blocks }); - try batch_providers.append(alloc, provider); - try batch_models.append(alloc, model); - }, - .assistant => { - // Pair this assistant message with its usage, if the - // receiver captured one for this position. (A turn - // ending in a stream error can have fewer usage entries - // than assistant messages; treat as null and move on.) - const usage: ?panto.session_manager.Usage = if (assistant_seen < per_message_usage.len) - per_message_usage[assistant_seen] - else - null; - assistant_seen += 1; - try batch_messages.append(alloc, .{ - .role = .assistant, - .content = blocks, - .provider = try alloc.dupe(u8, provider), - .model = try alloc.dupe(u8, model), - .stop_reason = try alloc.dupe(u8, "stop"), - .usage = usage, - }); - try batch_providers.append(alloc, null); - try batch_models.append(alloc, null); - }, - } - } - try mgr.appendMessagesAtomic(batch_messages.items, batch_providers.items, batch_models.items); -} - -/// Persist a compaction to the session log. The agent rewrote the -/// in-memory conversation to `[system..., summary, kept-suffix...]`; the -/// superseded prefix stays on disk untouched. We append everything from -/// the compaction summary onward as fresh entries: the summary message -/// (carrying the `compactionSummary` block) followed by the duplicated -/// kept-verbatim suffix. On replay, the latest summary resets effective -/// context, so the duplicated suffix is what survives. -/// -/// Usage is not threaded through here: the duplicated entries are replays -/// of already-sized turns, and the summary itself isn't an assistant turn. -pub fn persistCompaction( - alloc: std.mem.Allocator, - mgr: *panto.session_manager.SessionManager, - conv: *const panto.conversation.Conversation, - provider: []const u8, - model: []const u8, -) !void { - const start = panto.conversation.latestCompactionIndex(conv.messages.items) orelse return; - try persistTurn(alloc, mgr, conv, start, provider, model, &.{}); -} - -pub fn hasToolUseWithoutFollowingResults(conv: *const panto.conversation.Conversation, index: usize) bool { - const msg = conv.messages.items[index]; - for (msg.content.items) |block| { - if (block != .ToolUse) continue; - if (index + 1 >= conv.messages.items.len) return true; - const next = conv.messages.items[index + 1]; - if (next.role != .user) return true; - var found = false; - for (next.content.items) |next_block| { - if (next_block == .ToolResult and std.mem.eql(u8, next_block.ToolResult.tool_use_id, block.ToolUse.id)) { - found = true; - break; - } - } - if (!found) return true; - } - return false; -} |
