From bb85e867bc938138f29fb45230169af1ba60761c Mon Sep 17 00:00:00 2001 From: t Date: Wed, 10 Jun 2026 10:06:07 -0600 Subject: Add addUserText helper; update all call sites Conversation.addUserMessage now takes a []ContentBlock (symmetric with addAssistantMessage). Introduce a thin addUserText wrapper in agent.zig for the plain-text case and update every call site in agent.zig and anthropic_messages_json.zig accordingly. --- src/luarocks_runtime.zig | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'src/luarocks_runtime.zig') diff --git a/src/luarocks_runtime.zig b/src/luarocks_runtime.zig index e652096..7f01c19 100644 --- a/src/luarocks_runtime.zig +++ b/src/luarocks_runtime.zig @@ -38,6 +38,7 @@ const panto_home = @import("panto_home.zig"); const embedded_luarocks = @import("embedded_luarocks"); const embedded_lua_headers = @import("embedded_lua_headers"); const embedded_agent = @import("embedded_agent"); +const embedded_panto_so = @import("embedded_panto_so"); const lua_bridge = @import("lua_bridge.zig"); const c = lua_bridge.c; @@ -137,6 +138,7 @@ pub fn bootstrap( try panto_home.ensureDirsExist(layout, io); try stageLuaHeaders(allocator, io, layout); try stageAgentTree(allocator, io, layout); + try stagePantoModule(allocator, io, layout); try stageDefaultConfig(allocator, io, layout); const lua_wrapper_path = try writeLuaWrapper(allocator, io, layout, panto_executable_path); defer allocator.free(lua_wrapper_path); @@ -202,6 +204,33 @@ fn stageLuaHeaders( } } +// --------------------------------------------------------------------------- +// Stage the embedded native `panto.so` +// --------------------------------------------------------------------------- + +/// Write the binary-embedded `libpanto-lua` shared object to +/// `/lib/lua//panto.so`, which is already on `package.cpath` +/// (see `configurePackagePaths`). This guarantees the embedded VM's +/// `require('panto')` resolves to the native agent/stream module on a +/// cold, network-less machine — the module is *ours* and version-locked +/// to this binary's Lua, so unlike luv it cannot be fetched from luarocks. +/// +/// The `.so` leaves `lua_*` undefined and resolves them against the host +/// binary at `dlopen` time, identical to how a luarocks-installed C rock +/// (e.g. luv) works — `exe.rdynamic = true` keeps those symbols findable. +/// +/// Uses the same `writeIfDifferent` discipline as `stageLuaHeaders` so an +/// unchanged `.so` keeps its on-disk mtime across reruns. +fn stagePantoModule( + allocator: Allocator, + io: Io, + layout: panto_home.Layout, +) !void { + var dir = try Io.Dir.cwd().openDir(io, layout.lib_lua_dir, .{}); + defer dir.close(io); + try writeIfDifferent(allocator, io, dir, "panto.so", embedded_panto_so.bytes); +} + // --------------------------------------------------------------------------- // Stage the embedded `agent/` tree // --------------------------------------------------------------------------- @@ -311,11 +340,20 @@ fn writeIfDifferent( name: []const u8, contents: []const u8, ) !void { - if (dir.readFileAlloc(io, name, allocator, .limited(1 << 22))) |existing| { + // Size the read limit to the new content (plus a small margin) so it + // never truncates the comparison — staged files range from tiny + // headers to a multi-megabyte `panto.so`. A larger on-disk file can't + // match `contents` anyway, so capping at `contents.len + 1` is enough + // to detect inequality without reading unbounded bytes. + const limit = contents.len + 1; + if (dir.readFileAlloc(io, name, allocator, .limited(limit))) |existing| { defer allocator.free(existing); if (std.mem.eql(u8, existing, contents)) return; } else |err| switch (err) { error.FileNotFound => {}, + // A file larger than our limit definitionally differs from + // `contents`; fall through and rewrite. + error.StreamTooLong => {}, else => return err, } try dir.writeFile(io, .{ .sub_path = name, .data = contents }); -- cgit v1.3