groq_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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +57 -0
  4. data/CLAUDE.md +103 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +495 -0
  7. data/Rakefile +11 -0
  8. data/examples/README.md +39 -0
  9. data/examples/batch.rb +29 -0
  10. data/examples/chat_completion.rb +24 -0
  11. data/examples/chat_completion_stop.rb +19 -0
  12. data/examples/chat_completion_streaming.rb +23 -0
  13. data/examples/embedding.rb +20 -0
  14. data/examples/error_handling.rb +27 -0
  15. data/examples/file_upload.rb +23 -0
  16. data/examples/mcp_agent.rb +63 -0
  17. data/examples/mcp_chat_with_tools.rb +103 -0
  18. data/examples/mcp_resources_and_prompts.rb +89 -0
  19. data/examples/models_list.rb +16 -0
  20. data/examples/speech.rb +23 -0
  21. data/examples/transcription.rb +23 -0
  22. data/examples/translation.rb +22 -0
  23. data/lib/groq_ruby/client.rb +69 -0
  24. data/lib/groq_ruby/configuration.rb +62 -0
  25. data/lib/groq_ruby/error_mapper.rb +37 -0
  26. data/lib/groq_ruby/errors/api_connection_error.rb +8 -0
  27. data/lib/groq_ruby/errors/api_error.rb +14 -0
  28. data/lib/groq_ruby/errors/api_response_error.rb +5 -0
  29. data/lib/groq_ruby/errors/api_status_error.rb +23 -0
  30. data/lib/groq_ruby/errors/api_timeout_error.rb +8 -0
  31. data/lib/groq_ruby/errors/authentication_error.rb +4 -0
  32. data/lib/groq_ruby/errors/bad_request_error.rb +4 -0
  33. data/lib/groq_ruby/errors/configuration_error.rb +4 -0
  34. data/lib/groq_ruby/errors/conflict_error.rb +4 -0
  35. data/lib/groq_ruby/errors/error.rb +5 -0
  36. data/lib/groq_ruby/errors/internal_server_error.rb +4 -0
  37. data/lib/groq_ruby/errors/not_found_error.rb +4 -0
  38. data/lib/groq_ruby/errors/parameter_error.rb +13 -0
  39. data/lib/groq_ruby/errors/permission_denied_error.rb +4 -0
  40. data/lib/groq_ruby/errors/rate_limit_error.rb +4 -0
  41. data/lib/groq_ruby/errors/unprocessable_entity_error.rb +4 -0
  42. data/lib/groq_ruby/mcp/bridge.rb +239 -0
  43. data/lib/groq_ruby/mcp/claude_desktop_config.rb +79 -0
  44. data/lib/groq_ruby/mcp/client.rb +171 -0
  45. data/lib/groq_ruby/mcp/errors/error.rb +7 -0
  46. data/lib/groq_ruby/mcp/errors/json_rpc_error.rb +21 -0
  47. data/lib/groq_ruby/mcp/errors/protocol_error.rb +7 -0
  48. data/lib/groq_ruby/mcp/errors/timeout_error.rb +7 -0
  49. data/lib/groq_ruby/mcp/errors/transport_error.rb +6 -0
  50. data/lib/groq_ruby/mcp/errors/unknown_tool_error.rb +7 -0
  51. data/lib/groq_ruby/mcp/json_rpc.rb +51 -0
  52. data/lib/groq_ruby/mcp/prompt.rb +21 -0
  53. data/lib/groq_ruby/mcp/resource.rb +17 -0
  54. data/lib/groq_ruby/mcp/server_config.rb +22 -0
  55. data/lib/groq_ruby/mcp/tool.rb +22 -0
  56. data/lib/groq_ruby/mcp/transport.rb +32 -0
  57. data/lib/groq_ruby/mcp/transports/stdio.rb +100 -0
  58. data/lib/groq_ruby/mcp.rb +25 -0
  59. data/lib/groq_ruby/models/audio/transcription.rb +10 -0
  60. data/lib/groq_ruby/models/audio/translation.rb +8 -0
  61. data/lib/groq_ruby/models/batches/batch.rb +16 -0
  62. data/lib/groq_ruby/models/batches/batch_list.rb +10 -0
  63. data/lib/groq_ruby/models/batches/batch_request_counts.rb +8 -0
  64. data/lib/groq_ruby/models/chat/chat_completion.rb +14 -0
  65. data/lib/groq_ruby/models/chat/chat_completion_choice.rb +10 -0
  66. data/lib/groq_ruby/models/chat/chat_completion_chunk.rb +13 -0
  67. data/lib/groq_ruby/models/chat/chat_completion_chunk_choice.rb +10 -0
  68. data/lib/groq_ruby/models/chat/chat_completion_delta.rb +8 -0
  69. data/lib/groq_ruby/models/chat/chat_completion_message.rb +10 -0
  70. data/lib/groq_ruby/models/embeddings/create_embedding_response.rb +11 -0
  71. data/lib/groq_ruby/models/embeddings/embedding.rb +8 -0
  72. data/lib/groq_ruby/models/embeddings/embedding_usage.rb +8 -0
  73. data/lib/groq_ruby/models/files/file_deleted.rb +8 -0
  74. data/lib/groq_ruby/models/files/file_list.rb +10 -0
  75. data/lib/groq_ruby/models/files/file_object.rb +8 -0
  76. data/lib/groq_ruby/models/model.rb +8 -0
  77. data/lib/groq_ruby/models/model_deleted.rb +8 -0
  78. data/lib/groq_ruby/models/model_factory.rb +31 -0
  79. data/lib/groq_ruby/models/model_list.rb +10 -0
  80. data/lib/groq_ruby/models/usage.rb +11 -0
  81. data/lib/groq_ruby/multipart.rb +84 -0
  82. data/lib/groq_ruby/request.rb +13 -0
  83. data/lib/groq_ruby/resources/audio/speech.rb +32 -0
  84. data/lib/groq_ruby/resources/audio/transcriptions.rb +48 -0
  85. data/lib/groq_ruby/resources/audio/translations.rb +45 -0
  86. data/lib/groq_ruby/resources/audio.rb +26 -0
  87. data/lib/groq_ruby/resources/base.rb +33 -0
  88. data/lib/groq_ruby/resources/batches.rb +44 -0
  89. data/lib/groq_ruby/resources/chat/completions.rb +94 -0
  90. data/lib/groq_ruby/resources/chat.rb +16 -0
  91. data/lib/groq_ruby/resources/embeddings.rb +28 -0
  92. data/lib/groq_ruby/resources/files.rb +55 -0
  93. data/lib/groq_ruby/resources/models.rb +35 -0
  94. data/lib/groq_ruby/response.rb +9 -0
  95. data/lib/groq_ruby/streaming/chunk_stream.rb +58 -0
  96. data/lib/groq_ruby/streaming/event_parser.rb +23 -0
  97. data/lib/groq_ruby/transport.rb +169 -0
  98. data/lib/groq_ruby/version.rb +5 -0
  99. data/lib/groq_ruby.rb +36 -0
  100. data/lib/tasks/gem.rake +5 -0
  101. data/lib/tasks/lint/all.rake +11 -0
  102. data/lib/tasks/lint/rubocop.rake +15 -0
  103. data/lib/tasks/security.rake +11 -0
  104. data/lib/tasks/types.rake +11 -0
  105. data/sig/groq_ruby.rbs +191 -0
  106. data/sig/zeitwerk.rbs +13 -0
  107. data.tar.gz.sig +0 -0
  108. metadata +237 -0
  109. metadata.gz.sig +0 -0
