summaryrefslogtreecommitdiff
path: root/libpanto/src/anthropic_messages_json.zig
diff options
context:
space:
mode:
Diffstat (limited to 'libpanto/src/anthropic_messages_json.zig')
-rw-r--r--libpanto/src/anthropic_messages_json.zig47
1 files changed, 42 insertions, 5 deletions
diff --git a/libpanto/src/anthropic_messages_json.zig b/libpanto/src/anthropic_messages_json.zig
index 46ec17c..5b65c2b 100644
--- a/libpanto/src/anthropic_messages_json.zig
+++ b/libpanto/src/anthropic_messages_json.zig
@@ -64,10 +64,11 @@ pub fn serializeRequest(
if (tools.count() > 0) {
try s.objectField("tools");
try s.beginArray();
- var it = tools.iterator();
+ var it = tools.toolsForLLM();
while (it.next()) |t| {
try s.beginObject();
try s.objectField("name");
+ // `t.decl.name` is already wire-encoded by `toolsForLLM`.
try s.write(t.decl.name);
try s.objectField("description");
try s.write(t.decl.description);
@@ -180,7 +181,9 @@ fn writeBlock(s: *std.json.Stringify, block: conversation.ContentBlock) !void {
try s.objectField("id");
try s.write(tu.id);
try s.objectField("name");
- try s.write(tu.name);
+ // Replayed assistant tool_use: encode the stored dotted name.
+ var name_buf: [tool_registry_mod.max_wire_name_len]u8 = undefined;
+ try s.write(tool_registry_mod.encodeName(&name_buf, tu.name));
try s.objectField("input");
// Anthropic expects `input` as a nested JSON object, not a
// string. The block's input bytes were assembled from
@@ -801,9 +804,7 @@ test "serializeRequest - emits tools array when registry non-empty" {
var tools = tool_registry_mod.ToolRegistry.init(allocator);
defer tools.deinit();
- try tools.register(makeStaticTool(
- "echo",
- "Echo a message back.",
+ try tools.register(makeStaticTool("echo", "Echo a message back.",
\\{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}
));
@@ -824,6 +825,42 @@ test "serializeRequest - emits tools array when registry non-empty" {
try testing.expect(schema.get("properties").? == .object);
}
+test "serializeRequest - dotted names are wire-encoded in tools and history" {
+ const allocator = testing.allocator;
+
+ var conv = conversation.Conversation.init(allocator);
+ defer conv.deinit();
+ // A prior assistant tool_use replayed from history (dotted internally).
+ const id = try allocator.dupe(u8, "tu_1");
+ const name = try allocator.dupe(u8, "std.write");
+ var input: conversation.TextualBlock = .empty;
+ try input.appendSlice(allocator, "{}");
+ try conv.addAssistantMessage(&.{
+ .{ .ToolUse = .{ .id = id, .name = name, .input = input } },
+ });
+
+ var tools = tool_registry_mod.ToolRegistry.init(allocator);
+ defer tools.deinit();
+ try tools.register(makeStaticTool("std.read", "Read.", "{\"type\":\"object\"}"));
+
+ const cfg = testConfig("claude-x");
+ const body = try serializeRequest(allocator, &cfg, &conv, &tools);
+ defer allocator.free(body);
+
+ var parsed = try std.json.parseFromSlice(std.json.Value, allocator, body, .{});
+ defer parsed.deinit();
+
+ // Tool list: `std.read` -> `std__read`.
+ const tool_name = parsed.value.object.get("tools").?.array.items[0]
+ .object.get("name").?.string;
+ try testing.expectEqualStrings("std__read", tool_name);
+
+ // Replayed history tool_use: `std.write` -> `std__write`.
+ const hist_name = parsed.value.object.get("messages").?.array.items[0]
+ .object.get("content").?.array.items[0].object.get("name").?.string;
+ try testing.expectEqualStrings("std__write", hist_name);
+}
+
test "serializeRequest - assistant ToolUse becomes tool_use content block" {
const allocator = testing.allocator;