vapi-ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/vapi/tool.rb ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vapi
4
+ class Tool < Base
5
+ def list(**params)
6
+ client.get("/tool", params)
7
+ end
8
+
9
+ def find(id)
10
+ client.get("/tool/#{id}")
11
+ end
12
+
13
+ def create(params)
14
+ client.post("/tool", params)
15
+ end
16
+
17
+ def update(id, params)
18
+ client.patch("/tool/#{id}", params)
19
+ end
20
+
21
+ def delete(id)
22
+ client.delete("/tool/#{id}")
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vapi
4
+ VERSION = "0.1.0"
5
+ end
data/lib/vapi.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+ require 'json'
5
+
6
+ require_relative 'vapi/version'
7
+ require_relative 'vapi/errors'
8
+ require_relative 'vapi/configuration'
9
+ require_relative 'vapi/client'
10
+ require_relative 'vapi/base'
11
+ require_relative 'vapi/assistant'
12
+ require_relative 'vapi/call'
13
+ require_relative 'vapi/phone_number'
14
+ require_relative 'vapi/squad'
15
+ require_relative 'vapi/tool'
16
+ require_relative 'vapi/file'
17
+ require_relative 'vapi/knowledge_base'
18
+ require_relative 'vapi/log'
19
+ require_relative 'vapi/analytics'
20
+
21
+ module Vapi
22
+ class << self
23
+ attr_accessor :configuration
24
+
25
+ def configure
26
+ self.configuration ||= Configuration.new
27
+ yield(configuration) if block_given?
28
+ end
29
+
30
+ def client
31
+ @client ||= Client.new(configuration)
32
+ end
33
+
34
+ def reset!
35
+ @client = nil
36
+ @configuration = nil
37
+ end
38
+ end
39
+ end
data/spec/examples.txt ADDED
@@ -0,0 +1,60 @@
1
+ example_id | status | run_time |
2
+ ----------------------------------------- | ------ | --------------- |
3
+ ./spec/vapi/analytics_spec.rb[1:1:1] | passed | 0.00027 seconds |
4
+ ./spec/vapi/assistant_spec.rb[1:1:1] | passed | 0.00032 seconds |
5
+ ./spec/vapi/assistant_spec.rb[1:1:2] | passed | 0.00038 seconds |
6
+ ./spec/vapi/assistant_spec.rb[1:2:1] | passed | 0.0004 seconds |
7
+ ./spec/vapi/assistant_spec.rb[1:3:1] | passed | 0.00027 seconds |
8
+ ./spec/vapi/assistant_spec.rb[1:4:1] | passed | 0.00022 seconds |
9
+ ./spec/vapi/assistant_spec.rb[1:5:1] | passed | 0.00021 seconds |
10
+ ./spec/vapi/call_spec.rb[1:1:1] | passed | 0.0002 seconds |
11
+ ./spec/vapi/call_spec.rb[1:1:2] | passed | 0.00038 seconds |
12
+ ./spec/vapi/call_spec.rb[1:2:1] | passed | 0.00021 seconds |
13
+ ./spec/vapi/call_spec.rb[1:3:1] | passed | 0.00037 seconds |
14
+ ./spec/vapi/call_spec.rb[1:4:1] | passed | 0.00024 seconds |
15
+ ./spec/vapi/call_spec.rb[1:5:1] | passed | 0.00027 seconds |
16
+ ./spec/vapi/client_spec.rb[1:1:1] | passed | 0.00004 seconds |
17
+ ./spec/vapi/client_spec.rb[1:1:2:1] | passed | 0.00004 seconds |
18
+ ./spec/vapi/client_spec.rb[1:2:1] | passed | 0.00021 seconds |
19
+ ./spec/vapi/client_spec.rb[1:2:2] | passed | 0.00029 seconds |
20
+ ./spec/vapi/client_spec.rb[1:2:3] | passed | 0.00033 seconds |
21
+ ./spec/vapi/client_spec.rb[1:3:1] | passed | 0.00032 seconds |
22
+ ./spec/vapi/client_spec.rb[1:4:1] | passed | 0.00022 seconds |
23
+ ./spec/vapi/client_spec.rb[1:5:1] | passed | 0.00019 seconds |
24
+ ./spec/vapi/client_spec.rb[1:6:1] | passed | 0.00028 seconds |
25
+ ./spec/vapi/client_spec.rb[1:6:2] | passed | 0.00033 seconds |
26
+ ./spec/vapi/client_spec.rb[1:6:3] | passed | 0.00114 seconds |
27
+ ./spec/vapi/client_spec.rb[1:6:4] | passed | 0.00034 seconds |
28
+ ./spec/vapi/client_spec.rb[1:6:5] | passed | 0.0003 seconds |
29
+ ./spec/vapi/configuration_spec.rb[1:1:1] | passed | 0.00004 seconds |
30
+ ./spec/vapi/configuration_spec.rb[1:1:2] | passed | 0.00004 seconds |
31
+ ./spec/vapi/configuration_spec.rb[1:2:1] | passed | 0.00004 seconds |
32
+ ./spec/vapi/configuration_spec.rb[1:2:2] | passed | 0.00043 seconds |
33
+ ./spec/vapi/configuration_spec.rb[1:2:3] | passed | 0.00003 seconds |
34
+ ./spec/vapi/file_spec.rb[1:1:1] | passed | 0.0002 seconds |
35
+ ./spec/vapi/file_spec.rb[1:2:1] | passed | 0.00019 seconds |
36
+ ./spec/vapi/file_spec.rb[1:3:1] | passed | 0.00032 seconds |
37
+ ./spec/vapi/file_spec.rb[1:4:1] | passed | 0.00032 seconds |
38
+ ./spec/vapi/file_spec.rb[1:5:1] | passed | 0.00018 seconds |
39
+ ./spec/vapi/knowledge_base_spec.rb[1:1:1] | passed | 0.00022 seconds |
40
+ ./spec/vapi/knowledge_base_spec.rb[1:2:1] | passed | 0.00033 seconds |
41
+ ./spec/vapi/knowledge_base_spec.rb[1:3:1] | passed | 0.00035 seconds |
42
+ ./spec/vapi/knowledge_base_spec.rb[1:4:1] | passed | 0.00048 seconds |
43
+ ./spec/vapi/knowledge_base_spec.rb[1:5:1] | passed | 0.0002 seconds |
44
+ ./spec/vapi/log_spec.rb[1:1:1] | passed | 0.00024 seconds |
45
+ ./spec/vapi/log_spec.rb[1:1:2] | passed | 0.00035 seconds |
46
+ ./spec/vapi/phone_number_spec.rb[1:1:1] | passed | 0.0003 seconds |
47
+ ./spec/vapi/phone_number_spec.rb[1:2:1] | passed | 0.00021 seconds |
48
+ ./spec/vapi/phone_number_spec.rb[1:3:1] | passed | 0.00022 seconds |
49
+ ./spec/vapi/phone_number_spec.rb[1:4:1] | passed | 0.00032 seconds |
50
+ ./spec/vapi/phone_number_spec.rb[1:5:1] | passed | 0.0002 seconds |
51
+ ./spec/vapi/squad_spec.rb[1:1:1] | passed | 0.00026 seconds |
52
+ ./spec/vapi/squad_spec.rb[1:2:1] | passed | 0.0002 seconds |
53
+ ./spec/vapi/squad_spec.rb[1:3:1] | passed | 0.00038 seconds |
54
+ ./spec/vapi/squad_spec.rb[1:4:1] | passed | 0.00021 seconds |
55
+ ./spec/vapi/squad_spec.rb[1:5:1] | passed | 0.00028 seconds |
56
+ ./spec/vapi/tool_spec.rb[1:1:1] | passed | 0.02301 seconds |
57
+ ./spec/vapi/tool_spec.rb[1:2:1] | passed | 0.00033 seconds |
58
+ ./spec/vapi/tool_spec.rb[1:3:1] | passed | 0.00026 seconds |
59
+ ./spec/vapi/tool_spec.rb[1:4:1] | passed | 0.00051 seconds |
60
+ ./spec/vapi/tool_spec.rb[1:5:1] | passed | 0.00021 seconds |
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "vapi"
5
+ require "webmock/rspec"
6
+
7
+ RSpec.configure do |config|
8
+ config.expect_with :rspec do |expectations|
9
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
10
+ end
11
+
12
+ config.mock_with :rspec do |mocks|
13
+ mocks.verify_partial_doubles = true
14
+ end
15
+
16
+ config.shared_context_metadata_behavior = :apply_to_host_groups
17
+ config.filter_run_when_matching :focus
18
+ config.example_status_persistence_file_path = "spec/examples.txt"
19
+ config.disable_monkey_patching!
20
+ config.warnings = true
21
+
22
+ if config.files_to_run.one?
23
+ config.default_formatter = "doc"
24
+ end
25
+
26
+ config.order = :random
27
+ Kernel.srand config.seed
28
+
29
+ config.before(:each) do
30
+ WebMock.disable_net_connect!
31
+ Vapi.reset!
32
+ Vapi.configure do |c|
33
+ c.api_key = "test_api_key"
34
+ end
35
+ end
36
+
37
+ config.after(:each) do
38
+ WebMock.reset!
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Analytics do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#query" do
10
+ it "queries analytics" do
11
+ stub_request(:post, "#{base_url}/analytics")
12
+ .with(body: { queries: [{ name: "calls", table: "call" }] }.to_json)
13
+ .to_return(status: 200, body: [{ name: "calls", result: [] }].to_json,
14
+ headers: { "Content-Type" => "application/json" })
15
+
16
+ result = resource.query(queries: [{ name: "calls", table: "call" }])
17
+ expect(result).to be_an(Array)
18
+ expect(result.first["name"]).to eq("calls")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Assistant do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#list" do
10
+ it "lists assistants" do
11
+ stub_request(:get, "#{base_url}/assistant")
12
+ .to_return(status: 200, body: [{ id: "asst_1", name: "My Assistant" }].to_json,
13
+ headers: { "Content-Type" => "application/json" })
14
+
15
+ result = resource.list
16
+ expect(result).to be_an(Array)
17
+ expect(result.first["id"]).to eq("asst_1")
18
+ end
19
+
20
+ it "passes filter params" do
21
+ stub_request(:get, "#{base_url}/assistant")
22
+ .with(query: { limit: "10" })
23
+ .to_return(status: 200, body: [].to_json,
24
+ headers: { "Content-Type" => "application/json" })
25
+
26
+ resource.list(limit: "10")
27
+ end
28
+ end
29
+
30
+ describe "#find" do
31
+ it "gets an assistant by id" do
32
+ stub_request(:get, "#{base_url}/assistant/asst_1")
33
+ .to_return(status: 200, body: { id: "asst_1", name: "My Assistant" }.to_json,
34
+ headers: { "Content-Type" => "application/json" })
35
+
36
+ result = resource.find("asst_1")
37
+ expect(result["id"]).to eq("asst_1")
38
+ end
39
+ end
40
+
41
+ describe "#create" do
42
+ it "creates an assistant" do
43
+ stub_request(:post, "#{base_url}/assistant")
44
+ .with(body: { name: "New Assistant", model: { provider: "openai", model: "gpt-4" } }.to_json)
45
+ .to_return(status: 201, body: { id: "asst_2", name: "New Assistant" }.to_json,
46
+ headers: { "Content-Type" => "application/json" })
47
+
48
+ result = resource.create(name: "New Assistant", model: { provider: "openai", model: "gpt-4" })
49
+ expect(result["id"]).to eq("asst_2")
50
+ end
51
+ end
52
+
53
+ describe "#update" do
54
+ it "updates an assistant" do
55
+ stub_request(:patch, "#{base_url}/assistant/asst_1")
56
+ .with(body: { name: "Updated" }.to_json)
57
+ .to_return(status: 200, body: { id: "asst_1", name: "Updated" }.to_json,
58
+ headers: { "Content-Type" => "application/json" })
59
+
60
+ result = resource.update("asst_1", name: "Updated")
61
+ expect(result["name"]).to eq("Updated")
62
+ end
63
+ end
64
+
65
+ describe "#delete" do
66
+ it "deletes an assistant" do
67
+ stub_request(:delete, "#{base_url}/assistant/asst_1")
68
+ .to_return(status: 204, body: nil)
69
+
70
+ resource.delete("asst_1")
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Call do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#list" do
10
+ it "lists calls" do
11
+ stub_request(:get, "#{base_url}/call")
12
+ .to_return(status: 200, body: [{ id: "call_1", type: "outboundPhoneCall" }].to_json,
13
+ headers: { "Content-Type" => "application/json" })
14
+
15
+ result = resource.list
16
+ expect(result).to be_an(Array)
17
+ expect(result.first["id"]).to eq("call_1")
18
+ end
19
+
20
+ it "filters by assistantId" do
21
+ stub_request(:get, "#{base_url}/call")
22
+ .with(query: { assistantId: "asst_1" })
23
+ .to_return(status: 200, body: [].to_json,
24
+ headers: { "Content-Type" => "application/json" })
25
+
26
+ resource.list(assistantId: "asst_1")
27
+ end
28
+ end
29
+
30
+ describe "#find" do
31
+ it "gets a call by id" do
32
+ stub_request(:get, "#{base_url}/call/call_1")
33
+ .to_return(status: 200, body: { id: "call_1", status: "ended" }.to_json,
34
+ headers: { "Content-Type" => "application/json" })
35
+
36
+ result = resource.find("call_1")
37
+ expect(result["status"]).to eq("ended")
38
+ end
39
+ end
40
+
41
+ describe "#create" do
42
+ it "creates an outbound call" do
43
+ stub_request(:post, "#{base_url}/call")
44
+ .with(body: {
45
+ assistantId: "asst_1",
46
+ phoneNumberId: "pn_1",
47
+ customer: { number: "+1234567890" }
48
+ }.to_json)
49
+ .to_return(status: 201, body: { id: "call_2", type: "outboundPhoneCall" }.to_json,
50
+ headers: { "Content-Type" => "application/json" })
51
+
52
+ result = resource.create(
53
+ assistantId: "asst_1",
54
+ phoneNumberId: "pn_1",
55
+ customer: { number: "+1234567890" }
56
+ )
57
+ expect(result["id"]).to eq("call_2")
58
+ end
59
+ end
60
+
61
+ describe "#update" do
62
+ it "updates a call" do
63
+ stub_request(:patch, "#{base_url}/call/call_1")
64
+ .with(body: { name: "Updated Call" }.to_json)
65
+ .to_return(status: 200, body: { id: "call_1", name: "Updated Call" }.to_json,
66
+ headers: { "Content-Type" => "application/json" })
67
+
68
+ result = resource.update("call_1", name: "Updated Call")
69
+ expect(result["name"]).to eq("Updated Call")
70
+ end
71
+ end
72
+
73
+ describe "#delete" do
74
+ it "deletes a call" do
75
+ stub_request(:delete, "#{base_url}/call/call_1")
76
+ .to_return(status: 204, body: nil)
77
+
78
+ resource.delete("call_1")
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Client do
6
+ let(:client) { Vapi.client }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#initialize" do
10
+ it "creates a client instance" do
11
+ expect(client).to be_a(described_class)
12
+ end
13
+
14
+ context "with missing api_key" do
15
+ it "raises a ConfigurationError" do
16
+ config = Vapi::Configuration.new
17
+ expect { described_class.new(config) }.to raise_error(Vapi::ConfigurationError)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "#get" do
23
+ it "makes authenticated GET request" do
24
+ stub_request(:get, "#{base_url}/v1/test")
25
+ .to_return(status: 200, body: { data: "ok" }.to_json,
26
+ headers: { "Content-Type" => "application/json" })
27
+
28
+ result = client.get("/v1/test")
29
+ expect(result).to eq("data" => "ok")
30
+ end
31
+
32
+ it "sends Bearer token in Authorization header" do
33
+ stub_request(:get, "#{base_url}/v1/test")
34
+ .to_return(status: 200, body: {}.to_json,
35
+ headers: { "Content-Type" => "application/json" })
36
+
37
+ client.get("/v1/test")
38
+ expect(WebMock).to have_requested(:get, "#{base_url}/v1/test")
39
+ .with(headers: { "Authorization" => "Bearer test_api_key" })
40
+ end
41
+
42
+ it "passes query parameters" do
43
+ stub_request(:get, "#{base_url}/v1/test")
44
+ .with(query: { limit: "10" })
45
+ .to_return(status: 200, body: {}.to_json,
46
+ headers: { "Content-Type" => "application/json" })
47
+
48
+ client.get("/v1/test", limit: "10")
49
+ end
50
+ end
51
+
52
+ describe "#post" do
53
+ it "makes authenticated POST request with JSON body" do
54
+ stub_request(:post, "#{base_url}/v1/test")
55
+ .with(body: { name: "test" }.to_json,
56
+ headers: { "Content-Type" => "application/json" })
57
+ .to_return(status: 201, body: { id: "123" }.to_json,
58
+ headers: { "Content-Type" => "application/json" })
59
+
60
+ result = client.post("/v1/test", name: "test")
61
+ expect(result).to eq("id" => "123")
62
+ end
63
+ end
64
+
65
+ describe "#patch" do
66
+ it "makes authenticated PATCH request" do
67
+ stub_request(:patch, "#{base_url}/v1/test")
68
+ .to_return(status: 200, body: { success: true }.to_json,
69
+ headers: { "Content-Type" => "application/json" })
70
+
71
+ result = client.patch("/v1/test", name: "updated")
72
+ expect(result).to eq("success" => true)
73
+ end
74
+ end
75
+
76
+ describe "#delete" do
77
+ it "makes authenticated DELETE request" do
78
+ stub_request(:delete, "#{base_url}/v1/test")
79
+ .to_return(status: 204, body: nil)
80
+
81
+ client.delete("/v1/test")
82
+ end
83
+ end
84
+
85
+ describe "error handling" do
86
+ it "raises AuthenticationError on 401" do
87
+ stub_request(:get, "#{base_url}/v1/expired")
88
+ .to_return(status: 401, body: "Unauthorized")
89
+
90
+ expect { client.get("/v1/expired") }.to raise_error(Vapi::AuthenticationError)
91
+ end
92
+
93
+ it "raises NotFoundError on 404" do
94
+ stub_request(:get, "#{base_url}/v1/missing")
95
+ .to_return(status: 404, body: "Not Found")
96
+
97
+ expect { client.get("/v1/missing") }.to raise_error(Vapi::NotFoundError)
98
+ end
99
+
100
+ it "raises RateLimitError on 429 with retry-after" do
101
+ stub_request(:get, "#{base_url}/v1/limited")
102
+ .to_return(status: 429, body: "Too Many Requests",
103
+ headers: { "retry-after" => "30" })
104
+
105
+ expect { client.get("/v1/limited") }.to raise_error(Vapi::RateLimitError) do |error|
106
+ expect(error.retry_after).to eq("30")
107
+ end
108
+ end
109
+
110
+ it "raises ValidationError on 400" do
111
+ stub_request(:post, "#{base_url}/v1/bad")
112
+ .to_return(
113
+ status: 400,
114
+ body: { message: "Bad Request", errors: { "name" => ["is required"] } }.to_json,
115
+ headers: { "Content-Type" => "application/json" }
116
+ )
117
+
118
+ expect { client.post("/v1/bad", {}) }.to raise_error(Vapi::ValidationError) do |error|
119
+ expect(error.errors).to eq("name" => ["is required"])
120
+ end
121
+ end
122
+
123
+ it "raises APIError on 500" do
124
+ stub_request(:get, "#{base_url}/v1/error")
125
+ .to_return(status: 500, body: "Internal Server Error")
126
+
127
+ expect { client.get("/v1/error") }.to raise_error(Vapi::APIError)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Configuration do
6
+ describe "#initialize" do
7
+ it "sets default base_url" do
8
+ config = described_class.new
9
+ expect(config.base_url).to eq("https://api.vapi.ai")
10
+ end
11
+
12
+ it "sets default timeout" do
13
+ config = described_class.new
14
+ expect(config.timeout).to eq(30)
15
+ end
16
+ end
17
+
18
+ describe "#valid?" do
19
+ it "returns true when api_key is set" do
20
+ config = described_class.new
21
+ config.api_key = "test_key"
22
+ expect(config.valid?).to be true
23
+ end
24
+
25
+ it "returns false when api_key is nil" do
26
+ config = described_class.new
27
+ expect(config.valid?).to be false
28
+ end
29
+
30
+ it "returns false when api_key is empty" do
31
+ config = described_class.new
32
+ config.api_key = ""
33
+ expect(config.valid?).to be false
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::File do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#list" do
10
+ it "lists files" do
11
+ stub_request(:get, "#{base_url}/file")
12
+ .to_return(status: 200, body: [{ id: "file_1", name: "doc.pdf" }].to_json,
13
+ headers: { "Content-Type" => "application/json" })
14
+
15
+ result = resource.list
16
+ expect(result).to be_an(Array)
17
+ expect(result.first["name"]).to eq("doc.pdf")
18
+ end
19
+ end
20
+
21
+ describe "#find" do
22
+ it "gets a file by id" do
23
+ stub_request(:get, "#{base_url}/file/file_1")
24
+ .to_return(status: 200, body: { id: "file_1", name: "doc.pdf" }.to_json,
25
+ headers: { "Content-Type" => "application/json" })
26
+
27
+ result = resource.find("file_1")
28
+ expect(result["id"]).to eq("file_1")
29
+ end
30
+ end
31
+
32
+ describe "#create" do
33
+ it "creates a file" do
34
+ stub_request(:post, "#{base_url}/file")
35
+ .to_return(status: 201, body: { id: "file_2", name: "new.pdf" }.to_json,
36
+ headers: { "Content-Type" => "application/json" })
37
+
38
+ result = resource.create(name: "new.pdf")
39
+ expect(result["id"]).to eq("file_2")
40
+ end
41
+ end
42
+
43
+ describe "#update" do
44
+ it "updates a file" do
45
+ stub_request(:patch, "#{base_url}/file/file_1")
46
+ .with(body: { name: "renamed.pdf" }.to_json)
47
+ .to_return(status: 200, body: { id: "file_1", name: "renamed.pdf" }.to_json,
48
+ headers: { "Content-Type" => "application/json" })
49
+
50
+ result = resource.update("file_1", name: "renamed.pdf")
51
+ expect(result["name"]).to eq("renamed.pdf")
52
+ end
53
+ end
54
+
55
+ describe "#delete" do
56
+ it "deletes a file" do
57
+ stub_request(:delete, "#{base_url}/file/file_1")
58
+ .to_return(status: 204, body: nil)
59
+
60
+ resource.delete("file_1")
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::KnowledgeBase do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#list" do
10
+ it "lists knowledge bases" do
11
+ stub_request(:get, "#{base_url}/knowledge-base")
12
+ .to_return(status: 200, body: [{ id: "kb_1", name: "FAQ" }].to_json,
13
+ headers: { "Content-Type" => "application/json" })
14
+
15
+ result = resource.list
16
+ expect(result).to be_an(Array)
17
+ expect(result.first["name"]).to eq("FAQ")
18
+ end
19
+ end
20
+
21
+ describe "#find" do
22
+ it "gets a knowledge base by id" do
23
+ stub_request(:get, "#{base_url}/knowledge-base/kb_1")
24
+ .to_return(status: 200, body: { id: "kb_1", name: "FAQ" }.to_json,
25
+ headers: { "Content-Type" => "application/json" })
26
+
27
+ result = resource.find("kb_1")
28
+ expect(result["id"]).to eq("kb_1")
29
+ end
30
+ end
31
+
32
+ describe "#create" do
33
+ it "creates a knowledge base" do
34
+ stub_request(:post, "#{base_url}/knowledge-base")
35
+ .with(body: { name: "Product Docs", provider: "trieve" }.to_json)
36
+ .to_return(status: 201, body: { id: "kb_2", name: "Product Docs" }.to_json,
37
+ headers: { "Content-Type" => "application/json" })
38
+
39
+ result = resource.create(name: "Product Docs", provider: "trieve")
40
+ expect(result["id"]).to eq("kb_2")
41
+ end
42
+ end
43
+
44
+ describe "#update" do
45
+ it "updates a knowledge base" do
46
+ stub_request(:patch, "#{base_url}/knowledge-base/kb_1")
47
+ .with(body: { name: "Updated FAQ" }.to_json)
48
+ .to_return(status: 200, body: { id: "kb_1", name: "Updated FAQ" }.to_json,
49
+ headers: { "Content-Type" => "application/json" })
50
+
51
+ result = resource.update("kb_1", name: "Updated FAQ")
52
+ expect(result["name"]).to eq("Updated FAQ")
53
+ end
54
+ end
55
+
56
+ describe "#delete" do
57
+ it "deletes a knowledge base" do
58
+ stub_request(:delete, "#{base_url}/knowledge-base/kb_1")
59
+ .to_return(status: 204, body: nil)
60
+
61
+ resource.delete("kb_1")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Vapi::Log do
6
+ let(:resource) { described_class.new(Vapi.client) }
7
+ let(:base_url) { "https://api.vapi.ai" }
8
+
9
+ describe "#list" do
10
+ it "lists logs" do
11
+ stub_request(:get, "#{base_url}/logs")
12
+ .to_return(status: 200, body: [{ id: "log_1", type: "call" }].to_json,
13
+ headers: { "Content-Type" => "application/json" })
14
+
15
+ result = resource.list
16
+ expect(result).to be_an(Array)
17
+ expect(result.first["type"]).to eq("call")
18
+ end
19
+
20
+ it "filters by call id" do
21
+ stub_request(:get, "#{base_url}/logs")
22
+ .with(query: { callId: "call_1" })
23
+ .to_return(status: 200, body: [].to_json,
24
+ headers: { "Content-Type" => "application/json" })
25
+
26
+ resource.list(callId: "call_1")
27
+ end
28
+ end
29
+ end