summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command.zig4
-rw-r--r--src/extension_loader.zig4
-rw-r--r--src/lua_bridge.zig33
-rw-r--r--src/lua_runtime.zig16
-rw-r--r--src/main.zig2
-rw-r--r--src/system_prompt.zig18
6 files changed, 39 insertions, 38 deletions
diff --git a/src/command.zig b/src/command.zig
index 0f6fb01..588490c 100644
--- a/src/command.zig
+++ b/src/command.zig
@@ -33,9 +33,9 @@ pub const Context = struct {
allocator: std.mem.Allocator,
/// The active agent (a copyable public handle). Commands reach the
- /// conversation via `agent.conversation()` and compact via
+ /// conversation via `agent.conversation` and compact via
/// `agent.compact(...)`.
- agent: panto.Agent,
+ agent: *panto.Agent,
/// REPL output writer and its backing file writer (for flushing).
stdout: *std.Io.Writer,
diff --git a/src/extension_loader.zig b/src/extension_loader.zig
index ff49022..6d74559 100644
--- a/src/extension_loader.zig
+++ b/src/extension_loader.zig
@@ -495,7 +495,7 @@ const testing = std.testing;
fn xokText(result: panto.ToolCallResult) []const u8 {
switch (result) {
.ok => |parts| {
- for (parts) |p| {
+ for (parts.items) |p| {
if (p == .text) return p.text;
}
return "";
@@ -507,7 +507,7 @@ fn xokText(result: panto.ToolCallResult) []const u8 {
/// Test helper: free a results slice (parts on `.ok`).
fn xfreeResults(results: []panto.ToolCallResult) void {
for (results) |r| switch (r) {
- .ok => |b| (panto.ResultParts{ .items = b }).deinit(testing.allocator),
+ .ok => |b| b.deinit(testing.allocator),
.err => {},
};
}
diff --git a/src/lua_bridge.zig b/src/lua_bridge.zig
index 444cedc..9276e1d 100644
--- a/src/lua_bridge.zig
+++ b/src/lua_bridge.zig
@@ -262,7 +262,7 @@ pub fn pushJsonAsLua(
}
/// Read a tool handler's return value at `idx` and convert it into an
-/// owned `[]panto.ResultPart`. Two accepted shapes:
+/// owned `panto.ResultParts`. Two accepted shapes:
///
/// * a plain string -> one `.text` part;
/// * a table `{ text = "...", attachments = { { media_type = "...",
@@ -275,14 +275,14 @@ pub fn readHandlerResult(
L: *c.lua_State,
idx: c_int,
allocator: Allocator,
-) BridgeError![]panto.ResultPart {
+) BridgeError!panto.ResultParts {
const ty = c.lua_type(L, idx);
if (ty == T_STRING) {
var len: usize = 0;
const ptr = c.lua_tolstring(L, idx, &len);
if (ptr == null) return BridgeError.BadHandlerReturn;
- return ((panto.ResultParts.fromText(allocator, ptr[0..len]) catch
- return BridgeError.OutOfMemory).items);
+ return panto.ResultParts.fromText(allocator, ptr[0..len]) catch
+ return BridgeError.OutOfMemory;
}
if (ty != T_TABLE) return BridgeError.BadHandlerReturn;
return readHandlerResultTable(L, idx, allocator);
@@ -315,7 +315,7 @@ fn readHandlerResultTable(
L: *c.lua_State,
idx: c_int,
allocator: Allocator,
-) BridgeError![]panto.ResultPart {
+) BridgeError!panto.ResultParts {
var parts: std.ArrayList(panto.ResultPart) = .empty;
errdefer {
for (parts.items) |p| p.deinit(allocator);
@@ -372,7 +372,8 @@ fn readHandlerResultTable(
}
}
- return parts.toOwnedSlice(allocator) catch BridgeError.OutOfMemory;
+ const items = parts.toOwnedSlice(allocator) catch return BridgeError.OutOfMemory;
+ return .{ .items = items };
}
// ---------------------------------------------------------------------------
@@ -796,9 +797,9 @@ test "handler invocation: input parsed, result captured" {
}
const result = try readHandlerResult(L, -1, std.testing.allocator);
- defer (panto.ResultParts{ .items = result }).deinit(std.testing.allocator);
- try std.testing.expectEqual(@as(usize, 1), result.len);
- try std.testing.expectEqualStrings("got: hello", result[0].text);
+ defer result.deinit(std.testing.allocator);
+ try std.testing.expectEqual(@as(usize, 1), result.items.len);
+ try std.testing.expectEqualStrings("got: hello", result.items[0].text);
}
test "readHandlerResult: table with text and attachments" {
@@ -821,13 +822,13 @@ test "readHandlerResult: table with text and attachments" {
}
const result = try readHandlerResult(L, -1, std.testing.allocator);
- defer (panto.ResultParts{ .items = result }).deinit(std.testing.allocator);
- try std.testing.expectEqual(@as(usize, 3), result.len);
- try std.testing.expectEqualStrings("see image", result[0].text);
- try std.testing.expectEqualStrings("image/png", result[1].media.media_type.?);
- try std.testing.expectEqualStrings("AAA=", result[1].media.data);
- try std.testing.expectEqualStrings("application/pdf", result[2].media.media_type.?);
- try std.testing.expectEqualStrings("BBB=", result[2].media.data);
+ defer result.deinit(std.testing.allocator);
+ try std.testing.expectEqual(@as(usize, 3), result.items.len);
+ try std.testing.expectEqualStrings("see image", result.items[0].text);
+ try std.testing.expectEqualStrings("image/png", result.items[1].media.media_type.?);
+ try std.testing.expectEqualStrings("AAA=", result.items[1].media.data);
+ try std.testing.expectEqualStrings("application/pdf", result.items[2].media.media_type.?);
+ try std.testing.expectEqualStrings("BBB=", result.items[2].media.data);
}
test "handler crash: error message surfaces via xpcall traceback hook" {
diff --git a/src/lua_runtime.zig b/src/lua_runtime.zig
index c15ee63..eb760f8 100644
--- a/src/lua_runtime.zig
+++ b/src/lua_runtime.zig
@@ -550,7 +550,7 @@ const Slot = struct {
ok: bool = false,
/// Result payload as owned parts. Allocated from `allocator`.
/// Caller frees via `panto.ResultParts.deinit`.
- value: ?[]panto.ResultPart = null,
+ value: ?panto.ResultParts = null,
/// On `ok = false`, an owned copy of the error message.
err_msg: ?[]u8 = null,
};
@@ -703,11 +703,11 @@ fn runBatch(
continue;
}
if (slot.ok) {
- results[i] = .{ .ok = slot.value orelse (try panto.ResultParts.fromText(allocator, "")).items };
+ results[i] = .{ .ok = slot.value orelse try panto.ResultParts.fromText(allocator, "") };
// Free the err_msg if both ended up set somehow.
if (slot.err_msg) |m| allocator.free(m);
} else {
- if (slot.value) |v| (panto.ResultParts{ .items = v }).deinit(allocator);
+ if (slot.value) |v| v.deinit(allocator);
std.log.warn(
"panto-lua: tool '{s}' failed: {s}",
.{
@@ -734,13 +734,13 @@ fn formatToolError(
allocator: Allocator,
tool_name: []const u8,
message: []const u8,
-) ![]panto.ResultPart {
+) !panto.ResultParts {
const text = try std.fmt.allocPrint(
allocator,
"panto-lua: tool '{s}' failed: {s}",
.{ tool_name, message },
);
- return (try panto.ResultParts.fromTextOwned(allocator, text)).items;
+ return panto.ResultParts.fromTextOwned(allocator, text);
}
/// Start one coroutine: create a thread under the runtime's lua_State,
@@ -848,7 +848,7 @@ fn invokeCoroutineSync(
input: []const u8,
allocator: Allocator,
err_msg_out: *?[]u8,
-) ![]panto.ResultPart {
+) !panto.ResultParts {
const co = c.lua_newthread(L) orelse return RuntimeError.LuaInitFailed;
defer c.lua_settop(L, c.lua_gettop(L) - 1);
@@ -1065,7 +1065,7 @@ const testing = std.testing;
fn okText(result: panto.ToolCallResult) []const u8 {
switch (result) {
.ok => |parts| {
- for (parts) |p| {
+ for (parts.items) |p| {
if (p == .text) return p.text;
}
return "";
@@ -1077,7 +1077,7 @@ fn okText(result: panto.ToolCallResult) []const u8 {
/// Test helper: free a results slice (parts on `.ok`).
fn freeResults(results: []panto.ToolCallResult) void {
for (results) |r| switch (r) {
- .ok => |b| (panto.ResultParts{ .items = b }).deinit(testing.allocator),
+ .ok => |b| b.deinit(testing.allocator),
.err => {},
};
}
diff --git a/src/main.zig b/src/main.zig
index a4d524b..2a1de27 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -144,7 +144,7 @@ const CLIRenderer = struct {
/// it terminates (`turn_complete` → `next()` returns null). A failure
/// surfaces as the error from `next()`; the caller renders it. The stream is
/// always `deinit`ed (persisting the turn tail) on every exit path.
-fn driveTurn(agent: panto.Agent, message: panto.UserMessage, renderer: *CLIRenderer) !void {
+fn driveTurn(agent: *panto.Agent, message: panto.UserMessage, renderer: *CLIRenderer) !void {
var stream = try agent.run(message);
defer stream.deinit();
while (try stream.next()) |ev| try renderer.render(ev);
diff --git a/src/system_prompt.zig b/src/system_prompt.zig
index eea0b97..6676442 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: *panto.Agent,
) !void {
const user_dir = try userLayerDir(arena, environ_map);
const project_dir = try projectLayerDir(arena, io);
@@ -151,7 +151,7 @@ pub fn seedFreshLayers(
base_dir: ?[]const u8,
user_dir: ?[]const u8,
project_dir: ?[]const u8,
- agent: panto.Agent,
+ agent: *panto.Agent,
) !void {
const resolved = try resolveLayers(arena, io, base_dir, user_dir, project_dir);
const blocks = try resolved.blocks(arena);
@@ -174,7 +174,7 @@ pub fn reconcileResume(
io: Io,
environ_map: *const std.process.Environ.Map,
base_dir: []const u8,
- agent: panto.Agent,
+ agent: *panto.Agent,
) !void {
const user_dir = try userLayerDir(arena, environ_map);
const project_dir = try projectLayerDir(arena, io);
@@ -188,12 +188,12 @@ pub fn reconcileResumeLayers(
base_dir: ?[]const u8,
user_dir: ?[]const u8,
project_dir: ?[]const u8,
- agent: panto.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.items);
if (blocksEqual(config_blocks, window)) return;
@@ -473,7 +473,7 @@ 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: *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.
@@ -557,7 +557,7 @@ test "seedFresh then no-config-change resume is a no-op" {
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);
+ const eff_after = try panto.effectiveSystemBlocks(arena, h2.agent.conversation.messages.items);
try testing.expectEqual(seeded_count, eff_after.items.len);
}
@@ -600,7 +600,7 @@ test "resume after config change appends replace + append sequence" {
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.items);
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]);
@@ -608,7 +608,7 @@ test "resume after config change appends replace + append sequence" {
// 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);
+ const eff2 = try panto.effectiveSystemBlocks(arena, h2.agent.conversation.messages.items);
try testing.expectEqual(@as(usize, 2), eff2.items.len);
}