diff options
| author | t <t@tjp.lol> | 2026-06-11 09:08:42 -0600 |
|---|---|---|
| committer | t <t@tjp.lol> | 2026-06-11 09:23:28 -0600 |
| commit | e2477f7d2d2a4eab870a2bd61534cfd146907915 (patch) | |
| tree | 197dae8b7476558d7f105d3129778f30b91503e1 /libpanto/src/session.zig | |
| parent | 813ebd014a7614fdcdf4df5570b50944f2626076 (diff) | |
libpanto API fixes
- FSJSONLStore: don't require `cwd`, instead panto CLI provides it in
the session metadata
- Lua: expose the `SessionStore` interface and the `FSJSONLStore` and
`NullStore` implementations
- C: use idiomatic `const char *` for incoming strings
- C: expose the `FSJSONLStore` and `NullStore` implementations
Diffstat (limited to 'libpanto/src/session.zig')
| -rw-r--r-- | libpanto/src/session.zig | 35 |
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)" { |
