From f026bb81ae68f516910d0eb4f23c9344dd36b62b Mon Sep 17 00:00:00 2001 From: T Date: Mon, 25 May 2026 21:50:43 -0600 Subject: phase 2 done --- libpanto/src/conversation.zig | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'libpanto/src/conversation.zig') diff --git a/libpanto/src/conversation.zig b/libpanto/src/conversation.zig index 0e9a4e9..6776412 100644 --- a/libpanto/src/conversation.zig +++ b/libpanto/src/conversation.zig @@ -13,6 +13,22 @@ pub fn textualBlockFromSlice(alloc: Allocator, slice: []const u8) !TextualBlock return buf; } +/// A reasoning/thinking block from the assistant. +/// +/// `text` is the streamed reasoning content. `signature` is the opaque +/// integrity token Anthropic emits with extended-thinking responses and +/// requires echoed back verbatim on follow-up turns. It is optional because +/// other providers (OpenAI-compatible APIs) do not produce it. +pub const ThinkingBlock = struct { + text: TextualBlock = .empty, + signature: ?[]const u8 = null, + + pub fn deinit(self: *ThinkingBlock, alloc: Allocator) void { + self.text.deinit(alloc); + if (self.signature) |sig| alloc.free(sig); + } +}; + pub const ToolUseBlock = struct { id: []const u8, name: []const u8, @@ -37,13 +53,16 @@ pub const ToolResultBlock = struct { pub const ContentBlock = union(enum) { Text: TextualBlock, - Thinking: TextualBlock, + Thinking: ThinkingBlock, ToolUse: ToolUseBlock, ToolResult: ToolResultBlock, pub fn deinit(self: *ContentBlock, alloc: Allocator) void { switch (self.*) { - inline else => |*b| b.deinit(alloc), + .Text => |*b| b.deinit(alloc), + .Thinking => |*b| b.deinit(alloc), + .ToolUse => |*b| b.deinit(alloc), + .ToolResult => |*b| b.deinit(alloc), } } }; @@ -175,11 +194,11 @@ test "ContentBlock - Thinking variant" { defer conv.deinit(); try conv.addAssistantMessage(&.{ - .{ .Thinking = try textualBlockFromSlice(allocator, "hmm...") }, + .{ .Thinking = .{ .text = try textualBlockFromSlice(allocator, "hmm...") } }, .{ .Text = try textualBlockFromSlice(allocator, "answer") }, }); try std.testing.expectEqual(@as(usize, 2), conv.messages.items[0].content.items.len); - try std.testing.expectEqualStrings("hmm...", conv.messages.items[0].content.items[0].Thinking.items); + try std.testing.expectEqualStrings("hmm...", conv.messages.items[0].content.items[0].Thinking.text.items); try std.testing.expectEqualStrings("answer", conv.messages.items[0].content.items[1].Text.items); } -- cgit v1.3