ollama-ruby 1.22.0 → 1.23.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4e3eda370660a57c7382a3548702359bdb3ea37afc2c785a26fc0ef1f199cd7
4
- data.tar.gz: 77f392bc3c35948514cd78543560f3057b7b921487abd5803cad6f6f1cea9ac7
3
+ metadata.gz: 97a45592e9cf41628ed4b8fa86f98a2b8e5695669cf8b5919996df357b496301
4
+ data.tar.gz: 1a6fe9c40a33999e966e655c7cbf02956458c953bbcbf971c62a73c577290ed7
5
5
  SHA512:
6
- metadata.gz: c7633fbcb2ed35181d8ffbdf129f4e151f1328ade92df8279a7f62ced065e3abfd05f0c5c93ac06871dc7421b5567d9c2b963a41a97ddd4e8fe51e8bd7ca7aeb
7
- data.tar.gz: 93bdea4a001a9fb416100b6e5230c8a11d5524fe036b6216ccecc58e49584a703a1249e24510f1d66871866bcdd6483b703a4f47d0386253b0c5c3db613837d7
6
+ metadata.gz: 526e09b304cd3ebd743c037669eafe72cb5f4cd24bf0148744e67844924d8c99a71a1e649c8c27e3ea4dceb76617338b98bad8cd7d3a34d5888f9c3b18d0d26f
7
+ data.tar.gz: dd18fd50a3897fb1253d6c707fd57e2870e00d71e72f7540d79195fa0aa3e203db04e7374223034d0dbd4055de670d31acedac0b525434eb7d7e1f83630f89d5
data/CHANGES.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-07-17 v1.23.0
4
+
5
+ ### Added
6
+
7
+ - Support for nested properties in tool definitions by adding the `properties`
8
+ attribute to `Ollama::Tool::Function::Parameters::Property`.
9
+ - Support for array types in tool property definitions via the `items`
10
+ attribute in `Ollama::Tool::Function::Parameters::Property`.
11
+ - Implementation of shallow `to_hash` and recursive `as_json` in `Ollama::DTO`
12
+ to ensure deep serialization into primitives, including the integration of
13
+ `Tins::DeepTransform`.
14
+
15
+ ### Changed
16
+
17
+ - Increased the minimum required version of the `tins` gem to **1.54**.
18
+ - Moved the custom models section into its own dedicated section.
19
+
3
20
  ## 2026-06-21 v1.22.0
4
21
 
5
22
  ### New Features
data/README.md CHANGED
@@ -69,37 +69,6 @@ messages = Message.new(role: 'user', content: 'Why is the sky blue?')
69
69
  ollama.chat(model: 'llama3.1', stream: true, messages:, &Print)
70
70
  ```
71
71
 
72
- ### Importing Custom Models
73
-
74
- You can import your own model files (e.g., `.gguf`) directly into Ollama. This
75
- is a two-step process: first, upload the binary file to obtain a SHA256 digest,
76
- and then create the model using that digest as a reference.
77
-
78
- This workflow is particularly convenient in the `ollama_console`:
79
-
80
- ```ruby
81
- # 1. Upload the binary blob to get its digest
82
- # This will show a progress bar for both hashing and uploading
83
- digest = push_blob(body: File.new('my-model-q4_0.gguf', 'rb'))
84
-
85
- # 2. Define the model configuration
86
- template = "<|system|>\n{{ .System }}</s>\n<|user|>\n{{ .Prompt }}</s>\n<|assistant|>\n"
87
- system = "You are a helpful AI assistant."
88
- parameters = { stop: ["<|system|>", "<|user|>", "<|assistant|>", "</s>"] }
89
-
90
- # 3. Create the model using the digest (using Ruby 3 shorthand)
91
- create(
92
- model: 'my-username/my-model:latest',
93
- files: { 'my-model-q4_0.gguf' => digest },
94
- template:,
95
- system:,
96
- parameters:
97
- )
98
- ```
99
-
100
- This method is highly efficient as it uses streaming uploads and avoids
101
- redundant data transfers if the blob already exists on the server.
102
-
103
72
  ## Try out things in ollama\_console
104
73
 
105
74
  This is an interactive console where you can try out the different commands
@@ -280,6 +249,37 @@ jj ps
280
249
  jj version
281
250
  ```
