diff options
| author | T <t@tjp.lol> | 2026-05-25 21:50:43 -0600 |
|---|---|---|
| committer | T <t@tjp.lol> | 2026-05-25 22:19:44 -0600 |
| commit | f026bb81ae68f516910d0eb4f23c9344dd36b62b (patch) | |
| tree | e091d1a870cc75dc92e6cee785ee78ff4d6f088f /libpanto/src/conversation.zig | |
| parent | df2edee86eec2a8deb0ad57b5d20552199c12b65 (diff) | |
phase 2 done
Diffstat (limited to 'libpanto/src/conversation.zig')
| -rw-r--r-- | libpanto/src/conversation.zig | 27 |
1 files changed, 23 insertions, 4 deletions
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); } |
