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