ollama_chat 0.0.129 → 0.0.130

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: 9aae892b3b152a70e519a4d5a6268f046611c55d5b8ecfda66e2e4386a4681db
4
- data.tar.gz: '038e498781b238aef6f3d6ff595ec3beb50d00b7efd722f8636bcb87a273bbb2'
3
+ metadata.gz: 01d91ba996f30f84990c3d3eb60d0e65cc46b3eb0c593bd55eab6cc580e935e1
4
+ data.tar.gz: 28563308f748187b5cf15dcad886a775dcb6d2abd3c4466ab66854a10dec63fd
5
5
  SHA512:
6
- metadata.gz: 740289c0e7fdf453718f120f26fa201f68c1f677777b71e440789df72bb14db52526026114adb06ce15a2ea93b78ce6e39a478bfe77a22c1657692e1a5162445
7
- data.tar.gz: 1b553c6648636b5088857f199a21cd87b86836c59df746fa50c504569be8609fd0181c3b233dda977a065cefdddfda1cd7ce7640a154a742bef8ab7392513346
6
+ metadata.gz: edb330105098a15cb10bb0edaaca0131c1f339568c5639d2bc75b02adfaf1a4e0b94176e663e45784e9fb0d978732c854a680b937d135205bcb88c943c02c8b0
7
+ data.tar.gz: 2dff67556aab12d5ad4a9a72239ffa34982804cfa311970a42bf35af33ad1e848baf94f82d74e9e65f21724019963b016c05823fa7e1ec40e01f7b511c1824fd
data/CHANGES.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-08 v0.0.130
4
+
5
+ * Replace `ask?` with `confirm?` in `rag_handling.rb` for the `[v]iew` /
6
+ `[c]lear` prompts in `#clear_collection_tags` and
7
+ `#clear_collection_sources` to bypass `Reline` and keep command history
8
+ clean.
9
+ * Add `use_pager(force: true)` in the `#clear_collection_sources` view branch
10
+ to fix display.
11
+ * Rewrite `confirm?` YARD documentation in `dialog.rb` to clarify the
12
+ two-branch return contract (`yes: nil` → raw char, `yes:` matcher → matched
13
+ char or `nil`) and history-pollution rationale.
14
+ * Swap 7 `ask?` → `confirm?` stubs in `rag_handling_spec.rb`.
15
+ * Add `line_numbers: true` to the `read_file` tool block in
16
+ `default_config.yml`.
17
+ * Update `read_file.rb` to fall back to `tool_config.line_numbers?` when the
18
+ model omits the argument and interpolate the live default into the tool
19
+ description.
20
+ * Fix typo in description: `linenumbers` → `line numbers`.
21
+ * Update specs to extract `let :tool`, adjust `nil`-arg expectations for the
22
+ `1: ` prefix, checksum, and `line_count`, and add a new spec asserting raw
23
+ content when `tool_config.line_numbers` is stubbed to `false`.
24
+
3
25
  ## 2026-10-08 v0.0.129
4
26
 
5
27
  ### Features
@@ -29,21 +29,37 @@ module OllamaChat::Dialog
29
29
  prefill and Reline.pre_input_hook = old_pre_input_hook
30
30
  end
31
31
 
32
- # The confirm? method displays a prompt and reads a single character input
33
- # from the user in raw mode, then returns that character. This is best used
34
- # for confirmation prompts.
32
+ # The confirm? method displays a prompt and reads a **single keypress**
33
+ # from the user in raw mode (no Enter required), returning that character.
34
+ # Unlike {#ask?}, it does not go through Reline, so it never pollutes the
35
+ # command history — making it the right tool for confirmation gates *and*
36
+ # terse single-key selections such as `[v]iew` / `[c]lear` menus.
37
+ #
38
+ # The returned value depends on whether a positive-response matcher (`yes`)
39
+ # is supplied:
40
+ #
41
+ # - `yes: nil` (default) — the raw keypress is returned verbatim so the
42
+ # caller can dispatch on it (e.g. `case key; when /\Av/i; ...`); on
43
+ # timeout the `default` value is returned, and on interrupt (Ctrl-C)
44
+ # `nil` is returned.
45
+ # - `yes: <Regexp/Object>` — the keypress is returned only when it
46
+ # satisfies `yes === keypress` (e.g. `yes: /\Ay/i`); any other keypress,
47
+ # or an interrupt, yields `nil`.
35
48
  #
