summaryrefslogtreecommitdiff
path: root/libpanto/src/session.zig
diff options
context:
space:
mode:
Diffstat (limited to 'libpanto/src/session.zig')
-rw-r--r--libpanto/src/session.zig35
1 files changed, 26 insertions, 9 deletions
diff --git a/libpanto/src/session.zig b/libpanto/src/session.zig
index 492f94b..843989a 100644
--- a/libpanto/src/session.zig
+++ b/libpanto/src/session.zig
@@ -87,12 +87,14 @@ pub const SessionHeader = struct {
version: u32,
id: []const u8, // UUIDv7 string, owned
timestamp: []const u8, // ISO 8601, owned
- cwd: []const u8, // owned
+ /// Opaque session-wide metadata bag. Round-trips verbatim; `libpanto`
+ /// never interprets it. The panto CLI records `{ "cwd": ... }` here.
+ metadata: ?[]const u8 = null, // owned
pub fn deinit(self: SessionHeader, alloc: Allocator) void {
alloc.free(self.id);
alloc.free(self.timestamp);
- alloc.free(self.cwd);
+ if (self.metadata) |m| alloc.free(m);
}
};
@@ -308,8 +310,12 @@ pub fn serializeHeader(allocator: Allocator, header: SessionHeader) ![]u8 {
try s.write(header.id);
try s.objectField("timestamp");
try s.write(header.timestamp);
- try s.objectField("cwd");
- try s.write(header.cwd);
+ if (header.metadata) |md| {
+ var parsed = try std.json.parseFromSlice(std.json.Value, allocator, md, .{});
+ defer parsed.deinit();
+ try s.objectField("metadata");
+ try s.write(parsed.value);
+ }
try s.endObject();
return try aw.toOwnedSlice();
@@ -568,13 +574,24 @@ fn parseHeaderFromObject(allocator: Allocator, obj: std.json.ObjectMap) ParseErr
errdefer allocator.free(id);
const timestamp = try dupeStringField(allocator, obj, "timestamp");
errdefer allocator.free(timestamp);
- const cwd = try dupeStringField(allocator, obj, "cwd");
- errdefer allocator.free(cwd);
+ const metadata: ?[]const u8 = blk: {
+ if (obj.get("metadata")) |mv| {
+ break :blk try std.json.Stringify.valueAlloc(allocator, mv, .{});
+ }
+ if (obj.get("cwd")) |cv| {
+ if (cv != .string) return error.MissingField;
+ const cwd_json = try std.json.Stringify.valueAlloc(allocator, cv, .{});
+ defer allocator.free(cwd_json);
+ break :blk try std.fmt.allocPrint(allocator, "{{\"cwd\":{s}}}", .{cwd_json});
+ }
+ break :blk null;
+ };
+ errdefer if (metadata) |m| allocator.free(m);
return .{
.version = version,
.id = id,
.timestamp = timestamp,
- .cwd = cwd,
+ .metadata = metadata,
};
}
@@ -956,7 +973,7 @@ test "serialize/parse header round-trip" {
.version = 1,
.id = try dupe(a, "019dc5ba-53f6-71a5-ab8f-b1f8709c2572"),
.timestamp = try dupe(a, "2026-04-25T17:40:15.990Z"),
- .cwd = try dupe(a, "/Users/travis/Code/pantograph"),
+ .metadata = try dupe(a, "{\"cwd\":\"/Users/travis/Code/pantograph\"}"),
};
defer header.deinit(a);
@@ -968,7 +985,7 @@ test "serialize/parse header round-trip" {
try testing.expect(fe == .header);
try testing.expectEqual(@as(u32, 1), fe.header.version);
try testing.expectEqualStrings(header.id, fe.header.id);
- try testing.expectEqualStrings(header.cwd, fe.header.cwd);
+ try testing.expectEqualStrings(header.metadata.?, fe.header.metadata.?);
}
test "serialize/parse user message entry round-trip (with provider/model stamp)" {