summaryrefslogtreecommitdiff
path: root/libpanto/src/conversation.zig
diff options
context:
space:
mode:
authorT <t@tjp.lol>2026-05-25 21:50:43 -0600
committerT <t@tjp.lol>2026-05-25 22:19:44 -0600
commitf026bb81ae68f516910d0eb4f23c9344dd36b62b (patch)
treee091d1a870cc75dc92e6cee785ee78ff4d6f088f /libpanto/src/conversation.zig
parentdf2edee86eec2a8deb0ad57b5d20552199c12b65 (diff)
phase 2 done
Diffstat (limited to 'libpanto/src/conversation.zig')
-rw-r--r--libpanto/src/conversation.zig27
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);
}