summaryrefslogtreecommitdiff
path: root/src/system_prompt.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/system_prompt.zig')
-rw-r--r--src/system_prompt.zig107
1 files changed, 57 insertions, 50 deletions
diff --git a/src/system_prompt.zig b/src/system_prompt.zig
index 500b135..39c3ea8 100644
--- a/src/system_prompt.zig
+++ b/src/system_prompt.zig
@@ -137,7 +137,7 @@ pub fn seedFresh(
io: Io,
environ_map: *const std.process.Environ.Map,
base_dir: []const u8,
- agent: *panto.agent.Agent,
+ agent: panto.Agent,
) !void {
const user_dir = try userLayerDir(arena, environ_map);
const project_dir = try projectLayerDir(arena, io);
@@ -151,13 +151,13 @@ pub fn seedFreshLayers(
base_dir: ?[]const u8,
user_dir: ?[]const u8,
project_dir: ?[]const u8,
- agent: *panto.agent.Agent,
+ agent: panto.Agent,
) !void {
const resolved = try resolveLayers(arena, io, base_dir, user_dir, project_dir);
const blocks = try resolved.blocks(arena);
for (blocks) |text| {
// The agent adds to its conversation and persists the entry.
- try agent.addSystemMessage(text, .append);
+ try agent.addSystemMessage(text);
}
}
@@ -174,7 +174,7 @@ pub fn reconcileResume(
io: Io,
environ_map: *const std.process.Environ.Map,
base_dir: []const u8,
- agent: *panto.agent.Agent,
+ agent: panto.Agent,
) !void {
const user_dir = try userLayerDir(arena, environ_map);
const project_dir = try projectLayerDir(arena, io);
@@ -188,21 +188,21 @@ pub fn reconcileResumeLayers(
base_dir: ?[]const u8,
user_dir: ?[]const u8,
project_dir: ?[]const u8,
- agent: *panto.agent.Agent,
+ agent: panto.Agent,
) !void {
const resolved = try resolveLayers(arena, io, base_dir, user_dir, project_dir);
const config_blocks = try resolved.blocks(arena);
- const window = try effectiveConfigWindow(arena, agent.conversation.messages.items);
+ const window = try effectiveConfigWindow(arena, agent.conversation().messages());
if (blocksEqual(config_blocks, window)) return;
- // Re-seed: one `replace` for the seed, then one `append` per append.
- // The agent adds to its conversation and persists each entry (with the
- // correct system mode).
- try agent.addSystemMessage(config_blocks[0], .replace);
+ // Re-seed: one `setSystemPrompt` (replace) for the seed, then one
+ // `addSystemMessage` (append) per append. The agent adds to its
+ // conversation and persists each entry (with the correct system mode).
+ try agent.setSystemPrompt(config_blocks[0]);
for (config_blocks[1..]) |text| {
- try agent.addSystemMessage(text, .append);
+ try agent.addSystemMessage(text);
}
}
@@ -339,7 +339,7 @@ test "blocksEqual - length and content" {
test "effectiveConfigWindow - no replace anchors to leading system blocks" {
const alloc = testing.allocator;
- var conv = panto.conversation.Conversation.init(alloc);
+ var conv = panto.ConversationData.init(alloc);
defer conv.deinit();
try conv.addSystemMessage("seed");
@@ -357,7 +357,7 @@ test "effectiveConfigWindow - no replace anchors to leading system blocks" {
test "effectiveConfigWindow - anchors to last replace block" {
const alloc = testing.allocator;
- var conv = panto.conversation.Conversation.init(alloc);
+ var conv = panto.ConversationData.init(alloc);
defer conv.deinit();
try conv.addSystemMessage("old seed");
@@ -473,38 +473,45 @@ fn openTmpStore(arena: Allocator, root: []const u8) !panto.FileSystemJSONLStore
/// harness only holds the config to keep the agent's borrowed pointer valid.
const SPAgentHarness = struct {
config: panto.Config,
- agent: panto.agent.Agent,
+ agent: panto.Agent,
+ /// A second handle onto the same session (a copyable value proxying to
+ /// the same store + id) so the test can `forceFlush` without reaching
+ /// agent internals. `session_id` mirrors the agent's session id.
+ session: panto.Session,
+ session_id: []const u8,
fn init(
self: *SPAgentHarness,
session: panto.Session,
- adopted: ?panto.conversation.Conversation,
- ) void {
+ adopted: ?panto.ConversationData,
+ ) !void {
self.config = .{
.provider = .{ .openai_chat = .{ .api_key = "k", .base_url = "u", .model = "m" } },
};
- self.agent = panto.agent.Agent.init(testing.allocator, testing.io, &self.config, session, adopted);
+ self.session = session;
+ self.session_id = session.info.id;
+ self.agent = try panto.Agent.init(testing.allocator, testing.io, &self.config, session, adopted);
}
fn deinit(self: *SPAgentHarness) void {
self.agent.deinit();
}
-};
-/// Force the session to flush to disk by appending an assistant message
-/// through the agent's session. (System/user messages buffer in memory
-/// until the first assistant message; a realistic resume only sees what a
-/// completed turn persisted.)
-fn forceFlush(agent: *panto.agent.Agent) !void {
- var conv = panto.conversation.Conversation.init(testing.allocator);
- defer conv.deinit();
- try conv.addAssistantMessage(&.{});
- const id: panto.WireIdentity = .{ .api_style = .openai_chat, .base_url = "u", .model = "m" };
- var batch = [_]panto.PersistentMessage{
- .{ .message = conv.messages.items[0], .identity = id },
- };
- try agent.session.append(&batch);
-}
+ /// Force the session to flush to disk by appending an assistant message
+ /// through the (shared) session handle. (System/user messages buffer in
+ /// memory until the first assistant message; a realistic resume only
+ /// sees what a completed turn persisted.)
+ fn forceFlush(self: *SPAgentHarness) !void {
+ var conv = panto.ConversationData.init(testing.allocator);
+ defer conv.deinit();
+ try conv.addAssistantMessage(&.{});
+ const id: panto.WireIdentity = .{ .api_style = .openai_chat, .base_url = "u", .model = "m" };
+ var batch = [_]panto.PersistentMessage{
+ .{ .message = conv.messages.items[0], .identity = id },
+ };
+ try self.session.append(&batch);
+ }
+};
test "seedFresh then no-config-change resume is a no-op" {
const alloc = testing.allocator;
@@ -526,12 +533,12 @@ test "seedFresh then no-config-change resume is a no-op" {
var session_id_len: usize = 0;
{
var h: SPAgentHarness = undefined;
- h.init(store.create(), null);
+ try h.init(store.create(), null);
defer h.deinit();
- try seedFreshLayers(arena, testing.io, null, null, project_dir, &h.agent);
- try forceFlush(&h.agent); // persist seed (+ assistant) to disk
- @memcpy(session_id_buf[0..h.agent.session.info.id.len], h.agent.session.info.id);
- session_id_len = h.agent.session.info.id.len;
+ try seedFreshLayers(arena, testing.io, null, null, project_dir, h.agent);
+ try h.forceFlush(); // persist seed (+ assistant) to disk
+ @memcpy(session_id_buf[0..h.session_id.len], h.session_id);
+ session_id_len = h.session_id.len;
}
const session_id = session_id_buf[0..session_id_len];
@@ -547,10 +554,10 @@ test "seedFresh then no-config-change resume is a no-op" {
var sess2 = (try store.resolve(session_id)).?;
const conv2 = try sess2.load();
var h2: SPAgentHarness = undefined;
- h2.init(sess2, conv2);
+ try h2.init(sess2, conv2);
defer h2.deinit();
- try reconcileResumeLayers(arena, testing.io, null, null, project_dir, &h2.agent);
- const eff_after = try panto.effectiveSystemBlocks(arena, h2.agent.conversation.messages.items);
+ try reconcileResumeLayers(arena, testing.io, null, null, project_dir, h2.agent);
+ const eff_after = try panto.effectiveSystemBlocks(arena, h2.agent.conversation().messages());
try testing.expectEqual(seeded_count, eff_after.items.len);
}
@@ -572,12 +579,12 @@ test "resume after config change appends replace + append sequence" {
var session_id_len: usize = 0;
{
var h: SPAgentHarness = undefined;
- h.init(store.create(), null);
+ try h.init(store.create(), null);
defer h.deinit();
- try seedFreshLayers(arena, testing.io, null, null, project_dir, &h.agent);
- try forceFlush(&h.agent); // persist old seed (+ assistant) to disk
- @memcpy(session_id_buf[0..h.agent.session.info.id.len], h.agent.session.info.id);
- session_id_len = h.agent.session.info.id.len;
+ try seedFreshLayers(arena, testing.io, null, null, project_dir, h.agent);
+ try h.forceFlush(); // persist old seed (+ assistant) to disk
+ @memcpy(session_id_buf[0..h.session_id.len], h.session_id);
+ session_id_len = h.session_id.len;
}
const session_id = session_id_buf[0..session_id_len];
@@ -588,20 +595,20 @@ test "resume after config change appends replace + append sequence" {
var sess2 = (try store.resolve(session_id)).?;
const conv2 = try sess2.load();
var h2: SPAgentHarness = undefined;
- h2.init(sess2, conv2);
+ try h2.init(sess2, conv2);
defer h2.deinit();
- try reconcileResumeLayers(arena, testing.io, null, null, project_dir, &h2.agent);
+ try reconcileResumeLayers(arena, testing.io, null, null, project_dir, h2.agent);
// The effective prompt now reflects only the new config blocks.
- const eff = try panto.effectiveSystemBlocks(arena, h2.agent.conversation.messages.items);
+ const eff = try panto.effectiveSystemBlocks(arena, h2.agent.conversation().messages());
try testing.expectEqual(@as(usize, 2), eff.items.len);
try testing.expectEqualStrings("new seed", eff.items[0]);
try testing.expectEqualStrings("new append", eff.items[1]);
// A second no-op resume must not change the effective prompt (anchors
// to the new `replace` window, not the stale original seed).
- try reconcileResumeLayers(arena, testing.io, null, null, project_dir, &h2.agent);
- const eff2 = try panto.effectiveSystemBlocks(arena, h2.agent.conversation.messages.items);
+ try reconcileResumeLayers(arena, testing.io, null, null, project_dir, h2.agent);
+ const eff2 = try panto.effectiveSystemBlocks(arena, h2.agent.conversation().messages());
try testing.expectEqual(@as(usize, 2), eff2.items.len);
}