36
49
  # @param prompt [String] the prompt to display to the user
37
50
  # @param timeout [Integer, nil] optional timeout in seconds; if nil, the
38
- # method blocks until input, if 0 the method immediately returns the default
39
- # value.
51
+ # method blocks until input, if 0 it immediately returns the `default`
52
+ # value without waiting.
40
53
  # @param default [Object, nil] value returned when the timeout expires
41
54
  # (defaults to `nil`)
42
- # @param yes [Object, nil] value that is considered a positive response
55
+ # @param yes [Object, nil] matcher (`#===`) that defines a positive
56
+ # response; when `nil` the raw keypress is returned for the caller to
57
+ # interpret (default: `nil`)
43
58
  # @param output [IO] the IO object to write the prompt and the answer to
44
59
  #
45
- # @return [Object] the character entered by the user, the `default` value
46
- # if a timeout occurs, or `nil` if the read is interrupted (e.g. Ctrl-C)
60
+ # @return [Object, nil] see the dispatch rules above: the keypress (or
61
+ # `default` on timeout / `nil` on interrupt) when `yes:` is nil, otherwise
62
+ # the keypress only if it matches `yes`, else `nil`.
47
63
  def confirm?(prompt:, timeout: nil, default: nil, yes: nil, output: STDOUT)
48
64
  return default if timeout&.zero?
49
65
  if prompt.include?('%s')
@@ -623,6 +623,7 @@ tools:
623
623
  default: true
624
624
  require_confirmation: false
625
625
  result_display_timeout: 3
626
+ line_numbers: true
626
627
  allowed:
627
628
  - './tmp'
628
629
  - './lib'
@@ -248,7 +248,7 @@ module OllamaChat::RAGHandling
248
248
  label = source ? "#{source} #{snippet}" : snippet
249
249
  feedback(label, type: :info)
250
250
  view_tag_records(tag, [record])
251
- ask?(prompt: " [c]lear / other to go back: ") =~ /\Ac/i or next
251
+ confirm?(prompt: " [c]lear / other to go back: ") =~ /\Ac/i or next
252
252
  clear_tag_records(tag, source)
253
253
  else
254
254
  group_lines = []
@@ -270,7 +270,7 @@ module OllamaChat::RAGHandling
270
270
  )
271
271
  next if chosen.nil? || chosen == '[back]'
272
272
  src, recs = group_map[chosen]
273
- action = ask?(prompt: " [v]iew / [c]lear / other to go back: ")
273
+ action = confirm?(prompt: " [v]iew / [c]lear / other to go back: ")
274
274
  case action
275
275
  when /\Av/i
276
276
  view_tag_records(tag, recs)
@@ -350,11 +350,11 @@ module OllamaChat::RAGHandling
350
350
  break
351
351
  else
352
352
  source = display_map[chosen]
353
- action = ask?(prompt: " [v]iew / [c]lear / other to go back: ")
353
+ action = confirm?(prompt: " [v]iew / [c]lear / other to go back: ")
354
354
  case action
355
355
  when /\Av/i
356
356
  records = @documents.records(sources: [ source ])
357
- use_pager do |output|
357
+ use_pager(force: true) do |output|
358
358
  output.puts "#{bold{source}} (#{records.size} records)"
359
359
  output.puts
360
360
  records.each do |record|
@@ -28,7 +28,7 @@ class OllamaChat::Tools::ReadFile
28
28
  File reader – Returns raw text from path if it’s within allowed
29
29
  directories. No side effects; useful for inspecting config or source
30
30
  files. You can optionally specify a line range to read. You can also
