summaryrefslogtreecommitdiff
path: root/libpanto/src/file_system_jsonl_store.zig
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-13 23:45:59 -0600
committert <t@tjp.lol>2026-06-15 15:08:32 -0600
commit02b4c7a35ac0b714bc045d54fb4bb45d1ce4e490 (patch)
tree134196a82dd6fdd55b735be4c0cf38428c85038d /libpanto/src/file_system_jsonl_store.zig
parent71643a5d69ffc40882c9fcde3cc8a3bcf02d7396 (diff)
Add Codex Responses support and session debugging
Teach provider config and auth resolution about the Codex Responses dialect, including user-facing `style = "openai_responses"` with `dialect = "codex"`. Serialize and parse Responses traffic with provider-specific reasoning replay, assistant phase metadata, and robust function-call assembly keyed by `output_index` so streamed tool inputs survive proxy quirks and empty terminal payloads. Also persist thinking origins and message metadata across sessions, add the Anthropic interleaved-thinking header switch, write per-session debug logs, and improve the TUI and scripts for inspecting tool output and session costs.
Diffstat (limited to 'libpanto/src/file_system_jsonl_store.zig')
-rw-r--r--libpanto/src/file_system_jsonl_store.zig59
1 files changed, 58 insertions, 1 deletions
diff --git a/libpanto/src/file_system_jsonl_store.zig b/libpanto/src/file_system_jsonl_store.zig
index 1d56ae9..e47698c 100644
--- a/libpanto/src/file_system_jsonl_store.zig
+++ b/libpanto/src/file_system_jsonl_store.zig
@@ -709,7 +709,7 @@ pub const SessionFile = struct {
for (self.entries.items) |entry| {
switch (entry) {
- .message => |me| try appendMessageToConv(&conv, self.allocator, me.message),
+ .message => |me| try appendMessageToConv(&conv, self.allocator, me.message, me.stamp),
}
}
return conv;
@@ -733,6 +733,7 @@ fn appendMessageToConv(
conv: *conversation_mod.Conversation,
allocator: Allocator,
disk_msg: StoredMessage,
+ stamp: ?session_mod.WireStamp,
) !void {
var content: std.ArrayList(conversation_mod.ContentBlock) = .empty;
errdefer {
@@ -756,6 +757,14 @@ fn appendMessageToConv(
const tb = block.Text;
block = .{ .System = .{ .text = tb, .mode = sys_mode } };
}
+ if (block == .Thinking and stamp != null) {
+ block.Thinking.signature_origin = try conversation_mod.SignatureOrigin.init(
+ allocator,
+ stamp.?.api_style,
+ stamp.?.base_url,
+ stamp.?.model,
+ );
+ }
content.appendAssumeCapacity(block);
}
const role: conversation_mod.MessageRole = switch (disk_msg.role) {
@@ -2090,3 +2099,51 @@ test "FileSystemJSONLStore catalog: create → append → load round-trips" {
try testing.expectEqual(@as(usize, 2), loaded.messages.items.len);
try testing.expectEqual(conversation_mod.MessageRole.user, loaded.messages.items[0].role);
}
+
+test "FileSystemJSONLStore load restores thinking signature origin from message stamp" {
+ 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);
+
+ var catalog = try FileSystemJSONLStore.init(testing.allocator, io, sessions);
+ defer catalog.deinit();
+ const store = catalog.store();
+
+ var sess = store.create();
+ defer sess.info.deinit(testing.allocator);
+
+ var conv = conversation_mod.Conversation.init(testing.allocator);
+ defer conv.deinit();
+ try addUserText(&conv, "ping");
+ try conv.addAssistantMessage(&.{
+ .{ .Thinking = .{
+ .text = try conversation_mod.textualBlockFromSlice(testing.allocator, "thinking..."),
+ .signature = try testing.allocator.dupe(u8, "sig123"),
+ } },
+ .{ .Text = try conversation_mod.textualBlockFromSlice(testing.allocator, "pong") },
+ }, null);
+
+ const id: session_store_mod.WireIdentity = .{
+ .api_style = .anthropic_messages,
+ .base_url = "https://api.anthropic.com",
+ .model = "claude-sonnet-4-20250514",
+ };
+ var batch = [_]session_store_mod.PersistentMessage{
+ .{ .message = conv.messages.items[0], .identity = id },
+ .{ .message = conv.messages.items[1], .identity = id },
+ };
+ try sess.append(&batch);
+
+ var loaded = (try store.load(sess.info.id)).?;
+ defer loaded.deinit();
+ const thinking = loaded.messages.items[1].content.items[0].Thinking;
+ try testing.expect(thinking.signature_origin != null);
+ try testing.expect(thinking.signature_origin.?.matches(
+ .anthropic_messages,
+ "https://api.anthropic.com",
+ "claude-sonnet-4-20250514",
+ ));
+}