ollama-ruby 1.23.1 → 1.24.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: f197227ddcc162704a67a9cc17c97fd2b79d5771a96f3ebf20b11439c2a74c76
4
- data.tar.gz: 0d7ce28a20d917d972091270e09a1000436788a5ad65ce9c9992c9e5e8539d52
3
+ metadata.gz: 54d8913adab981adc75ef6c69fc059349fbd55249fa919d94b52fdf19985554b
4
+ data.tar.gz: f4df502f748953d6ca799ec58cebf1f04d507d554fa68c1b5262e90b2a2b75b0
5
5
  SHA512:
6
- metadata.gz: 44315e4d097b7866b0fbbed812d950c8e40b0ede380223561716d0a9f223fd74407afa803f2df5ad43f64cf3f620a8adabb0e4ba506518601036e78a0f1c194b
7
- data.tar.gz: b35bd622e71e8d6f79909c46c09a71792d8dac7cc37286de7b39049422f9e9fbca835d3f8e654926afc7ff84df628129a67bf63492953c49b55b735907a58915
6
+ metadata.gz: 4eacd7afe3fed35b8d49e16ebdc37297d8a1084ea31060d55a6710dc1f84479e4b0a41f251048d1d3292bf05f244b4eb0bccb9250c6f97735006df94a9a593e1
7
+ data.tar.gz: 4af350efba4685daea10c6c9edc9b5399fb1e4cf8b39302c1a532aeb0ed7dc9dfda149b686838115d757aa7f1f24d5a19a882cc7d1f869e478d3531e02cd2ff2
data/CHANGES.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-16 v1.24.0
4
+
5
+ * Add `Options.from_string` to parse `show`-format parameter strings with
6
+ type inference for `Boolean`, `Integer`, `Float`, and `Array` types.
7
+ * Add `draft_num_predict: Integer` to the `@@types` registry and freeze the
8
+ `@@types` hash to prevent accidental mutation.
9
+ * Fix an infinite loop in `bin/ollama_ps` by correcting the `while` condition
10
+ to `duration > 0` and ensuring explicit exit codes (`exit 0` for success,
11
+ `exit 1` for failure).
12
+ * Add `rescue Interrupt` handling in `bin/ollama_ps` for clean `Ctrl+C` exit
13
+ messages.
14
+ * Update YARD documentation for the `think` parameter in
15
+ `Ollama::Commands::Chat` and `Ollama::Commands::Generate` to include
16
+ `"max"` as an accepted thinking level.
17
+ * Document the `show` → `create` parameter import workflow in `README.md`.
18
+ * Add `-i INTERVAL` to the `ollama_ps` usage block in `README.md`.
19
+ * Fix backtick formatting for `Q4_K_M` and `F16` in the `ollama_ps` QUANT
20
+ column documentation.
21
+ * Remove vim modeline comments from `Gemfile` and `Rakefile`.
22
+
23
+ ## 2026-08-12 v1.23.2
24
+
25
+ - Optimized terminal rendering in `bin/ollama_ps` polling loop by replacing
26
+ `clear_screen` with `move_home` and `erase_in_display(nil)` to prevent tmux
27
+ flicker.
28
+ - Applied the same terminal clearing fix to streaming mode in
29
+ `lib/ollama/handlers/markdown.rb`.
30
+ - Updated `gem_hadar` development dependency to **>= 2.18.0**.
31
+
3
32
  ## 2026-07-23 v1.23.1
4
33
 
5
34
  - Update `tins` gem dependency to **~> 1.55** in `Rakefile` and
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
- # vim: set filetype=ruby et sw=2 ts=2:
2
-
3
1
  source 'https://rubygems.org'
4
2
 
5
3
  gemspec
data/README.md CHANGED
@@ -280,6 +280,16 @@ create(
280
280
  This method is highly efficient as it uses streaming uploads and avoids
281
281
  redundant data transfers if the blob already exists on the server.
282
282
 
283
+ You can also import parameters from an existing model using the `show`
284
+ endpoint. `Options.from_string` parses the multi-line `parameters` field into
285
+ a typed `Options` instance that can be passed to `create(…, parameters:)`:
286
+
287
+ ```ruby
288
+ info = show(model: 'llama3.1')
289
+ options = Options.from_string(info.parameters)
290
+ create(model: 'my-clone', from: 'llama3.1', parameters: options)
291
+ ```
292
+
283
293
  ## Auxiliary objects
284
294
 
285
295
  The following objects are provided to interact with the ollama server. You can
@@ -533,6 +543,7 @@ including:
533
543
  Usage: ollama_ps [OPTIONS]
534
544
 
535
545
  -f FORMAT output format: json, yaml, or table (default)
546
+ -i INTERVAL output the ps table every INTERVAL seconds
536
547
  -h this help
537
548
  ```
538
549
 
@@ -553,7 +564,7 @@ The script displays a formatted table with columns:
553
564
  * **PROCESSOR** - CPU/GPU allocation percentage
554
565
  * **CONTEXT** - Context window size
555
566
  * **PARAMS** - Parameter count (e.g., 30.5B, 23M)
556
- * **QUANT** - Quantization level (e.g., Q4_K_M, F16)
567
+ * **QUANT** - Quantization level (e.g., `Q4_K_M`, `F16`)
557
568
  * **UNTIL** - Time until model expiration
558
569
 
559
570
  Example output:
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- # vim: set filetype=ruby et sw=2 ts=2:
2
-
3
1
  require 'gem_hadar'
4
2
 
5
3
  GemHadar do
data/bin/ollama_ps CHANGED
@@ -190,6 +190,8 @@ def ps_table(models)
190
190
  puts table
191
191
  end
192
192
 
193
+ c = Term::ANSIColor
194
+
193
195
  opts = go 'f:i:h'
194
196
 
195
197
  opts[?h] and usage
@@ -204,14 +206,18 @@ when 'yaml'
204
206
  else
205
207
  duration = opts[?i].to_i.clamp(0..)
206
208
  begin
207
- print Term::ANSIColor.clear_screen, Term::ANSIColor.move_home if duration > 0
209
+ print c.move_home, c.erase_in_display(nil) if duration > 0
208
210
  if models = fetch_ps_models.full?
209
211
  ps_table(interpret_models(models))
210
212
  end
211
- duration == 0 and break
213
+ duration == 0 and exit 0
212
214
  sleep duration
215
+ rescue Interrupt
216
+ puts "\n *** Interrupted."
217
+ exit 0
213
218
  rescue => e
214
219
  warn "Caught #{e.class}: #{e}"
215
220
  sleep duration
216
- end while duration
221
+ end while duration > 0
222
+ exit 1
217
223
  end
@@ -40,7 +40,7 @@ class Ollama::Commands::Chat
40
40
  # @param stream [ TrueClass, FalseClass, nil ] whether to enable streaming for the operation
41
41
  # @param keep_alive [ String, nil ] duration to keep the model loaded in memory
42
42
  # @param think [ Boolean, String, nil ] whether to enable thinking mode for
43
- # generation. Can be "high", "medium", "low" instead of true
43
+ # generation. Can be "max", "high", "medium", "low" instead of true
44
44
  def initialize(model:, messages:, tools: nil, format: nil, options: nil, stream: nil, keep_alive: nil, think: nil)
45
45
  @model, @messages, @tools, @format, @options, @stream, @keep_alive, @think =
46
46
  model, as_array_of_hashes(messages), as_array_of_hashes(tools),
@@ -43,7 +43,7 @@ class Ollama::Commands::Generate
43
43
  # @param raw [ Boolean, nil ] whether to return raw output without formatting
44
44
  # @param keep_alive [ String, nil ] duration to keep the model loaded in memory
45
45
  # @param think [ Boolean, String, nil ] whether to enable thinking mode for
46
- # generation. Can be "high", "medium", "low" instead of true
46
+ # generation. Can be "max", "high", "medium", "low" instead of true
47
47
  def initialize(model:, prompt:, suffix: nil, images: nil, format: nil, options: nil, system: nil, template: nil, context: nil, stream: nil, raw: nil, keep_alive: nil, think: nil)
48
48
  @model, @prompt, @suffix, @images, @format, @options, @system, @template, @context, @stream, @raw, @keep_alive, @think =
49
49
  model, prompt, suffix, (Array(images) if images), format, options, system, template, context, stream, raw, keep_alive, think
@@ -45,7 +45,7 @@ class Ollama::Handlers::Markdown
45
45
  if @stream
46
46
  @content << content
47
47
  markdown_content = Kramdown::ANSI.parse(@content)
48
- @output.print clear_screen, move_home, markdown_content
48
+ @output.print move_home, erase_in_display(nil), markdown_content
49
49
  else
50
50
  markdown_content = Kramdown::ANSI.parse(content)
51
51
  @output.print markdown_content
@@ -68,6 +68,9 @@ class Ollama::Options
68
68
  # Maximum number of tokens to predict - limits generation length
69
69
  num_predict: Integer,
70
70
 
71
+ # Number of tokens for draft model - speculative decoding
72
+ draft_num_predict: Integer,
73
+
71
74
  # Top-K sampling - limits sampling to top K tokens
72
75
  top_k: Integer,
73
76
 
@@ -112,7 +115,7 @@ class Ollama::Options
112
115
 
113
116
  # Stop sequences - array of strings that will stop generation
114
117
  stop: Array,
115
- }
118
+ }.freeze
116
119
 
117
120
  @@types.each do |name, type|
118
121
  attr_reader name
@@ -158,4 +161,51 @@ class Ollama::Options
158
161
  def self.[](value)
159
162
  new(**value.to_h)
160
163
  end
164
+
165
+ # The from_string method creates a new instance of the class from a
166
+ # multi-line parameter string.
167
+ #
168
+ # This class method parses a string in the format used by the Ollama
169
+ # `show` endpoint's `parameters` field, where each line contains a
170
+ # parameter name and its value separated by whitespace. It infers the
171
+ # Ruby type for each value (Boolean, Integer, Float) based on the
172
+ # pattern, and accumulates array-typed parameters (e.g. `stop`)
173
+ # into an array. Unknown or unparseable lines are silently skipped.
174
+ #
175
+ # @example Parsing a `show` parameter block
176
+ # Options.from_string(<<~PARAMS)
177
+ # temperature 0.8
178
+ # top_k 40
179
+ # top_p 0.9
180
+ # stop <|start_header_id|>
181
+ # stop <|end_header_id|>
182
+ # PARAMS
183
+ # # => #<Ollama::Options temperature=0.8, top_k=40, …
184
+ #
185
+ # @param string [ String ] a multi-line parameter string as returned by
186
+ # the `show` endpoint's `parameters` field
187
+ #
188
+ # @return [ self ] a new instance of the class with the parsed attributes
189
+ def self.from_string(string)
190
+ self[
191
+ string.lines.each_with_object({}) do |l, h|
192
+ k, v = l.chomp.split(/\s+/, 2)
193
+ k = k.to_sym
194
+ h[k] =
195
+ case v
196
+ when 'true' then true
197
+ when 'false' then false
198
+ when /\A(?:-)?\d+\z/ then Integer(v)
199
+ else
200
+ if @@types[k] == Array
201
+ (h[k] ||= []) << v
202
+ else
203
+ Float(v)
204
+ end
205
+ end
206
+ rescue
207
+ nil
208
+ end.compact
209
+ ]
210
+ end
161
211
  end
@@ -1,6 +1,6 @@
1
1
  module Ollama
2
2
  # Ollama version
3
- VERSION = '1.23.1'
3
+ VERSION = '1.24.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.23.1 ruby lib
2
+ # stub: ollama-ruby 1.24.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama-ruby".freeze
6
- s.version = "1.23.1".freeze
6
+ s.version = "1.24.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,13 +18,13 @@ 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.17".freeze
21
+ s.rubygems_version = "4.0.22".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
 
25
25
  s.specification_version = 4
26
26
 
27
- s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.17.1".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.18.0".freeze])
28
28
  s.add_development_dependency(%q<all_images>.freeze, ["~> 0.12".freeze])
29
29
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
30
30
  s.add_development_dependency(%q<kramdown>.freeze, ["~> 2.0".freeze])
@@ -22,7 +22,7 @@ describe Ollama::Handlers::Markdown do
22
22
 
23
23
  it 'can markdown response as markdown' do
24
24
  output = double('output', :sync= => true)
25
- expect(output).to receive(:print).with("\e[2J", "\e[1;1H", ansi)
25
+ expect(output).to receive(:print).with("\e[1;1H", "\e[J", ansi)
26
26
  markdown = described_class.new(output:)
27
27
  response = double('response', response: md, done: false)
28
28
  markdown.call(response)
@@ -32,7 +32,7 @@ describe Ollama::Handlers::Markdown do
32
32
 
33
33
  it 'can markdown message content as markdown' do
34
34
  output = double('output', :sync= => true)
35
- expect(output).to receive(:print).with("\e[2J", "\e[1;1H", ansi)
35
+ expect(output).to receive(:print).with("\e[1;1H", "\e[J", ansi)
36
36
  markdown = described_class.new(output:)
37
37
  response = double('response', response: nil, message: double(content: md), done: false)
38
38
  markdown.call(response)
@@ -53,4 +53,58 @@ describe Ollama::Options do
53
53
  expect { described_class.new(penalize_newline: :tertium) }.
54
54
  to raise_error(TypeError)
55
55
  end
56
+
57
+ context '.from_string' do
58
+ it 'parses boolean values' do
59
+ result = described_class.from_string("use_mmap true\nuse_mlock false")
60
+ expect(result.use_mmap).to be true
61
+ expect(result.use_mlock).to be false
62
+ end
63
+
64
+ it 'parses integer values' do
65
+ result = described_class.from_string("num_ctx 8192\nnum_batch 512")
66
+ expect(result.num_ctx).to eq(8192)
67
+ expect(result.num_batch).to eq(512)
68
+ end
69
+
70
+ it 'parses negative integers' do
71
+ result = described_class.from_string("num_predict -1")
72
+ expect(result.num_predict).to eq(-1)
73
+ end
74
+
75
+ it 'parses float values' do
76
+ result = described_class.from_string("temperature 0.7\ntop_p 0.95")
77
+ expect(result.temperature).to be_within(1e-6).of(0.7)
78
+ expect(result.top_p).to be_within(1e-6).of(0.95)
79
+ end
80
+
81
+ it 'accumulates array values for multi-line keys' do
82
+ result = described_class.from_string(<<~EOS)
83
+ stop <|start_header_id|>
84
+ stop <|end_header_id|>
85
+ stop <|eot_id|>
86
+ EOS
87
+ expect(result.stop).to eq(
88
+ ['<|start_header_id|>', '<|end_header_id|>', '<|eot_id|>']
89
+ )
90
+ end
91
+
92
+ it 'handles mixed types in a single block' do
93
+ result = described_class.from_string(<<~EOS)
94
+ use_mmap true
95
+ num_ctx 4096
96
+ temperature 0.8
97
+ stop end
98
+ EOS
99
+ expect(result.use_mmap).to be true
100
+ expect(result.num_ctx).to eq(4096)
101
+ expect(result.temperature).to be_within(1e-6).of(0.8)
102
+ expect(result.stop).to eq(['end'])
103
+ end
104
+
105
+ it 'skips unparseable lines gracefully' do
106
+ result = described_class.from_string("temperature 0.7\ngarbage hello")
107
+ expect(result.temperature).to be_within(1e-6).of(0.7)
108
+ end
109
+ end
56
110
  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.23.1
4
+ version: 1.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 2.17.1
18
+ version: 2.18.0
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 2.17.1
25
+ version: 2.18.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: all_images
28
28
  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.17
427
+ rubygems_version: 4.0.22
428
428
  specification_version: 4
429
429
  summary: Interacting with the Ollama API
430
430
  test_files: