From 17a985cb41727b8a1bca4d95f334106c09386040 Mon Sep 17 00:00:00 2001 From: t Date: Sun, 7 Jun 2026 14:57:58 -0600 Subject: Alias Conversation instead of facading it; merge addAssistantMessage A facade that forwards every method 1:1 is worse than paring the real type down to the intended surface and aliasing it. conversation.Conversation's interface is already the public surface we want (init/deinit, the add*/replace* builders, and messages/allocator as plain data fields), so public.zig now aliases it straight through and Agent.conversation() returns a borrowed *Conversation for in-place surgery. Drops the ConversationData alias and the pointer-wrapper. Merged addAssistantMessageWithUsage into addAssistantMessage(blocks, ?usage) on the real type (separate method deleted), so the alias has the intended one-method shape; all call sites updated. Only Agent and Stream remain true facades -- they have genuinely-internal fields plus API-shaping renames (Stream.phase->state, Phase->State) an alias can't express. --- libpanto/src/public.zig | 53 ++++++++++++------------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) (limited to 'libpanto/src/public.zig') diff --git a/libpanto/src/public.zig b/libpanto/src/public.zig index 56a0676..31d5f7b 100644 --- a/libpanto/src/public.zig +++ b/libpanto/src/public.zig @@ -82,43 +82,14 @@ pub const CompactionSummaryBlock = conversation_mod.CompactionSummaryBlock; pub const Usage = conversation_mod.Usage; pub const effectiveSystemBlocks = conversation_mod.effectiveSystemBlocks; -/// The owned conversation value type. This is what `Session.load` returns -/// and what `Agent.init` adopts. Build one standalone with `init` for +/// The conversation type. Aliased straight through: its interface has been +/// pared down to exactly the public surface (constructors `init`/`deinit`, +/// the `add*`/`replace*` builders, and the `messages`/`allocator` data +/// fields), so no façade is needed. This is what `Session.load` returns, +/// what `Agent.init` adopts, and what `Agent.conversation()` borrows a +/// pointer to (for in-place surgery). Build one standalone with `init` for /// by-hand construction; once handed to an `Agent` it is owned by the agent. -/// For *operating on* an agent's live conversation, use the `Conversation` -/// handle (below) via `Agent.conversation()`. -pub const ConversationData = conversation_mod.Conversation; - -/// A borrowed handle onto a conversation owned by an `Agent`. Pointer- -/// wrapping makes the "don't move the conversation" invariant structural: -/// the handle is a cheap copyable view, minted per-call by -/// `Agent.conversation()`, borrowing state owned by its `Agent`. -pub const Conversation = struct { - inner: *conversation_mod.Conversation, - - /// Read the in-memory messages directly, for context-management surgery. - pub fn messages(self: Conversation) []conversation_mod.Message { - return self.inner.messages.items; - } - pub fn addUserMessage(self: Conversation, text: []const u8) !void { - return self.inner.addUserMessage(text); - } - pub fn addAssistantMessage(self: Conversation, blocks: []const ContentBlock, usage: ?Usage) !void { - if (usage) |u| { - return self.inner.addAssistantMessageWithUsage(blocks, u); - } - return self.inner.addAssistantMessage(blocks); - } - pub fn addSystemMessage(self: Conversation, text: []const u8) !void { - return self.inner.addSystemMessage(text); - } - pub fn replaceSystemMessage(self: Conversation, text: []const u8) !void { - return self.inner.replaceSystemMessage(text); - } - pub fn addCompactionSummary(self: Conversation, text: []const u8) !void { - return self.inner.addCompactionSummary(text); - } -}; +pub const Conversation = conversation_mod.Conversation; // =========================================================================== // Tools (data + small façade) @@ -199,7 +170,7 @@ pub const Agent = struct { io: std.Io, config: *const Config, session: Session, - maybe_conversation: ?ConversationData, + maybe_conversation: ?Conversation, ) !Agent { const inner = try allocator.create(agent_mod.Agent); inner.* = agent_mod.Agent.init(allocator, io, config, session, maybe_conversation); @@ -246,9 +217,11 @@ pub const Agent = struct { return self.inner.compactAndPersist(override_system_prompt, extra); } - /// A borrowed handle onto the agent's live conversation. - pub fn conversation(self: Agent) Conversation { - return .{ .inner = &self.inner.conversation }; + /// A borrowed pointer to the agent's live conversation, for in-place + /// context-management surgery. Valid for the agent's lifetime; do not + /// retain past it. + pub fn conversation(self: Agent) *Conversation { + return &self.inner.conversation; } /// The id of the session this agent appends to. -- cgit v1.3