31
- enable prefixing with linenumbers; this is highly recommended (and
31
+ enable prefixing with line numbers; this is highly recommended (and
32
32
  practically mandatory) before calling `open_file_in_editor` to ensure
33
33
  the line range is precise.
34
34
  EOT
@@ -53,8 +53,8 @@ class OllamaChat::Tools::ReadFile
53
53
  line_numbers: Tool::Function::Parameters::Property.new(
54
54
  type: 'boolean',
55
55
  description: <<~EOT
56
- Whether to prefix each line with its line number,
57
- e.g. "666: The line content…
56
+ Whether to prefix each line with its line number, e.g.
57
+ "666: The line content…" (default: #{!!tool_config.line_numbers?})
58
58
  EOT
59
59
  )
60
60
  },
@@ -77,12 +77,12 @@ class OllamaChat::Tools::ReadFile
77
77
  # @return [String] an error message as a JSON string if the operation fails
78
78
  # @raise [JSON::ParserError] if the result cannot be serialized to JSON
79
79
  def execute(tool_call, **opts)
80
-
81
80
  args = tool_call.function.arguments
82
81
 
83
82
  start_line = args.start_line.full?
84
83
  end_line = args.end_line.full?
85
84
  line_numbers = args.line_numbers
85
+ line_numbers.nil? and line_numbers = !!tool_config.line_numbers?
86
86
 
87
87
  path = assert_valid_path(args.path, tool_config.allowed?, check: :file)
88
88
  full_content = path.read
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.129'
3
+ VERSION = '0.0.130'
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_chat.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama_chat 0.0.129 ruby lib
2
+ # stub: ollama_chat 0.0.130 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama_chat".freeze
6
- s.version = "0.0.129".freeze
6
+ s.version = "0.0.130".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]
@@ -141,7 +141,7 @@ describe OllamaChat::RAGHandling do
141
141
  with(a_string_including('hello world'), type: :info)
142
142
  buf = StringIO.new
143
143
  expect(chat).to receive(:use_pager).and_yield(buf)
144
- expect(chat).to receive(:ask?).and_return('c')
144
+ expect(chat).to receive(:confirm?).and_return('c')
145
145
  expect(docs).to receive(:collection).at_least(:once).
146
146
  and_return('default')
147
147
  expect(docs).to receive(:clear).with(tags: [ 'mem' ])
@@ -164,7 +164,7 @@ describe OllamaChat::RAGHandling do
164
164
  with(a_string_including('hello world'), type: :info)
165
165
  buf = StringIO.new
166
166
  expect(chat).to receive(:use_pager).and_yield(buf)
167
- expect(chat).to receive(:ask?).and_return('x')
167
+ expect(chat).to receive(:confirm?).and_return('x')
168
168
  expect(chat).to receive(:feedback).with('Exiting chooser.')
169
169
  chat.clear_collection_tags
170
170
  expect(buf.string).to include('hello world')
@@ -186,7 +186,7 @@ describe OllamaChat::RAGHandling do
186
186
  with(a_string_including('a.rb'), type: :info)
187
187
  buf = StringIO.new
188
188
  expect(chat).to receive(:use_pager).and_yield(buf)
189
- expect(chat).to receive(:ask?).and_return('c')
189
+ expect(chat).to receive(:confirm?).and_return('c')
190
190
  expect(docs).to receive(:collection).at_least(:once).
191
191
  and_return('default')
192
192
  expect(docs).to receive(:source_remove).with('a.rb')
@@ -214,7 +214,7 @@ describe OllamaChat::RAGHandling do
214
214
  and_return('t1', 'a.rb "aaa"', '[EXIT]')
215
215
  expect(docs).to receive(:records).with(tags: 't1').
216
216
  and_return([ rec1, rec2 ])
217
- expect(chat).to receive(:ask?).and_return('c')
217
+ expect(chat).to receive(:confirm?).and_return('c')
218
218
  expect(docs).to receive(:collection).at_least(:once).
219
219
  and_return('default')
220
220
  expect(docs).to receive(:source_remove).with('a.rb')
@@ -263,7 +263,7 @@ describe OllamaChat::RAGHandling do
263
263
  expect(docs).to receive(:records).at_least(:once).
264
264
  and_return([ rec ])
265
265
  expect(chat).to receive(:choose_entry).and_return('a.rb [t1]', '[EXIT]')
266
- expect(chat).to receive(:ask?).and_return('c')
266
+ expect(chat).to receive(:confirm?).and_return('c')
267
267
  expect(docs).to receive(:collection).at_least(:once).
268
268
  and_return('default')
269
269
  expect(docs).to receive(:source_remove).with('a.rb')
@@ -280,7 +280,7 @@ describe OllamaChat::RAGHandling do
280
280
  expect(docs).to receive(:records).at_least(:once).
281
281
  and_return([ rec ])
282
282
  expect(chat).to receive(:choose_entry).and_return('a.rb [t1]', '[EXIT]')
283
- expect(chat).to receive(:ask?).and_return('v')
283
+ expect(chat).to receive(:confirm?).and_return('v')
284
284
 
285
285
  buf = StringIO.new
286
286
  expect(chat).to receive(:use_pager).and_yield(buf)
@@ -295,7 +295,7 @@ describe OllamaChat::RAGHandling do
295
295
  and_return([ rec ])
296
296
  expect(chat).to receive(:choose_entry).
297
297
  and_return('a.rb [t1]', '[EXIT]')
298
- expect(chat).to receive(:ask?).and_return('x')
298
+ expect(chat).to receive(:confirm?).and_return('x')
299
299
  expect(chat).to receive(:feedback).with('Exiting chooser.')
300
300
  chat.clear_collection_sources
301
301
  end
@@ -1,20 +1,24 @@
1
1
  describe OllamaChat::Tools::ReadFile do
2
- let(:chat) do
2
+ let :chat do
3
3
  OllamaChat::Chat.new(argv: chat_default_config)
4
4
  end
5
5
 
6
+ let :tool do
7
+ described_class.new(chat)
8
+ end
9
+
6
10
  connect_to_ollama_server
7
11
 
8
12
  it 'can have name' do
9
- expect(described_class.new(chat).name).to eq 'read_file'
13
+ expect(tool.name).to eq 'read_file'
10
14
  end
11
15
 
12
16
  it 'can have tool' do
13
- expect(described_class.new(chat).tool).to be_a Ollama::Tool
17
+ expect(tool.tool).to be_a Ollama::Tool
14
18
  end
15
19
 
16
20
  it 'can be converted to hash' do
17
- expect(described_class.new(chat).to_hash).to be_a Hash
21
+ expect(tool.to_hash).to be_a Hash
18
22
  end
19
23
 
20
24
 
@@ -32,7 +36,38 @@ describe OllamaChat::Tools::ReadFile do
32
36
  )
33
37
  )
34
38
 
35
- result = described_class.new(chat).execute(tool_call)
39
+ result = tool.execute(tool_call)
40
+
41
+ expect(result).to be_a(String)
42
+ json = json_object(result)
43
+ expect(json.path).to include 'example.rb'
44
+ expect(json.content).to eq <<~EOT
45
+ 1: puts "Hello World!"
46
+ EOT
47
+ expect(json.message).to match(/Read .+ from/)
48
+ expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
49
+ expect(json.line_count).to eq 1
50
+ expect(json.checksum).to match(/\A[0-9a-f]{8}\z/)
51
+ expect(described_class.summary_template(result:))\
52
+ .to match(/Read .+ from/)
53
+ end
54
+
55
+ it 'can be executed successfully with config line_numbers false' do
56
+ expect(tool.expose.tool_config).to receive(:line_numbers).and_return false
57
+ tool_call = double(
58
+ 'ToolCall',
59
+ function: double(
60
+ name: 'read_file',
61
+ arguments: double(
62
+ path: asset('example.rb'),
63
+ start_line: nil,
64
+ end_line: nil,
65
+ line_numbers: nil,
66
+ )
67
+ )
68
+ )
69
+
70
+ result = tool.execute(tool_call)
36
71
 
37
72
  expect(result).to be_a(String)
38
73
  json = json_object(result)
@@ -40,14 +75,15 @@ describe OllamaChat::Tools::ReadFile do
40
75
  expect(json.content).to eq <<~EOT
41
76
  puts "Hello World!"
42
77
  EOT
43
- expect(json.message).to include('Read 6.0 T (20.0 B) from')
78
+ expect(json.message).to match(/Read .+ from/)
44
79
  expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
45
80
  expect(json.line_count).to be_nil
46
- expect(json.checksum).not_to be_present
81
+ expect(json.checksum).not_to match(/\A[0-9a-f]{8}\z/)
47
82
  expect(described_class.summary_template(result:))\
48
- .to include('Read 6.0 T (20.0 B) from')
83
+ .to match(/Read .+ from/)
49
84
  end
50
85
 
86
+
51
87
  it 'can extract range when start_line is provided and end_line is nil' do
52
88
  tool_call = double(
53
89
  'ToolCall',
@@ -61,12 +97,12 @@ describe OllamaChat::Tools::ReadFile do
61
97
  )
62
98
  )
63
99
  )
64
- result = described_class.new(chat).execute(tool_call)
100
+ result = tool.execute(tool_call)
65
101
  json = json_object(result)
66
- expect(json.content).to eq "puts \"Hello World!\"\n"
67
- expect(json.message).to include('Read 6.0 T (20.0 B) from')
102
+ expect(json.content).to eq "1: puts \"Hello World!\"\n"
103
+ expect(json.message).to match(/Read .+ from/)
68
104
  expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
69
- expect(json.line_count).to be_nil
105
+ expect(json.line_count).to eq 1
70
106
  expect(json.checksum).not_to be_present
71
107
  end
72
108
 
@@ -83,12 +119,12 @@ describe OllamaChat::Tools::ReadFile do
83
119
  )
84
120
  )
85
121
  )
86
- result = described_class.new(chat).execute(tool_call)
122
+ result = tool.execute(tool_call)
87
123
  json = json_object(result)
88
- expect(json.content).to eq "puts \"Hello World!\"\n"
89
- expect(json.message).to include('Read 6.0 T (20.0 B) from')
124
+ expect(json.content).to eq "1: puts \"Hello World!\"\n"
125
+ expect(json.message).to match(/Read .+ from/)
90
126
  expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
91
- expect(json.line_count).to be_nil
127
+ expect(json.line_count).to eq 1
92
128
  expect(json.checksum).not_to be_present
93
129
  end
94
130
 
@@ -105,7 +141,7 @@ describe OllamaChat::Tools::ReadFile do
105
141
  )
106
142
  )
107
143
  )
108
- result = described_class.new(chat).execute(tool_call)
144
+ result = tool.execute(tool_call)
109
145
  json = json_object(result)
110
146
  expect(json.content).to eq ''
111
147
  expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
@@ -126,7 +162,7 @@ describe OllamaChat::Tools::ReadFile do
126
162
  )
127
163
  )
128
164
  )
129
- result = described_class.new(chat).execute(tool_call)
165
+ result = tool.execute(tool_call)
130
166
  json = json_object(result)
131
167
  expect(json.content).to include("1: puts \"Hello World!\"\n")
132
168
  expect(json.line_count).to eq 1
@@ -146,7 +182,7 @@ describe OllamaChat::Tools::ReadFile do
146
182
  )
147
183
  )
148
184
  )
149
- result = described_class.new(chat).execute(tool_call)
185
+ result = tool.execute(tool_call)
150
186
  json = json_object(result)
151
187
  expect(json.content).not_to include("1: ")
152
188
  expect(json.mtime).to match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
@@ -167,7 +203,7 @@ describe OllamaChat::Tools::ReadFile do
167
203
  )
168
204
  )
169
205
  )
170
- result = described_class.new(chat).execute(tool_call)
206
+ result = tool.execute(tool_call)
171
207
  json = json_object(result)
172
208
  expect(json.content).to eq(<<~EOT)
173
209
  2: John Doe,32,Software Engineer
@@ -192,7 +228,7 @@ describe OllamaChat::Tools::ReadFile do
192
228
  )
193
229
  )
194
230
 
195
- result = described_class.new(chat).execute(tool_call)
231
+ result = tool.execute(tool_call)
196
232
 
197
233
  # Should return valid JSON with error
198
234
  expect(result).to be_a(String)
@@ -219,7 +255,7 @@ describe OllamaChat::Tools::ReadFile do
219
255
  )
220
256
  )
221
257
 
222
- result = described_class.new(chat).execute(tool_call)
258
+ result = tool.execute(tool_call)
223
259
 
224
260
  # Should return valid JSON with error
225
261
  expect(result).to be_a(String)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama_chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.129
4
+ version: 0.0.130
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank