summaryrefslogtreecommitdiff
path: root/internal/llm/client_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/llm/client_test.go')
-rw-r--r--internal/llm/client_test.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/llm/client_test.go b/internal/llm/client_test.go
index 8257836..7533a8a 100644
--- a/internal/llm/client_test.go
+++ b/internal/llm/client_test.go
@@ -157,3 +157,43 @@ func TestErrFromStatus_RateLimitMarker(t *testing.T) {
t.Errorf("error should embed retry-after, got: %v", err)
}
}
+
+func TestChat_ToolsRoundTrip(t *testing.T) {
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ var body openAIRequest
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ t.Fatalf("decode body: %v", err)
+ }
+ if len(body.Tools) != 1 || body.Tools[0].Function.Name != "do_thing" {
+ t.Errorf("tools not forwarded in request: %+v", body.Tools)
+ }
+ w.Header().Set("Content-Type", "application/json")
+ fmt.Fprintln(w, `{
+ "model": "m",
+ "choices": [{"message": {"role": "assistant", "content": "",
+ "tool_calls": [{"id": "call_1", "type": "function",
+ "function": {"name": "do_thing", "arguments": "{\"x\":1}"}}]},
+ "finish_reason": "tool_calls"}],
+ "usage": {"prompt_tokens": 3, "completion_tokens": 4}
+ }`)
+ }))
+ defer srv.Close()
+
+ c := &Client{Endpoint: srv.URL + "/v1", Model: "m"}
+ resp, err := c.Chat(context.Background(), ChatRequest{
+ Messages: []Message{{Role: "user", Content: "go"}},
+ Tools: []Tool{{Type: "function", Function: ToolFunction{
+ Name: "do_thing", Description: "d", Parameters: map[string]any{"type": "object"},
+ }}},
+ })
+ if err != nil {
+ t.Fatalf("Chat: %v", err)
+ }
+ if len(resp.ToolCalls) != 1 {
+ t.Fatalf("expected 1 tool call, got %d", len(resp.ToolCalls))
+ }
+ tc := resp.ToolCalls[0]
+ if tc.ID != "call_1" || tc.Function.Name != "do_thing" || tc.Function.Arguments != `{"x":1}` {
+ t.Errorf("unexpected tool call parsed: %+v", tc)
+ }
+}