282
251
 
252
+ ## Importing Custom Models
253
+
254
+ You can import your own model files (e.g., `.gguf`) directly into Ollama. This
255
+ is a two-step process: first, upload the binary file to obtain a SHA256 digest,
256
+ and then create the model using that digest as a reference.
257
+
258
+ This workflow is particularly convenient in the `ollama_console`:
259
+
260
+ ```ruby
261
+ # 1. Upload the binary blob to get its digest
262
+ # This will show a progress bar for both hashing and uploading
263
+ digest = push_blob(body: File.new('my-model-q4_0.gguf', 'rb'))
264
+
265
+ # 2. Define the model configuration
266
+ template = "<|system|>\n{{ .System }}</s>\n<|user|>\n{{ .Prompt }}</s>\n<|assistant|>\n"
267
+ system = "You are a helpful AI assistant."
268
+ parameters = { stop: ["<|system|>", "<|user|>", "<|assistant|>", "</s>"] }
269
+
270
+ # 3. Create the model using the digest (using Ruby 3 shorthand)
271
+ create(
272
+ model: 'my-username/my-model:latest',
273
+ files: { 'my-model-q4_0.gguf' => digest },
274
+ template:,
275
+ system:,
276
+ parameters:
277
+ )
278
+ ```
279
+
280
+ This method is highly efficient as it uses streaming uploads and avoids
281
+ redundant data transfers if the blob already exists on the server.
282
+
283
283
  ## Auxiliary objects
284
284
 
285
285
  The following objects are provided to interact with the ollama server. You can
data/Rakefile CHANGED
@@ -34,7 +34,7 @@ GemHadar do
34
34
  dependency 'excon', '~> 1.0'
35
35
  dependency 'infobar', '~> 0.8'
36
36
  dependency 'json', '~> 2.0'
37
- dependency 'tins', '~> 1'
37
+ dependency 'tins', '~> 1.54'
38
38
  dependency 'term-ansicolor', '~> 1.11'
39
39
  dependency 'kramdown-ansi', '~> 0.0', '>= 0.0.1'
40
40
  dependency 'ostruct', '~> 0.0'
data/lib/ollama/dto.rb CHANGED
@@ -16,6 +16,7 @@
16
16
  # end
17
17
  module Ollama::DTO
18
18
  extend Tins::Concern
19
+ include Tins::DeepTransform
19
20
 
20
21
  included do
21
22
  self.attributes = Set.new
@@ -116,20 +117,35 @@ module Ollama::DTO
116
117
  end
117
118
  end
118
119
 
120
+ # The to_hash method converts the object's attributes into a JSON-compatible
121
+ # hash representation without recursing into child objects.
122
+ #
123
+ # This provides a "shallow" view of the DTO, excluding any nil values or
124
+ # empty collections.
125
+ #
126
+ # @param ignored [ Array ] ignored arguments
127
+ # @return [ Hash ] a shallow hash containing the object's non-nil and
128
+ # non-empty attributes
129
+ def to_hash(*ignored)
130
+ self.class.attributes.each_with_object({}) { |a, h| h[a] = send(a) }.
131
+ reject { _2.nil? || _2.ask_and_send(:size) == 0 }
132
+ end
133
+
119
134
  # The as_json method converts the object's attributes into a JSON-compatible
120
135
  # hash.
121
136
  #
122
- # This method gathers all defined attributes of the object and constructs a
123
- # hash representation, excluding any nil values or empty collections.
137
+ # This method leverages Tins::HashTransform to recursively collapse the DTO
138
+ # tree into pure Ruby primitives (Hashes and Arrays), ensuring that no DTO
139
+ # objects remain in the final output.
124
140
  #
125
141
  # @param ignored [ Array ] ignored arguments
126
- # @return [ Hash ] a hash containing the object's non-nil and non-empty attributes
142
+ # @return [ Hash ] a fully collapsed hash containing the object's attributes
127
143
  def as_json(*ignored)
128
- self.class.attributes.each_with_object({}) { |a, h| h[a] = send(a) }.
129
- reject { _2.nil? || _2.ask_and_send(:size) == 0 }
144
+ deep_transform(circular: "[Circular Reference]")
130
145
  end
