From 9c64a7d4462a11674e2dea481b037b5f5d9c62fc Mon Sep 17 00:00:00 2001 From: t Date: Tue, 2 Jun 2026 09:02:49 -0600 Subject: system prompt building and logging --- src/main.zig | 58 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index aaf86b5..20686eb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -11,6 +11,7 @@ const session_paths = @import("session_paths.zig"); const models_toml = @import("models_toml.zig"); const config_file = @import("config_file.zig"); const glob = @import("glob.zig"); +const system_prompt = @import("system_prompt.zig"); // Shorthand alias for the Lua C API. The bridge module owns the actual // `@cImport`; we re-use it here so the smoke check uses identical types. @@ -37,6 +38,7 @@ test { _ = models_toml; _ = config_file; _ = glob; + _ = system_prompt; } const Receiver = panto.provider.Receiver; @@ -363,20 +365,18 @@ pub fn main(init: std.process.Init) !void { var conv = panto.conversation.Conversation.init(alloc); defer conv.deinit(); - if (session_mgr.getEntries().len > 0) { + const is_resume = session_mgr.getEntries().len > 0; + if (is_resume) { // Resumed an existing session — rebuild the conversation from the - // log. The system prompt is part of the log. + // log. The system prompt is part of the log. (Reconciliation + // against the on-disk SYSTEM.md happens after the agent tree is + // staged, below.) conv.deinit(); conv = try session_mgr.rebuildConversation(); try stdout.print( "resumed session {s} ({d} entries)\n", .{ session_mgr.getSessionId()[0..@min(8, session_mgr.getSessionId().len)], session_mgr.getEntries().len }, ); - } else { - // Fresh session — install the default system prompt and record it. - const system_text = "You are a helpful assistant."; - try conv.addSystemMessage(system_text); - try appendSystemToSession(alloc, &session_mgr, system_text); } // The tool registry is owned here and referenced by the active config @@ -405,6 +405,36 @@ pub fn main(init: std.process.Init) !void { ); defer luarocks_rt.deinit(); + // Source the system prompt now that the base agent tree has been + // staged to `$PANTO_HOME/agent` (the bootstrap above writes the + // bundled `SYSTEM.md` there). The prompt is sourced by convention + // from SYSTEM.md / APPEND_SYSTEM.md across the base/user/project + // layers; the base layer is `luarocks_rt.layout.agent_dir`. + var sp_arena = std.heap.ArenaAllocator.init(alloc); + defer sp_arena.deinit(); + if (is_resume) { + // SYSTEM.md / APPEND_SYSTEM.md may have changed since this log was + // created; reconcile without rewriting history. + try system_prompt.reconcileResume( + sp_arena.allocator(), + io, + init.environ_map, + luarocks_rt.layout.agent_dir, + &conv, + &session_mgr, + ); + } else { + // Fresh session — source and install the system prompt. + try system_prompt.seedFresh( + sp_arena.allocator(), + io, + init.environ_map, + luarocks_rt.layout.agent_dir, + &conv, + &session_mgr, + ); + } + // luv is installed (or already present) at this point; wire the // libuv-driven coroutine scheduler before any extensions get a // chance to register tools that might want to yield. @@ -637,20 +667,6 @@ fn openSession( // Session append helpers — bridge in-memory ContentBlocks to on-disk entries. // ----------------------------------------------------------------------------- -fn appendSystemToSession( - alloc: std.mem.Allocator, - mgr: *panto.session_manager.SessionManager, - text: []const u8, -) !void { - const blocks = try alloc.alloc(panto.session_manager.DiskContentBlock, 1); - blocks[0] = .{ .text = .{ .text = try alloc.dupe(u8, text) } }; - _ = try mgr.appendMessage( - .{ .role = .system, .content = blocks }, - null, - null, - ); -} - fn appendUserPromptToSession( alloc: std.mem.Allocator, mgr: *panto.session_manager.SessionManager, -- cgit v1.3