summaryrefslogtreecommitdiff
path: root/libpanto/src/provider_openai_chat.zig
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-10 10:06:07 -0600
committert <t@tjp.lol>2026-06-10 12:17:27 -0600
commitbb85e867bc938138f29fb45230169af1ba60761c (patch)
tree5ad1cf50274c61ccfffab7048b4a4e28003d82b5 /libpanto/src/provider_openai_chat.zig
parentd26890bbc52e9f0050db40f208763a7f2b714ddd (diff)
Add addUserText helper; update all call sites
Conversation.addUserMessage now takes a []ContentBlock (symmetric with addAssistantMessage). Introduce a thin addUserText wrapper in agent.zig for the plain-text case and update every call site in agent.zig and anthropic_messages_json.zig accordingly.
Diffstat (limited to 'libpanto/src/provider_openai_chat.zig')
-rw-r--r--libpanto/src/provider_openai_chat.zig30
1 files changed, 20 insertions, 10 deletions
diff --git a/libpanto/src/provider_openai_chat.zig b/libpanto/src/provider_openai_chat.zig
index ed646e8..8319d9d 100644
--- a/libpanto/src/provider_openai_chat.zig
+++ b/libpanto/src/provider_openai_chat.zig
@@ -794,6 +794,16 @@ const EventRecorder = struct {
}
};
+/// Test helper: append a single-text user message. `addUserMessage` now
+/// takes a block slice (symmetric with `addAssistantMessage`); this wraps
+/// the common plain-text case the tests below use.
+fn addUserText(conv: *conversation.Conversation, text: []const u8) !void {
+ const tb = try conversation.textualBlockFromSlice(conv.allocator, text);
+ var block: conversation.ContentBlock = .{ .Text = tb };
+ errdefer block.deinit(conv.allocator);
+ try conv.addUserMessage(&.{block});
+}
+
test "two streamed turns persist assistant replies in the conversation" {
// Regression test for the bug where `finish_reason` arrived before
// `[DONE]` and `finalize` early-returned without appending the assistant
@@ -805,7 +815,7 @@ test "two streamed turns persist assistant replies in the conversation" {
defer conv.deinit();
try conv.addSystemMessage("You are a helpful assistant.");
- try conv.addUserMessage("hello!");
+ try addUserText(&conv, "hello!");
const turn1 = [_][]const u8{
\\{"choices":[{"delta":{"role":"assistant"}}]}
@@ -828,7 +838,7 @@ test "two streamed turns persist assistant replies in the conversation" {
);
// Second user turn: the assistant must still see its prior response.
- try conv.addUserMessage("how did you respond to my greeting just now?");
+ try addUserText(&conv, "how did you respond to my greeting just now?");
const turn2 = [_][]const u8{
\\{"choices":[{"delta":{"role":"assistant"}}]}
@@ -855,7 +865,7 @@ test "openai_chat: terminating usage chunk lands on message_complete with split
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("hi");
+ try addUserText(&conv, "hi");
var rec = EventRecorder{ .allocator = allocator };
defer rec.deinit();
@@ -888,7 +898,7 @@ test "openai_chat: omitted stream usage yields null on message_complete" {
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("hi");
+ try addUserText(&conv, "hi");
var rec = EventRecorder{ .allocator = allocator };
defer rec.deinit();
@@ -921,7 +931,7 @@ test "fragmented tool_call id and name are reassembled" {
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("call something");
+ try addUserText(&conv, "call something");
const events = [_][]const u8{
\\{"choices":[{"delta":{"role":"assistant"}}]}
@@ -956,7 +966,7 @@ test "inbound wire tool name is decoded to dotted form (even split across __)" {
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("read a file");
+ try addUserText(&conv, "read a file");
const events = [_][]const u8{
\\{"choices":[{"delta":{"role":"assistant"}}]}
@@ -991,7 +1001,7 @@ test "parallel tool_calls emit one complete start/delta/complete cycle per block
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("ping four hosts");
+ try addUserText(&conv, "ping four hosts");
var rec: EventRecorder = .{ .allocator = allocator };
defer rec.deinit();
@@ -1057,7 +1067,7 @@ test "non-contiguous tool_call deltas: re-emission of a closed index is dropped"
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("go");
+ try addUserText(&conv, "go");
var rec: EventRecorder = .{ .allocator = allocator };
defer rec.deinit();
@@ -1105,7 +1115,7 @@ test "onToolDetails fires after id+name complete, even mid-arg-stream" {
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("go");
+ try addUserText(&conv, "go");
var rec: EventRecorder = .{ .allocator = allocator };
defer rec.deinit();
@@ -1171,7 +1181,7 @@ test "tool_call with no arguments still finalizes a well-formed ToolUse" {
var conv = conversation.Conversation.init(allocator);
defer conv.deinit();
- try conv.addUserMessage("ring it");
+ try addUserText(&conv, "ring it");
const events = [_][]const u8{
\\{"choices":[{"delta":{"role":"assistant"}}]}