summaryrefslogtreecommitdiff
path: root/libawl/src/conversation.zig
diff options
context:
space:
mode:
authorT <t@tjp.lol>2026-05-25 12:19:50 -0700
committerT <t@tjp.lol>2026-05-25 12:39:24 -0700
commite8272efd9f71ad27a0e62b6b3fa3d13e99a6736f (patch)
tree16932c3f947aac908e15b77a71f9db3184e18a5c /libawl/src/conversation.zig
parent52b2ca78aed7950af27d4865aee65da781514a99 (diff)
work
Diffstat (limited to 'libawl/src/conversation.zig')
-rw-r--r--libawl/src/conversation.zig185
1 files changed, 0 insertions, 185 deletions
diff --git a/libawl/src/conversation.zig b/libawl/src/conversation.zig
deleted file mode 100644
index 0e9a4e9..0000000
--- a/libawl/src/conversation.zig
+++ /dev/null
@@ -1,185 +0,0 @@
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-
-/// A streaming text buffer used by content blocks.
-/// Thin alias over ArrayList(u8) — amortized O(1) appends,
-/// no O(n²) re-copying.
-pub const TextualBlock = std.ArrayList(u8);
-
-/// Create a TextualBlock with initial content (copies the slice).
-pub fn textualBlockFromSlice(alloc: Allocator, slice: []const u8) !TextualBlock {
- var buf: TextualBlock = .empty;
- try buf.appendSlice(alloc, slice);
- return buf;
-}
-
-pub const ToolUseBlock = struct {
- id: []const u8,
- name: []const u8,
- input: TextualBlock = .empty,
-
- pub fn deinit(self: *ToolUseBlock, alloc: Allocator) void {
- alloc.free(self.id);
- alloc.free(self.name);
- self.input.deinit(alloc);
- }
-};
-
-pub const ToolResultBlock = struct {
- tool_use_id: []const u8,
- content: TextualBlock = .empty,
-
- pub fn deinit(self: *ToolResultBlock, alloc: Allocator) void {
- alloc.free(self.tool_use_id);
- self.content.deinit(alloc);
- }
-};
-
-pub const ContentBlock = union(enum) {
- Text: TextualBlock,
- Thinking: TextualBlock,
- ToolUse: ToolUseBlock,
- ToolResult: ToolResultBlock,
-
- pub fn deinit(self: *ContentBlock, alloc: Allocator) void {
- switch (self.*) {
- inline else => |*b| b.deinit(alloc),
- }
- }
-};
-
-pub const MessageRole = enum {
- system,
- user,
- assistant,
-};
-
-pub const Message = struct {
- role: MessageRole,
- content: std.ArrayList(ContentBlock) = .empty,
-
- pub fn deinit(self: *Message, alloc: Allocator) void {
- for (self.content.items) |*block| {
- block.deinit(alloc);
- }
- self.content.deinit(alloc);
- }
-};
-
-pub const Conversation = struct {
- messages: std.ArrayList(Message) = .empty,
- allocator: Allocator,
-
- pub fn init(allocator: Allocator) Conversation {
- return .{
- .allocator = allocator,
- };
- }
-
- pub fn addSystemMessage(self: *Conversation, text: []const u8) !void {
- const tb = try textualBlockFromSlice(self.allocator, text);
- var content: std.ArrayList(ContentBlock) = .empty;
- try content.append(self.allocator, .{ .Text = tb });
- try self.messages.append(self.allocator, .{
- .role = .system,
- .content = content,
- });
- }
-
- pub fn addUserMessage(self: *Conversation, text: []const u8) !void {
- const tb = try textualBlockFromSlice(self.allocator, text);
- var content: std.ArrayList(ContentBlock) = .empty;
- try content.append(self.allocator, .{ .Text = tb });
- try self.messages.append(self.allocator, .{
- .role = .user,
- .content = content,
- });
- }
-
- /// Append an assistant message. Ownership of the blocks is transferred
- /// to the conversation; the caller must not deinit them after this call.
- pub fn addAssistantMessage(self: *Conversation, blocks: []const ContentBlock) !void {
- var content: std.ArrayList(ContentBlock) = .empty;
- try content.ensureTotalCapacity(self.allocator, blocks.len);
- for (blocks) |block| {
- content.appendAssumeCapacity(block);
- }
- try self.messages.append(self.allocator, .{
- .role = .assistant,
- .content = content,
- });
- }
-
- pub fn deinit(self: *Conversation) void {
- for (self.messages.items) |*msg| {
- msg.deinit(self.allocator);
- }
- self.messages.deinit(self.allocator);
- }
-};
-
-test "Conversation - add messages and verify content" {
- const allocator = std.testing.allocator;
-
- var conv = Conversation.init(allocator);
- defer conv.deinit();
-
- try conv.addSystemMessage("You are a helpful assistant.");
- try conv.addUserMessage("Hello!");
- try conv.addAssistantMessage(&.{
- .{ .Text = try textualBlockFromSlice(allocator, "Hi there!") },
- });
-
- try std.testing.expectEqual(@as(usize, 3), conv.messages.items.len);
-
- try std.testing.expectEqual(MessageRole.system, conv.messages.items[0].role);
- try std.testing.expectEqualStrings(
- "You are a helpful assistant.",
- conv.messages.items[0].content.items[0].Text.items,
- );
-
- try std.testing.expectEqual(MessageRole.user, conv.messages.items[1].role);
- try std.testing.expectEqualStrings("Hello!", conv.messages.items[1].content.items[0].Text.items);
-
- try std.testing.expectEqual(MessageRole.assistant, conv.messages.items[2].role);
- try std.testing.expectEqualStrings("Hi there!", conv.messages.items[2].content.items[0].Text.items);
-}
-
-test "TextualBlock - incremental append" {
- const allocator = std.testing.allocator;
-
- var tb = TextualBlock.empty;
- defer tb.deinit(allocator);
-
- try tb.appendSlice(allocator, "Hello");
- try tb.appendSlice(allocator, " world");
- try std.testing.expectEqualStrings("Hello world", tb.items);
-}
-
-test "Conversation - deinit frees without leaks" {
- const allocator = std.testing.allocator;
-
- var conv = Conversation.init(allocator);
- try conv.addSystemMessage("system");
- try conv.addUserMessage("user message");
- try conv.addAssistantMessage(&.{
- .{ .Text = try textualBlockFromSlice(allocator, "response") },
- });
- conv.deinit();
-}
-
-test "ContentBlock - Thinking variant" {
- const allocator = std.testing.allocator;
-
- var conv = Conversation.init(allocator);
- defer conv.deinit();
-
- try conv.addAssistantMessage(&.{
- .{ .Thinking = 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("answer", conv.messages.items[0].content.items[1].Text.items);
-}