From 02b4c7a35ac0b714bc045d54fb4bb45d1ce4e490 Mon Sep 17 00:00:00 2001 From: t Date: Sat, 13 Jun 2026 23:45:59 -0600 Subject: 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. --- libpanto/src/file_system_jsonl_store.zig | 59 +++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) (limited to 'libpanto/src/file_system_jsonl_store.zig') 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", + )); +} -- cgit v1.3