diff options
Diffstat (limited to 'libpanto/src/openai_chat_json.zig')
| -rw-r--r-- | libpanto/src/openai_chat_json.zig | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/libpanto/src/openai_chat_json.zig b/libpanto/src/openai_chat_json.zig index 37d347b..6991559 100644 --- a/libpanto/src/openai_chat_json.zig +++ b/libpanto/src/openai_chat_json.zig @@ -117,7 +117,7 @@ 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("type"); @@ -125,6 +125,7 @@ pub fn serializeRequest( try s.objectField("function"); 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); @@ -261,7 +262,11 @@ fn writeMessage(s: *std.json.Stringify, msg: conversation.Message, allocator: Al try s.objectField("function"); try s.beginObject(); try s.objectField("name"); - try s.write(tu.name); + // Replayed assistant tool_use. The conversation stores the + // internal (dotted) name; encode `.` -> `__` so it matches + // what we advertise in `tools`. + 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("arguments"); // `arguments` is a string carrying JSON, per the OpenAI // wire format — not a nested object. @@ -664,9 +669,7 @@ test "serializeRequest - emits tools array when registry non-empty" { var tools = emptyTools(); 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"]} )); @@ -691,6 +694,29 @@ test "serializeRequest - emits tools array when registry non-empty" { try testing.expect(params.get("required").? == .array); } +test "serializeRequest - dotted tool name is wire-encoded with __" { + const allocator = testing.allocator; + + var conv = conversation.Conversation.init(allocator); + defer conv.deinit(); + try conv.addUserMessage("go"); + + var tools = emptyTools(); + defer tools.deinit(); + try tools.register(makeStaticTool("std.read", "Read a file.", "{\"type\":\"object\"}")); + + const cfg = testConfig("gpt-4o"); + 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(); + + const f = parsed.value.object.get("tools").?.array.items[0].object.get("function").?.object; + // Internal `std.read` crosses the wire as `std__read` (OpenAI forbids dots). + try testing.expectEqualStrings("std__read", f.get("name").?.string); +} + test "serializeRequest - assistant ToolUse becomes tool_calls" { const allocator = testing.allocator; |