@@ -0,0 +1,35 @@
1
+ module GroqRuby
2
+ module Resources
3
+ # `client.models.list / retrieve / delete`.
4
+ #
5
+ # @example List
6
+ # client.models.list.data.each { |m| puts m.id }
7
+ #
8
+ # @example Retrieve
9
+ # client.models.retrieve("llama-3.3-70b-versatile")
10
+ class Models < Base
11
+ BASE_PATH = "/openai/v1/models".freeze
12
+
13
+ # @return [GroqRuby::Models::ModelList]
14
+ def list
15
+ payload = perform(Request.new(method: :get, path: BASE_PATH))
16
+ GroqRuby::Models::ModelList.from_hash(payload)
17
+ end
18
+
19
+ # @param model_id [String]
20
+ # @return [GroqRuby::Models::Model]
21
+ # @raise [NotFoundError] if no such model exists for this account
22
+ def retrieve(model_id)
23
+ payload = perform(Request.new(method: :get, path: "#{BASE_PATH}/#{model_id}"))
24
+ GroqRuby::Models::Model.from_hash(payload)
25
+ end
26
+
27
+ # @param model_id [String]
28
+ # @return [GroqRuby::Models::ModelDeleted]
29
+ def delete(model_id)
30
+ payload = perform(Request.new(method: :delete, path: "#{BASE_PATH}/#{model_id}"))
31
+ GroqRuby::Models::ModelDeleted.from_hash(payload)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module GroqRuby
2
+ # Value object representing a parsed HTTP response. The body is either a
3
+ # decoded JSON object (Hash/Array) or a raw String for binary responses.
4
+ Response = Data.define(:status, :headers, :body) do
5
+ def success?
6
+ status.between?(200, 299)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,58 @@
1
+ require "json"
2
+
3
+ module GroqRuby
4
+ module Streaming
5
+ # Lazy stream of parsed chat completion chunks. Wraps the transport's
6
+ # SSE delivery with the `[DONE]` sentinel handling that OpenAI-style
7
+ # APIs use, and the JSON decode → model wrap step.
8
+ #
9
+ # Yields {GroqRuby::Models::ChatCompletionChunk} instances. Honours the
10
+ # `[DONE]` terminator by stopping iteration cleanly.
11
+ #
12
+ # @example Iterate via Enumerable
13
+ # stream = client.chat.completions.create(stream: true, ...)
14
+ # stream.each { |chunk| print chunk.choices.first.delta.content }
15
+ #
16
+ # @example Pass a block directly
17
+ # client.chat.completions.create(stream: true, ...) do |chunk|
18
+ # ...
19
+ # end
20
+ class ChunkStream
21
+ include Enumerable
22
+
23
+ DONE_SENTINEL = "[DONE]".freeze
24
+
25
+ # @param transport [Transport]
26
+ # @param request [Request]
27
+ # @param chunk_model [Class] class with a `.from_hash(Hash)` constructor
28
+ def initialize(transport:, request:, chunk_model:)
29
+ @transport = transport
30
+ @request = request
31
+ @chunk_model = chunk_model
32
+ end
33
+
34
+ # Iterate through each chunk. When called without a block, returns an
35
+ # Enumerator that lets callers compose with `Enumerable` methods.
36
+ #
37
+ # @yieldparam chunk [GroqRuby::Models::ChatCompletionChunk]
38
+ # @return [Enumerator] when called without a block
39
+ # @return [void] when called with a block
40
+ # @raise [APIError] subclass on non-2xx response or transport failure.
41
+ def each(&block)
42
+ return enum_for(:each) unless block_given?
43
+ parser = EventParser.new
44
+ result = @transport.stream(@request) do |raw_chunk|
45
+ parser.feed(raw_chunk) { |_event, data, _id, _retry| forward_event(data, &block) }
46
+ end
47
+ raise result.failure if result.failure?
48
+ end
49
+
50
+ private
51
+
52
+ def forward_event(data, &block)
53
+ return if data.nil? || data.empty? || data == DONE_SENTINEL
54
+ block.call(@chunk_model.from_hash(JSON.parse(data)))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ require "event_stream_parser"
2
+
3
+ module GroqRuby
4
+ module Streaming
5
+ # Thin adapter over the upstream `event_stream_parser` gem. Feeds raw
6
+ # response chunks in and yields parsed `(event, data, id, retry)`
7
+ # tuples. Single-purpose: it owns the SSE parser state and nothing else.
8
+ class EventParser
9
+ def initialize
10
+ @parser = ::EventStreamParser::Parser.new
11
+ end
12
+
13
+ # Feed a raw chunk from the HTTP response. Yields each parsed event.
14
+ # @yieldparam event [String, nil]
15
+ # @yieldparam data [String]
16
+ # @yieldparam id [String, nil]
17
+ # @yieldparam reconnect_time [Integer, nil]
18
+ def feed(chunk, &block)
19
+ @parser.feed(chunk, &block)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,169 @@
1
+ require "net/http"
2
+ require "json"
3
+ require "uri"
4
+ require "dry/monads"
5
+
6
+ module GroqRuby
7
+ # The single HTTP client used by every resource. Wraps Net::HTTP and
8
+ # exposes two operations: a buffered {#call} for ordinary requests and a
9
+ # streaming {#stream} for SSE (chat completions with `stream: true`).
10
+ #
11
+ # Both methods return a Result. Internal control flow uses Do notation
12
+ # so the happy path stays linear; transport-level failures are wrapped in
13
+ # the appropriate {APIError} subclass.
14
+ #
15
+ # Resources call `.value!` to surface the parsed response (raising on
16
+ # failure), preserving parity with the Python client's exception model.
17
+ class Transport
18
+ include Dry::Monads[:result, :do]
19
+
20
+ JSON_CONTENT_TYPE = "application/json"
21
+
22
+ # @param configuration [Configuration]
23
+ def initialize(configuration)
24
+ @config = configuration
25
+ end
26
+
27
+ # Execute a buffered request.
28
+ #
29
+ # @param request [Request]
30
+ # @param accept [Symbol] :json (decode body as JSON) or :binary (return raw String)
31
+ # @return [Dry::Monads::Result<Response, APIError>]
32
+ def call(request, accept: :json)
33
+ raw = yield execute(request)
34
+ response = yield decode(raw, accept)
35
+ yield validate(response)
36
+ Success(response)
37
+ end
38
+
39
+ # Execute a streaming request, yielding each raw chunk to the block.
40
+ # The HTTP response is opened in chunked mode; the body is never
41
+ # buffered in full. Validates the status before streaming begins;
42
+ # error responses are read in full so the body can be parsed and
43
+ # surfaced via the mapped exception.
44
+ #
45
+ # @yieldparam chunk [String]
46
+ # @return [Dry::Monads::Result<Response, APIError>]
47
+ def stream(request, &on_chunk)
48
+ uri = build_uri(request)
49
+ http = build_http(uri)
50
+ net_request = build_net_request(request, uri)
51
+
52
+ with_translated_errors do
53
+ outcome = nil
54
+ http.start do |conn|
55
+ conn.request(net_request) do |raw|
56
+ outcome = stream_response(raw, &on_chunk)
57
+ end
58
+ end
59
+ outcome
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def execute(request)
66
+ uri = build_uri(request)
67
+ http = build_http(uri)
68
+ net_request = build_net_request(request, uri)
69
+
70
+ with_translated_errors do
71
+ Success(http.start { |conn| conn.request(net_request) })
72
+ end
73
+ end
74
+
75
+ def with_translated_errors
76
+ yield
77
+ rescue Net::OpenTimeout, Net::ReadTimeout => e
78
+ Failure(APITimeoutError.new(e.message))
79
+ rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH => e
80
+ Failure(APIConnectionError.new(e.message))
81
+ end
82
+
83
+ def decode(raw, accept)
84
+ headers = collect_headers(raw)
85
+ body = raw.body || ""
86
+ decoded = (accept == :json) ? decode_json(body) : body
87
+ Success(Response.new(status: raw.code.to_i, headers: headers, body: decoded))
88
+ rescue JSON::ParserError => e
89
+ Failure(APIResponseError.new("invalid JSON response: #{e.message}"))
90
+ end
91
+
92
+ def decode_json(body)
93
+ body.empty? ? nil : JSON.parse(body)
94
+ end
95
+
96
+ def validate(response)
97
+ response.success? ? Success(response) : Failure(map_error(response))
98
+ end
99
+
100
+ def stream_response(raw, &on_chunk)
101
+ status = raw.code.to_i
102
+ headers = collect_headers(raw)
103
+ if status.between?(200, 299)
104
+ raw.read_body(&on_chunk)
105
+ Success(Response.new(status: status, headers: headers, body: nil))
106
+ else
107
+ body = decode_json_safe(raw.read_body)
108
+ Failure(map_error(Response.new(status: status, headers: headers, body: body)))
109
+ end
110
+ end
111
+
112
+ def decode_json_safe(body)
113
+ decode_json(body)
114
+ rescue JSON::ParserError
115
+ body
116
+ end
117
+
118
+ def map_error(response)
119
+ ErrorMapper.call(status: response.status, headers: response.headers, body: response.body)
120
+ end
121
+
122
+ def collect_headers(raw)
123
+ raw.each_header.to_h
124
+ end
125
+
126
+ def build_uri(request)
127
+ uri = URI.parse("#{@config.base_url.chomp("/")}/#{request.path.delete_prefix("/")}")
128
+ uri.query = URI.encode_www_form(request.query) if request.query && !request.query.empty?
129
+ uri
130
+ end
131
+
132
+ def build_http(uri)
133
+ http = Net::HTTP.new(uri.host, uri.port)
134
+ http.use_ssl = (uri.scheme == "https")
135
+ http.open_timeout = @config.open_timeout
136
+ http.read_timeout = @config.read_timeout
137
+ http
138
+ end
139
+
140
+ def build_net_request(request, uri)
141
+ klass = net_http_class(request.method)
142
+ net_request = klass.new(uri.request_uri)
143
+ apply_headers(net_request, request)
144
+ apply_body(net_request, request)
145
+ net_request
146
+ end
147
+
148
+ def net_http_class(method)
149
+ case method
150
+ when :get then Net::HTTP::Get
151
+ when :post then Net::HTTP::Post
152
+ when :delete then Net::HTTP::Delete
153
+ else raise ArgumentError, "unsupported HTTP method: #{method.inspect}"
154
+ end
155
+ end
156
+
157
+ def apply_headers(net_request, request)
158
+ @config.default_headers.each { |k, v| net_request[k] = v }
159
+ request.headers.each { |k, v| net_request[k] = v }
160
+ net_request["Content-Type"] = request.content_type if request.content_type
161
+ end
162
+
163
+ def apply_body(net_request, request)
164
+ return if request.body.nil?
165
+ net_request.body = request.body.is_a?(String) ? request.body : JSON.generate(request.body)
166
+ net_request["Content-Type"] ||= JSON_CONTENT_TYPE
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GroqRuby
4
+ VERSION = "0.1.0"
5
+ end
data/lib/groq_ruby.rb ADDED
@@ -0,0 +1,36 @@
1
+ require "zeitwerk"
2
+
3
+ loader = Zeitwerk::Loader.for_gem
4
+ # Acronyms that can't be derived from the default snake_case → CamelCase
5
+ # inflection. Each maps a basename (without `.rb`) to its constant.
6
+ loader.inflector.inflect(
7
+ "mcp" => "MCP",
8
+ "api_error" => "APIError",
9
+ "api_connection_error" => "APIConnectionError",
10
+ "api_timeout_error" => "APITimeoutError",
11
+ "api_status_error" => "APIStatusError",
12
+ "api_response_error" => "APIResponseError"
13
+ )
14
+ # Collapse organizational sub-directories so files inside them define
15
+ # constants in the parent namespace. Public API stays flat — callers
16
+ # write `GroqRuby::AuthenticationError`, not `GroqRuby::Errors::Auth…`.
17
+ loader.collapse("#{__dir__}/groq_ruby/errors")
18
+ loader.collapse("#{__dir__}/groq_ruby/mcp/errors")
19
+ loader.collapse("#{__dir__}/groq_ruby/models/chat")
20
+ loader.collapse("#{__dir__}/groq_ruby/models/audio")
21
+ loader.collapse("#{__dir__}/groq_ruby/models/embeddings")
22
+ loader.collapse("#{__dir__}/groq_ruby/models/files")
23
+ loader.collapse("#{__dir__}/groq_ruby/models/batches")
24
+ loader.setup
25
+
26
+ # Idiomatic Ruby client for the Groq API. See {GroqRuby::Client} for the
27
+ # main entry point and the `examples/` directory for end-to-end snippets.
28
+ module GroqRuby
29
+ # Convenience constructor — `GroqRuby.client` reads configuration from
30
+ # the `GROQ_API_KEY` and `GROQ_BASE_URL` env vars by default.
31
+ #
32
+ # @return [Client]
33
+ def self.client(**opts)
34
+ Client.new(**opts)
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_helper"
2
+
3
+ namespace :gem do
4
+ Bundler::GemHelper.install_tasks
5
+ end
@@ -0,0 +1,11 @@
1
+ namespace :lint do
2
+ desc "Run all linter checks"
3
+ task all: %i[rubocop] do
4
+ puts "All lints completed successfully!"
5
+ end
6
+
7
+ namespace :all do
8
+ desc "Run all linter autocorrects"
9
+ task autocorrect: %i[rubocop:autocorrect]
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ require "rubocop/rake_task"
2
+
3
+ namespace :lint do
4
+ desc "Run rubocop linter check"
5
+ task :rubocop do
6
+ exec "bundle exec rubocop"
7
+ end
8
+
9
+ namespace :rubocop do
10
+ desc "Run rubocop autocorrect"
11
+ task :autocorrect do
12
+ exec "bundle exec rubocop --autocorrect-all"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ require "bundler/audit/task"
2
+
3
+ Bundler::Audit::Task.new
4
+
5
+ namespace :security do
6
+ desc "Update vulnerability database and run audit"
7
+ task :audit do
8
+ Rake::Task["bundle:audit:update"].invoke
9
+ Rake::Task["bundle:audit"].invoke
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ namespace :types do
2
+ desc "Validate RBS syntax in sig/ (catches sigs that reference nonexistent types)"
3
+ task :validate do
4
+ sh "bundle exec rbs " \
5
+ "-r uri -r ipaddr -r stringio -r tempfile -r net-http -r openssl -r resolv -r zlib " \
6
+ "-I sig validate"
7
+ end
8
+ end
9
+
10
+ desc "Validate RBS sigs"
11
+ task types: ["types:validate"]
data/sig/groq_ruby.rbs ADDED
@@ -0,0 +1,191 @@
1
+ module GroqRuby
2
+ VERSION: String
3
+
4
+ def self.client: (**untyped opts) -> Client
5
+
6
+ class Error < StandardError
7
+ end
8
+
9
+ class ConfigurationError < Error
10
+ end
11
+
12
+ class ParameterError < Error
13
+ attr_reader messages: Hash[untyped, untyped]
14
+ def initialize: (Hash[untyped, untyped] messages) -> void
15
+ end
16
+
17
+ class APIError < Error
18
+ attr_reader request: untyped
19
+ def initialize: (String message, ?request: untyped?) -> void
20
+ end
21
+
22
+ class APIConnectionError < APIError
23
+ end
24
+
25
+ class APITimeoutError < APIConnectionError
26
+ end
27
+
28
+ class APIStatusError < APIError
29
+ attr_reader status: Integer
30
+ attr_reader headers: Hash[String, String]
31
+ attr_reader body: untyped
32
+
33
+ def initialize: (
34
+ String message,
35
+ status: Integer,
36
+ ?headers: Hash[String, String],
37
+ ?body: untyped,
38
+ ?request: untyped?
39
+ ) -> void
40
+ end
41
+
42
+ class BadRequestError < APIStatusError
43
+ end
44
+
45
+ class AuthenticationError < APIStatusError
46
+ end
47
+
48
+ class PermissionDeniedError < APIStatusError
49
+ end
50
+
51
+ class NotFoundError < APIStatusError
52
+ end
53
+
54
+ class ConflictError < APIStatusError
55
+ end
56
+
57
+ class UnprocessableEntityError < APIStatusError
58
+ end
59
+
60
+ class RateLimitError < APIStatusError
61
+ end
62
+
63
+ class InternalServerError < APIStatusError
64
+ end
65
+
66
+ class APIResponseError < APIError
67
+ end
68
+
69
+ class Client
70
+ attr_reader configuration: untyped
71
+
72
+ def initialize: (
73
+ ?api_key: String?,
74
+ ?base_url: String?,
75
+ ?open_timeout: (Float | Integer)?,
76
+ ?read_timeout: (Float | Integer)?,
77
+ ?user_agent: String?
78
+ ) -> void
79
+
80
+ def chat: () -> untyped
81
+ def embeddings: () -> untyped
82
+ def audio: () -> untyped
83
+ def models: () -> untyped
84
+ def files: () -> untyped
85
+ def batches: () -> untyped
86
+ end
87
+
88
+ module MCP
89
+ PROTOCOL_VERSION: String
90
+
91
+ class Error < GroqRuby::Error
92
+ end
93
+
94
+ class TransportError < Error
95
+ end
96
+
97
+ class TimeoutError < Error
98
+ end
99
+
100
+ class ProtocolError < Error
101
+ end
102
+
103
+ class JsonRpcError < Error
104
+ attr_reader code: Integer
105
+ attr_reader data: untyped
106
+
107
+ def initialize: (code: Integer, message: String, ?data: untyped) -> void
108
+ end
109
+
110
+ class UnknownToolError < Error
111
+ end
112
+
113
+ class ServerConfig
114
+ attr_reader name: String
115
+ attr_reader command: String
116
+ attr_reader args: Array[String]
117
+ attr_reader env: Hash[String, String]
118
+
119
+ def initialize: (
120
+ name: String,
121
+ command: String,
122
+ ?args: Array[String],
123
+ ?env: Hash[String, String]
124
+ ) -> void
125
+ end
126
+
127
+ module ClaudeDesktopConfig
128
+ VAR_PATTERN: Regexp
129
+
130
+ def self.load: (String path) -> Array[ServerConfig]
131
+ def self.parse: ((Hash[untyped, untyped] | String) input) -> Array[ServerConfig]
132
+ end
133
+
134
+ class Tool
135
+ attr_reader name: String
136
+ attr_reader description: String?
137
+ attr_reader input_schema: Hash[String, untyped]
138
+ def self.from_hash: (Hash[untyped, untyped]?) -> Tool?
139
+ end
140
+
141
+ class Resource
142
+ attr_reader uri: String
143
+ attr_reader name: String?
144
+ attr_reader description: String?
145
+ attr_reader mime_type: String?
146
+ def self.from_hash: (Hash[untyped, untyped]?) -> Resource?
147
+ end
148
+
149
+ class Prompt
150
+ attr_reader name: String
151
+ attr_reader description: String?
152
+ attr_reader arguments: Array[untyped]
153
+ def self.from_hash: (Hash[untyped, untyped]?) -> Prompt?
154
+ end
155
+
156
+ class Client
157
+ DEFAULT_REQUEST_TIMEOUT: Float
158
+
159
+ attr_reader server_name: String?
160
+ attr_reader server_version: String?
161
+ attr_reader server_capabilities: Hash[String, untyped]
162
+
163
+ def self.connect: (ServerConfig, ?request_timeout: Numeric) -> Client
164
+ def initialize: (untyped transport, ?request_timeout: Numeric) -> void
165
+ def initialize_session: () -> Hash[String, untyped]
166
+ def tools_list: () -> Array[Tool]
167
+ def tools_call: (name: String, ?arguments: Hash[untyped, untyped]) -> Hash[String, untyped]
168
+ def resources_list: () -> Array[Resource]
169
+ def resources_read: (String uri) -> Hash[String, untyped]
170
+ def prompts_list: () -> Array[Prompt]
171
+ def prompts_get: (String name, ?Hash[untyped, untyped] arguments) -> Hash[String, untyped]
172
+ def supports?: (String capability) -> bool
173
+ def stop: () -> void
174
+ end
175
+
176
+ class Bridge
177
+ NAME_SEPARATOR: String
178
+ READ_RESOURCE_SUFFIX: String
179
+
180
+ def initialize: (Array[ServerConfig], ?request_timeout: Numeric) -> void
181
+ def tools: () -> Array[Hash[Symbol, untyped]]
182
+ def tool_names: () -> Array[String]
183
+ def resources: () -> Array[Hash[Symbol, untyped]]
184
+ def prompts: () -> Array[Hash[Symbol, untyped]]
185
+ def call: (String namespaced_name, (Hash[untyped, untyped] | String) arguments) -> Hash[String, untyped]
186
+ def read_resource: (String uri, ?server: String?) -> Hash[String, untyped]
187
+ def get_prompt: (String namespaced_name, ?Hash[untyped, untyped] arguments) -> Hash[String, untyped]
188
+ def stop: () -> void
189
+ end
190
+ end
191
+ end
data/sig/zeitwerk.rbs ADDED
@@ -0,0 +1,13 @@
1
+ # Minimal type stubs for Zeitwerk. We only use a tiny slice of its API in the
2
+ # gem entry point — `Zeitwerk::Loader.for_gem` plus `#ignore` and `#setup` on
3
+ # the returned loader. The community gem_rbs_collection has fuller sigs; this
4
+ # stub avoids pulling that in for one bootstrap call.
5
+ module Zeitwerk
6
+ class Loader
7
+ def self.for_gem: () -> Loader
8
+
9
+ def ignore: (*String paths) -> void
10
+
11
+ def setup: () -> void
12
+ end
13
+ end
data.tar.gz.sig ADDED
Binary file