main
1# frozen_string_literal: true
2
3RSpec.describe Net::Llm::Anthropic do
4 subject(:client) do
5 described_class.new(
6 api_key: ENV.fetch("ANTHROPIC_API_KEY", "test-key")
7 )
8 end
9
10 describe "#initialize" do
11 it "sets default model" do
12 expect(client.model).to eq("claude-sonnet-4-20250514")
13 end
14
15 it "allows custom model" do
16 custom = described_class.new(
17 api_key: ENV.fetch("ANTHROPIC_API_KEY", "test-key"),
18 model: "claude-3-opus-20240229"
19 )
20 expect(custom.model).to eq("claude-3-opus-20240229")
21 end
22 end
23
24 describe "#messages" do
25 let(:messages) { [{ role: "user", content: "Hello" }] }
26
27 context "without streaming", :vcr do
28 it "POST /v1/messages" do
29 result = client.messages(messages)
30
31 expect(result["content"]).not_to be_empty
32 expect(result["role"]).to eq("assistant")
33 end
34 end
35
36 context "with streaming", :vcr do
37 it "yields SSE events to the block" do
38 results = []
39 client.messages(messages) { |event| results << event }
40
41 expect(results).not_to be_empty
42 expect(results.last["type"]).to eq("message_stop")
43 end
44 end
45
46 context "with system prompt", :vcr do
47 it "includes system in request" do
48 result = client.messages(messages, system: "You are a helpful assistant.")
49
50 expect(result["content"]).not_to be_empty
51 end
52 end
53
54 context "with tools", :vcr do
55 let(:tools) do
56 [{
57 name: "get_weather",
58 description: "Get weather for a city",
59 input_schema: {
60 type: "object",
61 properties: { city: { type: "string" } },
62 required: ["city"]
63 }
64 }]
65 end
66
67 it "POST /v1/messages with tools" do
68 messages = [{ role: "user", content: "What is the weather in Tokyo?" }]
69 result = client.messages(messages, tools: tools)
70
71 expect(result["content"]).not_to be_empty
72 expect(result["stop_reason"]).to eq("tool_use")
73 end
74 end
75
76 context "error handling" do
77 it "returns error hash on HTTP failure" do
78 bad_client = described_class.new(api_key: "invalid-key")
79 stub_request(:post, "https://api.anthropic.com/v1/messages")
80 .to_return(status: 401, body: "Unauthorized")
81
82 result = bad_client.messages(messages)
83 expect(result["code"]).to eq("401")
84 expect(result["body"]).to eq("Unauthorized")
85 end
86 end
87 end
88end