131
146
 
132
- # The == method compares two objects for equality based on their JSON representation.
147
+ # The == method compares two objects for equality based on their JSON
148
+ # representation.
133
149
  #
134
150
  # This method checks if the JSON representation of the current object is
135
151
  # equal to the JSON representation of another object.
@@ -142,12 +158,10 @@ module Ollama::DTO
142
158
  as_json == other.as_json
143
159
  end
144
160
 
145
- alias to_hash as_json
146
-
147
161
  # The empty? method checks whether the object has any attributes defined.
148
162
  #
149
163
  # This method determines if the object contains no attributes by checking
150
- # if its hash representation is empty. It is typically used to verify
164
+ # if its hash representation is empty. This is typically used to verify
151
165
  # if an object, such as a DTO, has been initialized with any values.
152
166
  #
153
167
  # @return [ TrueClass, FalseClass ] true if the object has no attributes,
@@ -37,13 +37,27 @@ class Ollama::Tool::Function::Parameters::Property
37
37
  # property can take, or nil if not set
38
38
  attr_reader :enum
39
39
 
40
+ # The properties attribute reader returns the nested properties associated
41
+ # with the object.
42
+ #
43
+ # @return [ Hash, nil ] a map of property names to their corresponding Property objects,
44
+ # or nil if not set
45
+ attr_reader :properties
46
+
47
+ # The items attribute reader returns the definition of elements for array types.
48
+ #
49
+ # @return [ Object, nil ] the schema definition for array items, or nil if not set
50
+ attr_reader :items
51
+
40
52
  # The initialize method sets up a new Property instance with the specified
41
53
  # attributes.
42
54
  #
43
55
  # @param type [ String ] the data type of the property
44
56
  # @param description [ String ] a detailed explanation of what the property represents
45
57
  # @param enum [ Array<String>, nil ] an optional array of valid values that the property can take
46
- def initialize(type:, description:, enum: nil)
47
- @type, @description, @enum = type, description, Array(enum)
58
+ # @param properties [ Hash, nil ] optional nested properties for 'object' types
59
+ # @param items [ Object, nil ] optional schema definition for 'array' type elements
60
+ def initialize(type:, description:, enum: nil, properties: nil, items: nil)
61
+ @type, @description, @enum, @properties, @items = type, description, Array(enum), properties, items
48
62
  end
49
63
  end
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '1.22.0'
3
+ VERSION = '1.23.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/ollama-ruby.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama-ruby 1.22.0 ruby lib
2
+ # stub: ollama-ruby 1.23.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "1.22.0".freeze
6
+ s.version = "1.23.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "Ollama-ruby - Interacting with the Ollama API".freeze, "--main".freeze, "README.md".freeze]
20
20
  s.required_ruby_version = Gem::Requirement.new(">= 3.1".freeze)
21
- s.rubygems_version = "4.0.10".freeze
21
+ s.rubygems_version = "4.0.17".freeze
22
22
  s.summary = "Interacting with the Ollama API".freeze
23
23
  s.test_files = ["spec/ollama/client/doc_spec.rb".freeze, "spec/ollama/client_spec.rb".freeze, "spec/ollama/commands/blob_exists_spec.rb".freeze, "spec/ollama/commands/chat_spec.rb".freeze, "spec/ollama/commands/copy_spec.rb".freeze, "spec/ollama/commands/create_spec.rb".freeze, "spec/ollama/commands/delete_spec.rb".freeze, "spec/ollama/commands/embed_spec.rb".freeze, "spec/ollama/commands/embeddings_spec.rb".freeze, "spec/ollama/commands/generate_spec.rb".freeze, "spec/ollama/commands/ps_spec.rb".freeze, "spec/ollama/commands/pull_spec.rb".freeze, "spec/ollama/commands/push_blob_spec.rb".freeze, "spec/ollama/commands/push_spec.rb".freeze, "spec/ollama/commands/show_spec.rb".freeze, "spec/ollama/commands/tags_spec.rb".freeze, "spec/ollama/commands/version_spec.rb".freeze, "spec/ollama/digester_spec.rb".freeze, "spec/ollama/handlers/collector_spec.rb".freeze, "spec/ollama/handlers/dump_json_spec.rb".freeze, "spec/ollama/handlers/dump_yaml_spec.rb".freeze, "spec/ollama/handlers/markdown_spec.rb".freeze, "spec/ollama/handlers/nop_spec.rb".freeze, "spec/ollama/handlers/print_spec.rb".freeze, "spec/ollama/handlers/progress_spec.rb".freeze, "spec/ollama/handlers/say_spec.rb".freeze, "spec/ollama/handlers/single_spec.rb".freeze, "spec/ollama/image_spec.rb".freeze, "spec/ollama/message_spec.rb".freeze, "spec/ollama/options_spec.rb".freeze, "spec/ollama/tool_spec.rb".freeze, "spec/spec_helper.rb".freeze]
