gigachat-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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +24 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +303 -0
  5. data/lib/gigachat/auth/access_token.rb +18 -0
  6. data/lib/gigachat/auth/token_manager.rb +107 -0
  7. data/lib/gigachat/certs/russian_trusted_root_ca.pem +33 -0
  8. data/lib/gigachat/client.rb +242 -0
  9. data/lib/gigachat/configuration.rb +94 -0
  10. data/lib/gigachat/errors.rb +77 -0
  11. data/lib/gigachat/internal/chat_accumulator.rb +47 -0
  12. data/lib/gigachat/internal/mime_types.rb +23 -0
  13. data/lib/gigachat/internal/retry_policy.rb +67 -0
  14. data/lib/gigachat/internal/sse_decoder.rb +85 -0
  15. data/lib/gigachat/internal/transport.rb +99 -0
  16. data/lib/gigachat/internal/util.rb +21 -0
  17. data/lib/gigachat/internal/v1_chat_accumulator.rb +41 -0
  18. data/lib/gigachat/resources/base.rb +31 -0
  19. data/lib/gigachat/resources/batches.rb +55 -0
  20. data/lib/gigachat/resources/chat.rb +43 -0
  21. data/lib/gigachat/resources/chat_v1.rb +24 -0
  22. data/lib/gigachat/resources/embeddings.rb +13 -0
  23. data/lib/gigachat/resources/files.rb +55 -0
  24. data/lib/gigachat/resources/functions.rb +14 -0
  25. data/lib/gigachat/resources/models.rb +15 -0
  26. data/lib/gigachat/stream.rb +85 -0
  27. data/lib/gigachat/types/ai_check_result.rb +18 -0
  28. data/lib/gigachat/types/balance.rb +9 -0
  29. data/lib/gigachat/types/balance_entry.rb +10 -0
  30. data/lib/gigachat/types/base.rb +80 -0
  31. data/lib/gigachat/types/batch.rb +29 -0
  32. data/lib/gigachat/types/batch_list.rb +17 -0
  33. data/lib/gigachat/types/chat_completion.rb +33 -0
  34. data/lib/gigachat/types/chat_event.rb +28 -0
  35. data/lib/gigachat/types/content_part.rb +15 -0
  36. data/lib/gigachat/types/embedding.rb +12 -0
  37. data/lib/gigachat/types/embeddings.rb +13 -0
  38. data/lib/gigachat/types/file_deleted.rb +13 -0
  39. data/lib/gigachat/types/file_list.rb +9 -0
  40. data/lib/gigachat/types/file_object.rb +16 -0
  41. data/lib/gigachat/types/file_ref.rb +11 -0
  42. data/lib/gigachat/types/function_call.rb +22 -0
  43. data/lib/gigachat/types/function_validation.rb +20 -0
  44. data/lib/gigachat/types/message.rb +20 -0
  45. data/lib/gigachat/types/model.rb +12 -0
  46. data/lib/gigachat/types/model_list.rb +10 -0
  47. data/lib/gigachat/types/tokens_count.rb +11 -0
  48. data/lib/gigachat/types/tokens_count_list.rb +10 -0
  49. data/lib/gigachat/types/tool_execution.rb +12 -0
  50. data/lib/gigachat/types/usage.rb +12 -0
  51. data/lib/gigachat/types/v1/chat_completion.rb +18 -0
  52. data/lib/gigachat/types/v1/chat_completion_chunk.rb +18 -0
  53. data/lib/gigachat/types/v1/choice.rb +14 -0
  54. data/lib/gigachat/types/v1/message.rb +16 -0
  55. data/lib/gigachat/types/v1/usage.rb +14 -0
  56. data/lib/gigachat/version.rb +5 -0
  57. data/lib/gigachat-ruby.rb +4 -0
  58. data/lib/gigachat.rb +31 -0
  59. metadata +144 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ # Response of POST /v2/chat/completions.
