summaryrefslogtreecommitdiff
path: root/libpanto/src/conversation.zig
diff options
context:
space:
mode:
Diffstat (limited to 'libpanto/src/conversation.zig')
-rw-r--r--libpanto/src/conversation.zig49
1 files changed, 47 insertions, 2 deletions
diff --git a/libpanto/src/conversation.zig b/libpanto/src/conversation.zig
index 780f650..2c29f8e 100644
--- a/libpanto/src/conversation.zig
+++ b/libpanto/src/conversation.zig
@@ -41,13 +41,58 @@ pub const ToolUseBlock = struct {
}
};
+/// A binary attachment stored in a tool result. `media_type` is owned
+/// (e.g. "image/png"); `data` is the streaming text buffer holding
+/// base64-encoded bytes.
+pub const StoredMediaPart = struct {
+ media_type: []const u8,
+ data: TextualBlock = .empty,
+
+ pub fn deinit(self: *StoredMediaPart, alloc: Allocator) void {
+ alloc.free(self.media_type);
+ self.data.deinit(alloc);
+ }
+};
+
+/// One part of a tool result as stored in the conversation. Text uses the
+/// streaming `TextualBlock` form to preserve incremental-append semantics.
+pub const ResultPartStored = union(enum) {
+ text: TextualBlock,
+ media: StoredMediaPart,
+
+ pub fn deinit(self: *ResultPartStored, alloc: Allocator) void {
+ switch (self.*) {
+ .text => |*t| t.deinit(alloc),
+ .media => |*m| m.deinit(alloc),
+ }
+ }
+};
+
pub const ToolResultBlock = struct {
tool_use_id: []const u8,
- content: TextualBlock = .empty,
+ parts: std.ArrayList(ResultPartStored) = .empty,
pub fn deinit(self: *ToolResultBlock, alloc: Allocator) void {
alloc.free(self.tool_use_id);
- self.content.deinit(alloc);
+ for (self.parts.items) |*p| p.deinit(alloc);
+ self.parts.deinit(alloc);
+ }
+
+ /// Concatenate all text parts into `out`. Media parts are skipped.
+ /// Used by callers (compaction, OpenAI fan-out) that want only the
+ /// textual portion.
+ pub fn appendTextInto(self: ToolResultBlock, alloc: Allocator, out: *TextualBlock) !void {
+ for (self.parts.items) |p| {
+ if (p == .text) try out.appendSlice(alloc, p.text.items);
+ }
+ }
+
+ /// True if any part is a media attachment.
+ pub fn hasMedia(self: ToolResultBlock) bool {
+ for (self.parts.items) |p| {
+ if (p == .media) return true;
+ }
+ return false;
}
};