phaseo_sdk 2.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.
@@ -0,0 +1,3 @@
1
+ module PhaseoSdk
2
+ VERSION = "2.1.0"
3
+ end
data/lib/phaseo_sdk.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative "phaseo_sdk/version"
2
+ require_relative "index"
@@ -0,0 +1,22 @@
1
+ require_relative "lib/phaseo_sdk/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "phaseo_sdk"
5
+ spec.version = PhaseoSdk::VERSION
6
+ spec.authors = ["Phaseo"]
7
+ spec.email = ["danielbutler500@gmail.com"]
8
+
9
+ spec.summary = "Official Phaseo Gateway SDK for Ruby"
10
+ spec.description = "Ruby client for the Phaseo Gateway API with generated endpoints and typed wrappers."
11
+ spec.homepage = "https://phaseo.app"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = ">= 3.0.0"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/phaseoteam/Phaseo"
17
+ spec.metadata["changelog_uri"] = "https://github.com/phaseoteam/Phaseo/blob/main/packages/sdk/sdk-ruby/CHANGELOG.md"
18
+
19
+ spec.files = Dir.glob("{lib,examples,tests}/**/*").select { |f| File.file?(f) }
20
+ spec.files += %w[README.md phaseo_sdk.gemspec]
21
+ spec.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,39 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class ApiKeyMutationsTest < Minitest::Test
5
+ def test_api_key_mutation_helpers_return_payloads
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ case [method, path]
15
+ when ["POST", "/keys"]
16
+ { "data" => { "id" => "key_123", "name" => "Admin Key", "status" => "active" } }
17
+ when ["PATCH", "/keys/key_123"]
18
+ { "data" => { "id" => "key_123", "name" => "Renamed Key", "status" => "disabled" } }
19
+ when ["DELETE", "/keys/key_123"]
20
+ { "data" => { "id" => "key_123", "deleted" => true } }
21
+ else
22
+ raise "Unexpected request"
23
+ end
24
+ end
25
+
26
+ created = client.create_api_key("name" => "Admin Key", "scopes" => ["gateway:read"])
27
+ updated = client.update_api_key("key_123", "name" => "Renamed Key", "disabled" => true)
28
+ deleted = client.delete_api_key("key_123")
29
+
30
+ assert_equal "active", created["data"]["status"]
31
+ assert_equal "disabled", updated["data"]["status"]
32
+ assert_equal true, deleted["data"]["deleted"]
33
+ assert_equal [
34
+ ["POST", "/keys", nil, nil, { "name" => "Admin Key", "scopes" => ["gateway:read"] }],
35
+ ["PATCH", "/keys/key_123", nil, nil, { "name" => "Renamed Key", "disabled" => true }],
36
+ ["DELETE", "/keys/key_123", nil, nil, nil]
37
+ ], calls
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class ApiKeyTest < Minitest::Test
5
+ def test_get_api_key_returns_payload
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ {
15
+ "data" => {
16
+ "id" => "key_123",
17
+ "hash" => "keyhash_123",
18
+ "status" => "active"
19
+ }
20
+ }
21
+ end
22
+
23
+ response = client.get_api_key("key_123")
24
+
25
+ assert_equal "key_123", response["data"]["id"]
26
+ assert_equal "keyhash_123", response["data"]["hash"]
27
+ assert_equal "active", response["data"]["status"]
28
+ assert_equal [["GET", "/keys/key_123", nil, nil, nil]], calls
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class ApiKeysTest < Minitest::Test
5
+ def test_list_api_keys_returns_payload
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ {
15
+ "object" => "list",
16
+ "data" => [
17
+ { "id" => "key_123", "status" => "active" },
18
+ { "id" => "key_456", "status" => "disabled" }
19
+ ]
20
+ }
21
+ end
22
+
23
+ response = client.list_api_keys("disabled" => "true", "limit" => "2")
24
+
25
+ assert_equal "list", response["object"]
26
+ assert_equal "key_123", response["data"][0]["id"]
27
+ assert_equal "disabled", response["data"][1]["status"]
28
+ assert_equal [["GET", "/keys", { "disabled" => "true", "limit" => "2" }, nil, nil]], calls
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class AsyncJobsTest < Minitest::Test
5
+ def test_async_jobs_resource_builds_expected_url
6
+ client = PhaseoSdk::Phaseo.new(api_key: "test", enable_deprecation_warnings: false)
7
+
8
+ assert_equal(
9
+ "wss://api.phaseo.app/v1/async/video/video%20123/ws?interval_ms=1500&close_on_terminal=false",
10
+ client.async_jobs.websocket_url("video", "video 123", interval_ms: 1500, close_on_terminal: false)
11
+ )
12
+ end
13
+ end
@@ -0,0 +1,124 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class BatchesTest < Minitest::Test
5
+ def test_create_batch_returns_payload
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ {
15
+ "id" => "batch_123",
16
+ "status" => "validating",
17
+ "provider" => "openai",
18
+ "request_id" => "req_ruby_batch_1",
19
+ "session_id" => "session_ruby_batch_1",
20
+ "pricing_lines" => [{ "provider" => "openai", "cost_usd" => 0.03 }]
21
+ }
22
+ end
23
+
24
+ response = client.create_batch(
25
+ "input_file_id" => "file_123",
26
+ "endpoint" => "/v1/responses",
27
+ "completion_window" => "24h",
28
+ "session_id" => "session_ruby_batch_1"
29
+ )
30
+
31
+ assert_equal "batch_123", response["id"]
32
+ assert_equal "validating", response["status"]
33
+ assert_equal "openai", response["provider"]
34
+ assert_equal "req_ruby_batch_1", response["request_id"]
35
+ assert_equal "session_ruby_batch_1", response["session_id"]
36
+ assert_equal "openai", response.dig("pricing_lines", 0, "provider")
37
+ assert_equal [["POST", "/batches", nil, nil, {
38
+ "input_file_id" => "file_123",
39
+ "endpoint" => "/v1/responses",
40
+ "completion_window" => "24h",
41
+ "session_id" => "session_ruby_batch_1"
42
+ }]], calls
43
+ end
44
+
45
+ def test_retrieve_batch_returns_payload
46
+ client = PhaseoSdk::Phaseo.new(
47
+ api_key: "test",
48
+ enable_deprecation_warnings: false
49
+ )
50
+
51
+ calls = []
52
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
53
+ calls << [method, path, query, headers, body]
54
+ {
55
+ "id" => "batch_123",
56
+ "status" => "completed",
57
+ "provider" => "openai",
58
+ "request_id" => "req_ruby_batch_2",
59
+ "session_id" => "session_ruby_batch_1",
60
+ "request_counts" => { "total" => 4, "completed" => 3, "failed" => 1 },
61
+ "billing" => { "charged" => true, "cost_usd" => 0.12 }
62
+ }
63
+ end
64
+
65
+ response = client.retrieve_batch("batch_123")
66
+
67
+ assert_equal "batch_123", response["id"]
68
+ assert_equal "completed", response["status"]
69
+ assert_equal "openai", response["provider"]
70
+ assert_equal "req_ruby_batch_2", response["request_id"]
71
+ assert_equal "session_ruby_batch_1", response["session_id"]
72
+ assert_equal 4, response.dig("request_counts", "total")
73
+ assert_equal true, response.dig("billing", "charged")
74
+ assert_equal [["GET", "/batches/batch_123", nil, nil, nil]], calls
75
+ end
76
+
77
+ def test_cancel_batch_returns_payload
78
+ client = PhaseoSdk::Phaseo.new(
79
+ api_key: "test",
80
+ enable_deprecation_warnings: false
81
+ )
82
+
83
+ calls = []
84
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
85
+ calls << [method, path, query, headers, body]
86
+ { "id" => "batch_123", "status" => "cancelling" }
87
+ end
88
+
89
+ response = client.cancel_batch("batch_123")
90
+
91
+ assert_equal "batch_123", response["id"]
92
+ assert_equal "cancelling", response["status"]
93
+ assert_equal(
94
+ "wss://api.phaseo.app/v1/async/batch/batch_123/ws?interval_ms=1500&close_on_terminal=false",
95
+ client.batch_websocket_url("batch_123", interval_ms: 1500, close_on_terminal: false)
96
+ )
97
+ assert_equal(
98
+ "wss://api.phaseo.app/v1/async/video/video%20123/ws?interval_ms=1500&close_on_terminal=false",
99
+ client.get_async_job_websocket_url("video", "video 123", interval_ms: 1500, close_on_terminal: false)
100
+ )
101
+ assert_equal [["POST", "/batches/batch_123/cancel", nil, nil, nil]], calls
102
+ end
103
+
104
+ def test_cancel_batch_surfaces_request_errors
105
+ client = PhaseoSdk::Phaseo.new(
106
+ api_key: "test",
107
+ enable_deprecation_warnings: false
108
+ )
109
+
110
+ client.raw_client.define_singleton_method(:request) do |**_args|
111
+ raise Phaseo::Gen::RequestError.new(
112
+ status_code: 404,
113
+ status_message: "Not Found",
114
+ response_body: "{\"error\":\"not found\"}"
115
+ )
116
+ end
117
+
118
+ error = assert_raises(Phaseo::Gen::RequestError) do
119
+ client.cancel_batch("batch_missing_123")
120
+ end
121
+
122
+ assert_equal 404, error.status_code
123
+ end
124
+ end
@@ -0,0 +1,75 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class ChatTest < Minitest::Test
5
+ def test_generate_text_preserves_gateway_metadata
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ if method == "GET" && path == "/models"
15
+ next({
16
+ "models" => [
17
+ {
18
+ "model_id" => "openai/gpt-5-nano",
19
+ "status" => "active"
20
+ }
21
+ ]
22
+ })
23
+ end
24
+ {
25
+ "id" => "req_ruby_chat_1",
26
+ "nativeResponseId" => "chatcmpl_ruby_1",
27
+ "object" => "chat.completion",
28
+ "created" => 1_723_000_000,
29
+ "model" => "openai/gpt-5-nano",
30
+ "provider" => "openai",
31
+ "session_id" => "session_ruby_chat_1",
32
+ "upstream_request_id" => "upstream_ruby_chat_1",
33
+ "provider_attempts" => [
34
+ { "provider" => "openai", "status_code" => 200, "duration_ms" => 412 }
35
+ ],
36
+ "pricing_lines" => [
37
+ { "provider" => "openai", "cost_usd" => 0.0025 }
38
+ ],
39
+ "usage" => {
40
+ "input_tokens" => 2,
41
+ "output_tokens" => 1,
42
+ "total_tokens" => 3
43
+ },
44
+ "choices" => [
45
+ {
46
+ "index" => 0,
47
+ "message" => { "role" => "assistant", "content" => "hi" },
48
+ "finish_reason" => "stop"
49
+ }
50
+ ]
51
+ }
52
+ end
53
+
54
+ response = client.generate_text(
55
+ {
56
+ model: "openai/gpt-5-nano",
57
+ messages: [{ role: "user", content: "hi" }]
58
+ }
59
+ )
60
+
61
+ assert_equal "openai", response["provider"]
62
+ assert_equal "chatcmpl_ruby_1", response["nativeResponseId"]
63
+ assert_equal "session_ruby_chat_1", response["session_id"]
64
+ assert_equal "upstream_ruby_chat_1", response["upstream_request_id"]
65
+ assert_equal "openai", response.dig("provider_attempts", 0, "provider")
66
+ assert_equal "openai", response.dig("pricing_lines", 0, "provider")
67
+ assert_equal 2, response["usage"]["input_tokens"]
68
+ assert_equal 1, response["usage"]["output_tokens"]
69
+ assert_equal 3, response["usage"]["total_tokens"]
70
+ assert_equal [
71
+ ["GET", "/models", { "model_id" => "openai/gpt-5-nano", "limit" => "1" }, nil, nil],
72
+ ["POST", "/chat/completions", nil, nil, { model: "openai/gpt-5-nano", messages: [{ role: "user", content: "hi" }] }]
73
+ ], calls
74
+ end
75
+ end
@@ -0,0 +1,29 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/index"
3
+
4
+ class CurrentKeyTest < Minitest::Test
5
+ def test_get_current_api_key_returns_payload
6
+ client = PhaseoSdk::Phaseo.new(
7
+ api_key: "test",
8
+ enable_deprecation_warnings: false
9
+ )
10
+
11
+ calls = []
12
+ client.raw_client.define_singleton_method(:request) do |method:, path:, query: nil, headers: nil, body: nil|
13
+ calls << [method, path, query, headers, body]
14
+ {
15
+ "data" => {
16
+ "id" => "key_123",
17
+ "prefix" => "phaseo_v1_sk_test",
18
+ "status" => "active"
19
+ }
20
+ }
21
+ end
22
+
23
+ response = client.get_current_api_key
24
+
25
+ assert_equal "key_123", response["data"]["id"]
26
+ assert_equal "active", response["data"]["status"]
27
+ assert_equal [["GET", "/key", nil, nil, nil]], calls
28
+ end
29
+ end