6
+ class ChatCompletion < Base
7
+ attribute :model
8
+ attribute :thread_id
9
+ attribute :message_id
10
+ attribute :messages, Message, array: true
11
+ attribute :finish_reason
12
+ attribute :usage, Usage
13
+ attribute :additional_data
14
+
15
+ # The spec documents `created_at`; the Python SDK also accepts `created`.
16
+ def created_at = self[:created_at] || self[:created]
17
+
18
+ def text = assistant_messages.map(&:text).join
19
+
20
+ def message = assistant_messages.first
21
+
22
+ def function_call = parts.find(&:function_call)&.function_call
23
+
24
+ def files = parts.flat_map { it.files || [] }
25
+
26
+ private
27
+
28
+ def assistant_messages = (messages || []).select { [nil, "assistant"].include?(it.role) }
29
+
30
+ def parts = (messages || []).flat_map { it.content || [] }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ # One named SSE event of a v2 stream (`response.message.delta`, `response.message.done`, ...).
6
+ class ChatEvent < ChatCompletion
7
+ DELTA = "response.message.delta"
8
+ DONE = "response.message.done"
9
+ TOOL_IN_PROGRESS = "response.tool.in_progress"
10
+ TOOL_COMPLETED = "response.tool.completed"
11
+
12
+ attr_reader :type
13
+
14
+ def initialize(data = {}, type: nil, x_headers: nil)
15
+ super(data, x_headers:)
16
+ @type = type
17
+ end
18
+
19
+ def delta? = type == DELTA
20
+
21
+ def done? = type == DONE
22
+
23
+ def tool_in_progress? = type == TOOL_IN_PROGRESS
24
+
25
+ def tool_completed? = type == TOOL_COMPLETED
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class ContentPart < Base
6
+ attribute :text
7
+ attribute :files, FileRef, array: true
8
+ attribute :function_call, FunctionCall
9
+ attribute :function_result
10
+ attribute :tool_execution, ToolExecution
11
+ attribute :logprobs
12
+ attribute :inline_data
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class Embedding < Base
6
+ attribute :object
7
+ attribute :embedding
8
+ attribute :index
9
+ attribute :usage
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class Embeddings < Base
6
+ enumerable :data, Embedding
7
+ attribute :model
8
+ attribute :object
9
+
10
+ def vectors = map(&:embedding)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FileDeleted < Base
6
+ attribute :id
7
+ attribute :deleted
8
+ attribute :access_policy
9
+
10
+ def deleted? = deleted == true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FileList < Base
6
+ enumerable :data, FileObject
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FileObject < Base
6
+ attribute :id
7
+ attribute :bytes
8
+ attribute :created_at
9
+ attribute :filename
10
+ attribute :object
11
+ attribute :purpose
12
+ attribute :access_policy
13
+ attribute :modalities
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FileRef < Base
6
+ attribute :id
7
+ attribute :target
8
+ attribute :mime
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FunctionCall < Base
6
+ attribute :name
7
+
8
+ # The spec types arguments as a JSON string, but the API (and both official SDKs) send an object.
9
+ # Accept both and always hand back a Hash; the raw value stays available via `[:arguments]`.
10
+ def arguments
11
+ raw = self[:arguments]
12
+ return raw if raw.is_a?(Hash)
13
+ return {} unless raw.is_a?(String)
14
+
15
+ parsed = JSON.parse(raw, symbolize_names: true)
16
+ parsed.is_a?(Hash) ? parsed : {}
17
+ rescue JSON::ParserError
18
+ {}
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class FunctionValidation < Base
6
+ class Issue < Base
7
+ attribute :description
8
+ attribute :schema_location
9
+ end
10
+
11
+ attribute :status
12
+ attribute :message
13
+ attribute :json_ai_rules_version
14
+ attribute :errors, Issue, array: true
15
+ attribute :warnings, Issue, array: true
16
+
17
+ def valid? = (errors || []).empty?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class Message < Base
6
+ attribute :role
7
+ attribute :message_id
8
+ attribute :content, ContentPart, array: true
9
+
10
+ # The live API returns `tool_state_id` (checked 2026-10-02, and the request schema agrees), while the
11
+ # spec's response schema and the Python SDK say `tools_state_id`. Read either; the raw key is kept as
12
+ # is, so passing the message back sends exactly what the API returned.
13
+ def tools_state_id = self[:tools_state_id] || self[:tool_state_id]
14
+
15
+ alias tool_state_id tools_state_id
16
+
17
+ def text = (content || []).filter_map(&:text).join
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class Model < Base
6
+ attribute :id
7
+ attribute :object
8
+ attribute :owned_by
9
+ attribute :type
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class ModelList < Base
6
+ enumerable :data, Model
7
+ attribute :object
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class TokensCount < Base
6
+ attribute :object
7
+ attribute :tokens
8
+ attribute :characters
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ # POST /tokens/count returns a bare JSON array; the client wraps it as `{ data: [...] }`.
6
+ class TokensCountList < Base
7
+ enumerable :data, TokensCount
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class ToolExecution < Base
6
+ attribute :name
7
+ attribute :status
8
+ attribute :seconds_left
9
+ attribute :censored
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ class Usage < Base
6
+ attribute :input_tokens
7
+ attribute :input_tokens_details
8
+ attribute :output_tokens
9
+ attribute :total_tokens
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ module V1
6
+ # Response of POST /chat/completions (v1).
7
+ class ChatCompletion < Base
8
+ attribute :choices, Choice, array: true
9
+ attribute :created
10
+ attribute :model
11
+ attribute :object
12
+ attribute :usage, Usage
13
+
14
+ def text = choices.to_a.first&.message&.content || ""
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ module V1
6
+ # One `data:` frame of a v1 stream.
7
+ class ChatCompletionChunk < Base
8
+ attribute :choices, Choice, array: true
9
+ attribute :created
10
+ attribute :model
11
+ attribute :object
12
+ attribute :usage, Usage
13
+
14
+ def text = (choices || []).filter_map { it.delta&.content }.join
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ module V1
6
+ class Choice < Base
7
+ attribute :message, Message
8
+ attribute :delta, Message
9
+ attribute :index
10
+ attribute :finish_reason
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ module V1
6
+ class Message < Base
7
+ attribute :role
8
+ attribute :content
9
+ attribute :name
10
+ attribute :created
11
+ attribute :functions_state_id
12
+ attribute :function_call, FunctionCall
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ module Types
5
+ module V1
6
+ class Usage < Base
7
+ attribute :prompt_tokens
8
+ attribute :completion_tokens
9
+ attribute :precached_prompt_tokens
10
+ attribute :total_tokens
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GigaChat
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Bundler auto-requires a gem by its name; the library's entry point is `require "gigachat"`.
4
+ require_relative "gigachat"
data/lib/gigachat.rb ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "faraday/multipart"
5
+ require "json"
6
+ require "openssl"
7
+ require "securerandom"
8
+ require "stringio"
9
+ require "time"
10
+ require "uri"
11
+ require "zeitwerk"
12
+
13
+ # Ruby client for the GigaChat REST API.
14
+ module GigaChat
15
+ LOADER = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
16
+ LOADER.inflector.inflect("gigachat" => "GigaChat", "sse_decoder" => "SSEDecoder")
17
+ # The shim's name is not a valid constant; errors.rb defines many constants and is required explicitly.
18
+ LOADER.ignore("#{__dir__}/gigachat-ruby.rb", "#{__dir__}/gigachat/errors.rb")
19
+ LOADER.setup
20
+
21
+ class << self
22
+ # Global defaults shared by every client built afterwards.
23
+ def config = @config ||= Configuration.new
24
+
25
+ def configure = yield(config)
26
+
27
+ def reset_config! = (@config = Configuration.new)
28
+ end
29
+ end
30
+
31
+ require_relative "gigachat/errors"
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gigachat-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandr Dryzhuk
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.14'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.14'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-multipart
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - !ruby/object:Gem::Dependency
41
+ name: zeitwerk
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.8'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.8'
54
+ description: 'Plain-Ruby client for Sber''s GigaChat API: chat (v2 and v1) with SSE
55
+ streaming, embeddings, files, batches, token counting and AI-text detection.'
56
+ email:
57
+ - dev@ad-it.pro
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - LICENSE.txt
64
+ - README.md
65
+ - lib/gigachat-ruby.rb
66
+ - lib/gigachat.rb
67
+ - lib/gigachat/auth/access_token.rb
68
+ - lib/gigachat/auth/token_manager.rb
69
+ - lib/gigachat/certs/russian_trusted_root_ca.pem
70
+ - lib/gigachat/client.rb
71
+ - lib/gigachat/configuration.rb
72
+ - lib/gigachat/errors.rb
73
+ - lib/gigachat/internal/chat_accumulator.rb
74
+ - lib/gigachat/internal/mime_types.rb
75
+ - lib/gigachat/internal/retry_policy.rb
76
+ - lib/gigachat/internal/sse_decoder.rb
77
+ - lib/gigachat/internal/transport.rb
78
+ - lib/gigachat/internal/util.rb
79
+ - lib/gigachat/internal/v1_chat_accumulator.rb
80
+ - lib/gigachat/resources/base.rb
81
+ - lib/gigachat/resources/batches.rb
82
+ - lib/gigachat/resources/chat.rb
83
+ - lib/gigachat/resources/chat_v1.rb
84
+ - lib/gigachat/resources/embeddings.rb
85
+ - lib/gigachat/resources/files.rb
86
+ - lib/gigachat/resources/functions.rb
87
+ - lib/gigachat/resources/models.rb
88
+ - lib/gigachat/stream.rb
89
+ - lib/gigachat/types/ai_check_result.rb
90
+ - lib/gigachat/types/balance.rb
91
+ - lib/gigachat/types/balance_entry.rb
92
+ - lib/gigachat/types/base.rb
93
+ - lib/gigachat/types/batch.rb
94
+ - lib/gigachat/types/batch_list.rb
95
+ - lib/gigachat/types/chat_completion.rb
96
+ - lib/gigachat/types/chat_event.rb
97
+ - lib/gigachat/types/content_part.rb
98
+ - lib/gigachat/types/embedding.rb
99
+ - lib/gigachat/types/embeddings.rb
100
+ - lib/gigachat/types/file_deleted.rb
101
+ - lib/gigachat/types/file_list.rb
102
+ - lib/gigachat/types/file_object.rb
103
+ - lib/gigachat/types/file_ref.rb
104
+ - lib/gigachat/types/function_call.rb
105
+ - lib/gigachat/types/function_validation.rb
106
+ - lib/gigachat/types/message.rb
107
+ - lib/gigachat/types/model.rb
108
+ - lib/gigachat/types/model_list.rb
109
+ - lib/gigachat/types/tokens_count.rb
110
+ - lib/gigachat/types/tokens_count_list.rb
111
+ - lib/gigachat/types/tool_execution.rb
112
+ - lib/gigachat/types/usage.rb
113
+ - lib/gigachat/types/v1/chat_completion.rb
114
+ - lib/gigachat/types/v1/chat_completion_chunk.rb
115
+ - lib/gigachat/types/v1/choice.rb
116
+ - lib/gigachat/types/v1/message.rb
117
+ - lib/gigachat/types/v1/usage.rb
118
+ - lib/gigachat/version.rb
119
+ homepage: https://github.com/amdest/gigachat-ruby
120
+ licenses:
121
+ - MIT
122
+ metadata:
123
+ homepage_uri: https://github.com/amdest/gigachat-ruby
124
+ source_code_uri: https://github.com/amdest/gigachat-ruby
125
+ changelog_uri: https://github.com/amdest/gigachat-ruby/blob/master/CHANGELOG.md
126
+ rubygems_mfa_required: 'true'
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '4.0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubygems_version: 4.0.16
142
+ specification_version: 4
143
+ summary: Ruby client for the GigaChat REST API
144
+ test_files: []