24
24
 
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
35
35
  s.add_runtime_dependency(%q<excon>.freeze, ["~> 1.0".freeze])
36
36
  s.add_runtime_dependency(%q<infobar>.freeze, ["~> 0.8".freeze])
37
37
  s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
38
- s.add_runtime_dependency(%q<tins>.freeze, ["~> 1".freeze])
38
+ s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.54".freeze])
39
39
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
40
40
  s.add_runtime_dependency(%q<kramdown-ansi>.freeze, ["~> 0.0".freeze, ">= 0.0.1".freeze])
41
41
  s.add_runtime_dependency(%q<ostruct>.freeze, ["~> 0.0".freeze])
@@ -68,4 +68,164 @@ describe Ollama::Tool do
68
68
  %{{"type":"function","function":{"name":"get_current_weather","description":"Get the current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string","description":"The location to get the weather for, e.g. Berlin, Berlin"},"format":{"type":"string","description":"The format to return the weather in, e.g. 'celsius' or 'fahrenheit'","enum":["celsius","fahrenheit"]}},"required":["location","format"]}}}}
69
69
  )
70
70
  end
71
+
72
+ context 'with nested properties' do
73
+ let :address do
74
+ Ollama::Tool::Function::Parameters::Property.new(
75
+ type: 'string',
76
+ description: 'Street address',
77
+ )
78
+ end
79
+
80
+ let :city do
81
+ Ollama::Tool::Function::Parameters::Property.new(
82
+ type: 'string',
83
+ description: 'City name',
84
+ )
85
+ end
86
+
87
+ let :location_details do
88
+ Ollama::Tool::Function::Parameters::Property.new(
89
+ type: 'object',
90
+ description: 'Location details',
91
+ properties: { address: address, city: city },
92
+ )
93
+ end
94
+
95
+ let :nested_parameters do
96
+ Ollama::Tool::Function::Parameters.new(
97
+ type: 'object',
98
+ properties: { location: location_details },
99
+ required: %w[ location ],
100
+ )
101
+ end
102
+
103
+ let :nested_tool do
104
+ described_class.new(
105
+ type: 'function',
106
+ function: Ollama::Tool::Function.new(
107
+ name: 'get_location',
108
+ description: 'Get location info',
109
+ parameters: nested_parameters,
110
+ ),
111
+ )
112
+ end
113
+
114
+ it 'can serialize nested properties' do
115
+ expect(nested_tool.as_json[:function][:parameters][:properties][:location]).to eq({
116
+ type: 'object',
117
+ description: 'Location details',
118
+ properties: {
119
+ address: { type: 'string', description: 'Street address' },
120
+ city: { type: 'string', description: 'City name' }
121
+ }
122
+ })
123
+ end
124
+
125
+ it 'can serialize deeply nested properties' do
126
+ lat = Ollama::Tool::Function::Parameters::Property.new(type: 'number', description: 'Latitude')
127
+ lng = Ollama::Tool::Function::Parameters::Property.new(type: 'number', description: 'Longitude')
128
+ coords = Ollama::Tool::Function::Parameters::Property.new(
129
+ type: 'object',
130
+ description: 'GPS coordinates',
131
+ properties: { lat: lat, lng: lng }
132
+ )
133
+ loc = Ollama::Tool::Function::Parameters::Property.new(
134
+ type: 'object',
135
+ description: 'Location',
136
+ properties: { coordinates: coords }
137
+ )
138
+ event = Ollama::Tool::Function::Parameters::Property.new(
139
+ type: 'object',
140
+ description: 'Event',
141
+ properties: { location: loc }
142
+ )
143
+
144
+ deep_tool = described_class.new(
145
+ type: 'function',
146
+ function: Ollama::Tool::Function.new(
147
+ name: 'get_event',
148
+ description: 'Get event info',
149
+ parameters: Ollama::Tool::Function::Parameters.new(
150
+ type: 'object',
151
+ properties: { details: event },
152
+ required: %w[ details ]
153
+ )
154
+ )
155
+ )
156
+
157
+ expect(deep_tool.as_json[:function][:parameters][:properties][:details][:properties][:location][:properties][:coordinates][:properties][:lat][:type]).to eq('number')
158
+ end
159
+ end
160
+
161
+ context 'with array properties' do
162
+ let :tags do
163
+ Ollama::Tool::Function::Parameters::Property.new(
164
+ type: 'array',
165
+ description: 'A list of tags',
166
+ items: 'string'
167
+ )
168
+ end
169
+
170
+ let :edit_item do
171
+ Ollama::Tool::Function::Parameters::Property.new(
172
+ type: 'object',
173
+ description: 'An edit block',
174
+ properties: {
175
+ search: Ollama::Tool::Function::Parameters::Property.new(type: 'string', description: 'Search text'),
176
+ replace: Ollama::Tool::Function::Parameters::Property.new(type: 'string', description: 'Replace text')
177
+ }
178
+ )
179
+ end
180
+
181
+ let :edits do
182
+ Ollama::Tool::Function::Parameters::Property.new(
183
+ type: 'array',
184
+ description: 'A list of edits',
185
+ items: edit_item
186
+ )
187
+ end
188
+
189
+ let :array_parameters do
190
+ Ollama::Tool::Function::Parameters.new(
191
+ type: 'object',
192
+ properties: { tags: tags, edits: edits },
193
+ required: %w[ tags edits ]
194
+ )
195
+ end
196
+
197
+ let :array_tool do
198
+ described_class.new(
199
+ type: 'function',
200
+ function: Ollama::Tool::Function.new(
201
+ name: 'update_content',
202
+ description: 'Update content with tags and edits',
203
+ parameters: array_parameters
204
+ )
205
+ )
206
+ end
207
+
208
+ it 'can serialize simple array properties' do
209
+ expect(array_tool.as_json[:function][:parameters][:properties][:tags]).to eq({
210
+ type: 'array',
211
+ description: 'A list of tags',
212
+ items: 'string'
213
+ })
214
+ end
215
+
216
+ it 'can serialize complex array properties (objects)' do
217
+ expect(array_tool.as_json[:function][:parameters][:properties][:edits]).to eq({
218
+ type: 'array',
219
+ description: 'A list of edits',
220
+ items: {
221
+ type: 'object',
222
+ description: 'An edit block',
223
+ properties: {
224
+ search: { type: 'string', description: 'Search text' },
225
+ replace: { type: 'string', description: 'Replace text' }
226
+ }
227
+ }
228
+ })
229
+ end
230
+ end
71
231
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.22.0
4
+ version: 1.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -169,14 +169,14 @@ dependencies:
169
169
  requirements:
170
170
  - - "~>"
171
171
  - !ruby/object:Gem::Version
172
- version: '1'
172
+ version: '1.54'
173
173
  type: :runtime
174
174
  prerelease: false
175
175
  version_requirements: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - "~>"
178
178
  - !ruby/object:Gem::Version
179
- version: '1'
179
+ version: '1.54'
180
180
  - !ruby/object:Gem::Dependency
181
181
  name: term-ansicolor
182
182
  requirement: !ruby/object:Gem::Requirement
@@ -424,7 +424,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
424
424
  - !ruby/object:Gem::Version
425
425
  version: '0'
426
426
  requirements: []
427
- rubygems_version: 4.0.10
427
+ rubygems_version: 4.0.17
428
428
  specification_version: 4
429
429
  summary: Interacting with the Ollama API
430
430
  test_files: