diff options
Diffstat (limited to 'libpanto')
| -rw-r--r-- | libpanto/src/agent.zig | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/libpanto/src/agent.zig b/libpanto/src/agent.zig index 3616ab6..09b0994 100644 --- a/libpanto/src/agent.zig +++ b/libpanto/src/agent.zig @@ -270,6 +270,13 @@ pub const Agent = struct { /// rewound by `rewriteWithSummary` so a compaction re-persists its summary /// + restated suffix. _persisted_through: usize = 0, + /// User-message blocks queued by an embedder seam (the CLI's + /// `panto.ext.agent:submit`) for the host front end to open the next + /// turn with, so the turn runs on the host's own driver (rendering, + /// interrupts) rather than inside the queuing callback. Blocks and the + /// list storage are owned by `conversation.allocator` — the same + /// ownership `run` adopts. + _pending_submission: std.ArrayList(conversation.ContentBlock) = .empty, /// Construct an agent. /// @@ -311,6 +318,8 @@ pub const Agent = struct { // self-heap-pinned (`init` allocated it), so it frees itself last. const allocator = self._allocator; self._registry.deinit(); + for (self._pending_submission.items) |*b| b.deinit(self.conversation.allocator); + self._pending_submission.deinit(self.conversation.allocator); self.conversation.deinit(); self._session.info.deinit(allocator); allocator.destroy(self); @@ -454,6 +463,22 @@ pub const Agent = struct { /// The agent re-reads its `config` snapshot at the top of each provider /// response inside the stream, so a mid-conversation `setConfig` takes /// effect at the next response boundary, never mid-stream. + /// Append blocks to the pending submission (see `_pending_submission`). + /// Adopts the block *contents*; the `blocks` slice itself stays the + /// caller's. Multiple calls accumulate into one pending user message. + pub fn queueSubmission(self: *Agent, blocks: []const conversation.ContentBlock) !void { + try self._pending_submission.appendSlice(self.conversation.allocator, blocks); + } + + /// Take the pending submission, or null when none is queued. The caller + /// owns the returned slice: typically hand it to `run` (which adopts the + /// block contents) and free the slice itself with + /// `conversation.allocator`. + pub fn takeSubmission(self: *Agent) !?[]conversation.ContentBlock { + if (self._pending_submission.items.len == 0) return null; + return try self._pending_submission.toOwnedSlice(self.conversation.allocator); + } + pub fn run(self: *Agent, message: UserMessage) !*Stream { self._auto_compacted = false; |
