ollama_chat 0.0.102 → 0.0.104

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: 568c2c35b6cac06a63868dd50e7d3acdcc6bfea902fdb2c17046a1ebb9804323
4
- data.tar.gz: 48fbcad533cd2142d2af419b14ef742cb0ec52fa1fbc17fdc8f2c46bef6b7711
3
+ metadata.gz: 3c49eaf9f13a4ed9059d931dca9fdde0c634280496426e0339c0e117de7b8340
4
+ data.tar.gz: 5bdcaa702ae84492475c6acfb3bdf9cd559aae3ac3c39ae535bd3aa6312fed03
5
5
  SHA512:
6
- metadata.gz: bab0b5327f79e741f114d777a55db7b77d0661df872fc28b4c65c653c8163c9d78cd79785c5c551395ce7db353956fc4bb97690fdeb6774abfe2d536934cab04
7
- data.tar.gz: 1e1a80b0046cda70de6f32be4bd4b662de25aa7e2adf0a2acb7882ca87eef82a373e7cb9421172d5ca5aa469bdd2937722f222d570a61660e2eeb91fa461b912
6
+ metadata.gz: ec2836dc21c758dd687734e921a8aadd85ca42bb2d827d6f160a690f5870294276f8dd7421699421de7231e71c697e3eace26e31606f6496aeaab8c367c32049
7
+ data.tar.gz: 1cc7c1bbd4dc27b28dbc5296bcd4bf7084bc0f493e2a3826cbf2623f9bd3749637729a182d8d89cc2b34c5fac71f7c80b40510f5022d9d64a8b707c6199a1398
data/CHANGES.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-07-31 v0.0.104
4
+
5
+ ### Changed
6
+
7
+ #### Added
8
+
9
+ - Enabled interactive profile creation with duplicate validation by supporting
10
+ the `allow_new` keyword argument in `choose_profile_for_model`.
11
+
12
+ #### Changed
13
+
14
+ - Standardized API naming conventions by renaming the `offer_new_session`
15
+ parameter to `allow_new` in `session_management.rb` and `choose_session`.
16
+ - Updated `commands.rb` to pass `allow_new: true` to `choose_profile_for_model`
17
+ during `/model options` and implemented an early return on profile selection
18
+ cancellation.
19
+ - Renamed the `OllamaChat::Tools::RetrieveDocumentSnippets` class to
20
+ `SearchKnowledge`.
21
+ - Updated tool registration, default configuration, and descriptions for
22
+ `search_knowledge` to reference knowledge collections.
23
+
24
+ #### Fixed
25
+
26
+ - Adjusted `commands_spec.rb` test cases to reflect updated method signatures
27
+ and expected behavior for profile selection.
28
+
29
+ ## 2026-07-30 v0.0.103
30
+
31
+ ### Added
32
+
33
+ - Introduced `-y` (on) and `-n` (off) flags to the `/toggle` command for
34
+ explicit state setting via `set(true, show: true)` or `set(false, show:
35
+ true)`.
36
+ - Added startup logging to the Chat client in the `start` method of `chat.rb`,
37
+ recording the `client` and `server` versions, URL, `user`, and config
38
+ filename.
39
+ - Implemented path templating support using `%{path}` in
40
+ `lib/ollama_chat/tools/run_tests.rb` and documented its usage in
41
+ `lib/ollama_chat/oc.rb`.
42
+ - Added the `-m` flag to the `/model` command to enable interactive model
43
+ selection via `choose_model`.
44
+ - Integrated JSON parsing for the last line of test output within execution
45
+ logs.
46
+
47
+ ### Changed
48
+
49
+ - Optimized the `/model change` command by moving option parsing after an early
50
+ exit for the `change` subcommand.
51
+ - Simplified the `/model` command by removing the `-p` flag and introducing
52
+ `choose_profile_for_model` for automatic profile resolution, falling back to
53
+ the `'default'` profile.
54
+ - Refactored `use_model` and related methods to utilize keyword shorthand.
55
+ - Updated `model_handling.rb` methods (`edit_model_options`,
56
+ `copy_model_options_from_session`, and `copy_model_options_to_session`) to
57
+ accept an optional `model_name` argument.
58
+ - Standardized emoji rendering in tmux using Unicode escape sequences and
59
+ Variation Selector-16 across `lib/ollama_chat/commands.rb`,
60
+ `lib/ollama_chat/dialog.rb`, `lib/ollama_chat/favourites_management.rb` (via
61
+ `prefix_favourite`), and `lib/ollama_chat/information.rb`.
62
+ - Updated the `OLLAMA_CHAT_TOOLS_TEST_RUNNER` environment variable to include
63
+ the `--no-color` flag for `bundle exec rspec`.
64
+
65
+ ### Fixed
66
+
67
+ - Ensured the Jira tool is unconfigured in specs by setting the
68
+ `OC::OLLAMA::CHAT::TOOLS::JIRA::URL` constant to `nil` using `const_conf_as`.
69
+
70
+ ### Refactored
71
+
72
+ - Reorganized command specs into dedicated `describe` blocks for `/copy`,
73
+ `/paste`, `/toggle`, and `/clear` within `commands_spec.rb`.
74
+ - Moved `handle_input` test cases from `chat_spec.rb` to a new
75
+ `commands_spec.rb`.
76
+ - Updated parsing specs in `spec/ollama_chat/parsing_spec.rb` to conditionally
77
+ skip tests based on the presence of `gs` (Postscript/PDF) or `pandoc` (EPUB).
78
+
79
+ ### Dependencies
80
+ - Updated `rubygems_version` to **4.0.17**.
81
+
3
82
  ## 2026-07-26 v0.0.102
4
83
 
5
84
  - Added `ollama_chat_log` executable to the gem manifest in the `Rakefile` and
data/README.md CHANGED
@@ -420,10 +420,10 @@ context, manipulate files, and retrieve external information.
420
420
  | **Web/External** | `search_web`, `get_url`, `browse`, `get_rfc`, `get_cve`, `get_endoflife`, `get_ghr`, `get_jira_issue` | Access the internet, fetch specific URLs, and look up technical standards. |
421
421
  | **System/Util** | `get_time`, `get_location`, `get_current_weather`, `generate_password`, `compute_bmi`, `roll_dice` | General utility functions for time, location, and simple calculations. |
422
422
  | **Editor/Clip** | `copy_to_clipboard`, `paste_from_clipboard`, `paste_into_editor`, `open_file_in_editor` | Bridge the gap between the chat and the system clipboard or editor. |
423
- | **Knowledge** | `retrieve_document_snippets`, `file_context` | Semantic search for specific snippets vs. broad retrieval of structured project context. |
423
+ | **Knowledge** | `search_knowledge`, `file_context` | Semantic search for specific snippets vs. broad retrieval of structured project context. |
424
424
  | **Multimodal** | `generate_image` | Generate images via a local ComfyUI server. |
425
425
 
426
- ***Note on Knowledge Tools**: Use `retrieve_document_snippets` for precise,
426
+ ***Note on Knowledge Tools**: Use `search_knowledge` for precise,
427
427
  low-token semantic discovery and `file_context` for a comprehensive view of
428
428
  modules or patterns. Be cautious with broad patterns in `file_context`, as
429
429
  importing too many files can exceed the LLM's context window.*
@@ -169,6 +169,10 @@ class OllamaChat::Chat
169
169
  # The start method initializes the chat session by displaying information,
170
170
  # then prompts the user for input to begin interacting with the chat.
171
171
  def start
172
+ log(:info, 'Starting chat client', data: {
173
+ client:, server: { version: server_version, url: server_url }, user:,
174
+ config: @ollama_chat_config.filename,
175
+ })
172
176
  begin
173
177
  if model = session.current_model.full?
174
178
  use_model(model, keep_options: true)
@@ -335,16 +339,17 @@ class OllamaChat::Chat
335
339
  !!@parse_content
336
340
  end
337
341
 
338
- # Returns whether there is a prompt waiting to be prefilled into the input buffer.
342
+ # Returns the prefill prompt string if one exists and is not empty, or nil
343
+ # otherwise.
339
344
  #
340
- # @return [Boolean] true if a prefill prompt exists and is not empty, false otherwise
345
+ # @return [String, NilClass] the prefill prompt string, or nil if not set or empty
341
346
  def prefill_prompt
342
347
  @prefill_prompt.full?
343
348
  end
344
349
 
345
- # Sets the content to be prefilled into the next user input prompt.
346
- #
347
- # @param prefill_prompt [String, nil] The text to prefill, or nil to clear it
350
+ # @!attribute [w] prefill_prompt=
351
+ # Sets the content to be prefilled into the next user input prompt.
352
+ # @return [String, NilClass] the prompt
348
353
  attr_writer :prefill_prompt
349
354
 
350
355
  # Signals a graceful shutdown of the application.
@@ -58,7 +58,7 @@ module OllamaChat::Commands
58
58
  complete: [ 'config', %w[ edit reload ] ],
59
59
  optional: true,
60
60
  help: <<~EOT
61
- ⚙️ View, edit, or reload configuration
61
+ \u2699\uFE0F View, edit, or reload configuration
62
62
  EOT
63
63
  ) do |subcommand|
64
64
  case subcommand
@@ -86,19 +86,33 @@ module OllamaChat::Commands
86
86
 
87
87
  command(
88
88
  name: :toggle,
89
- regexp: %r(^/toggle(?:\s+(markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding))?$),
89
+ regexp: %r(^/toggle(?:\s+(markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding)(?:\s+(-[yn]))?)?$),
90
90
  complete: [ 'toggle', %w[ markdown stream location runtime_info voice think_loud think_strip embedding ] ],
91
91
  help: <<~EOT
92
92
  🎛️ Toggle feature switches
93
93
  (markdown, stream, location, runtime_info,
94
94
  voice, think_loud, think_strip, embedding)
95
+ Options: -y (on), -n (off)
95
96
  EOT
96
- ) do |toggle_name|
97
+ ) do |toggle_name, flag|
97
98
  if toggle_name == 'embedding'
98
- embedding_paused.toggle(show: false)
99
+ if flag == '-y'
100
+ embedding_paused.set(false)
101
+ elsif flag == '-n'
102
+ embedding_paused.set(true)
103
+ else
104
+ embedding_paused.toggle(show: false)
105
+ end
99
106
  embedding.show
100
107
  elsif toggle_name
101
- send(toggle_name).toggle
108
+ switch = send(toggle_name)
109
+ if flag == '-y'
110
+ switch.set(true, show: true)
111
+ elsif flag == '-n'
112
+ switch.set(false, show: true)
113
+ else
114
+ switch.toggle
115
+ end
102
116
  else
103
117
  STDOUT.puts "Available toggles: markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding"
104
118
  end
@@ -110,7 +124,7 @@ module OllamaChat::Commands
110
124
  regexp: %r(^/favourite(?:\s+(add|delete))?(?:\s+(model|prompt|system|persona|suggest))$),
111
125
  complete: [ 'favourite', %w[ add delete ], %w[ model prompt system persona suggest ] ],
112
126
  help: <<~EOT
113
- Manage favorites (add/delete models,
127
+ \u2B50\uFE0F Manage favorites (add/delete models,
114
128
  prompts, personae)
115
129
  EOT
116
130
  ) do |subcommand, type|
@@ -125,34 +139,40 @@ module OllamaChat::Commands
125
139
 
126
140
  command(
127
141
  name: :model,
128
- regexp: %r(^/model(?:\s+(change|options|options from session|options to session))(?:\s+(-p\s*\w+))?$),
142
+ regexp: %r(^/model(?:\s+(change|options|options from session|options to session))?((?:\s+(?:-m))*)$),
129
143
  complete: [ 'model', %w[ change options options\ from\ session options\ to\ session ] ],
130
144
  help: <<~EOT
131
145
  🤖 Manage AI models & profiles:
132
- - change: Switch active model (-p [profile])
146
+ - change: Switch active model
133
147
  - options: Edit saved profile config
134
148
  - options from session: Save live → Saved
135
149
  - options to session: Apply Saved → Live
150
+ -m interactively choose a model
136
151
  EOT
137
152
  ) do |subcommand, opts|
138
- case subcommand
139
- when 'change'
140
- opts = go_command('p:', opts, defaults: { ?p => 'default' })
153
+ if subcommand == 'change'
141
154
  begin
142
- use_model(profile: opts[?p])
155
+ model = choose_model('', @model)
156
+ profile = choose_profile_for_model(model) || 'default'
157
+ use_model(model, profile:)
143
158
  rescue OllamaChat::UnknownModelError => e
144
159
  msg = "Caught #{e.class}: #{e}"
145
- log(:error, msg, data: { command: 'model', profile: opts[?p] }, warn: true)
160
+ log(:error, msg, data: { command: 'model', profile: }, warn: true)
146
161
  end
162
+ next :next
163
+ end
164
+ opts = go_command('m', opts)
165
+ model = opts[?m] ? choose_model('', @model) : @model
166
+ case subcommand
147
167
  when 'options'
148
- opts = go_command('p:', opts, defaults: { ?p => 'default' })
149
- edit_model_options(@model, profile: opts[?p])
168
+ profile = choose_profile_for_model(model, allow_new: true) or next :next
169
+ edit_model_options(model, profile:)
150
170
  when 'options from session'
151
- opts = go_command('p:', opts, defaults: { ?p => 'default' })
152
- copy_model_options_from_session(profile: opts[?p])
171
+ profile = choose_profile_for_model(model) || 'default'
172
+ copy_model_options_from_session(model, profile:)
153
173
  when 'options to session'
154
- opts = go_command('p:', opts, defaults: { ?p => 'default' })
155
- copy_model_options_to_session(profile: opts[?p])
174
+ profile = choose_profile_for_model(model) || 'default'
175
+ copy_model_options_to_session(model, profile:)
156
176
  end
157
177
  :next
158
178
  end
@@ -720,7 +740,7 @@ module OllamaChat::Commands
720
740
  name: :compose,
721
741
  regexp: %r(^/compose$),
722
742
  help: <<~EOT
723
- ✍️ Compose message in external editor
743
+ \u270D\uFE0F Compose message in external editor
724
744
  EOT
725
745
  ) do
726
746
  edit_text.full? or :next
@@ -930,7 +950,7 @@ module OllamaChat::Commands
930
950
  complete: [ 'info', %w[ session model runtime rag ] ],
931
951
  optional: true,
932
952
  help: <<~EOT,
933
- ℹ️ Show info:
953
+ \u2139\uFE0F Show info:
934
954
  - session: Current chat details
935
955
  - model: Active AI model info
936
956
  - runtime: System/environmental data
@@ -59,14 +59,14 @@ module OllamaChat::Dialog
59
59
  case
60
60
  when yes.nil?
61
61
  if keypress
62
- output.puts "⌨️ #{answer}"
62
+ output.puts "\u2328\uFE0F #{answer}"
63
63
  else
64
- output.puts "⌛️ #{answer}"
64
+ output.puts "\u231B\uFE0F #{answer}"
65
65
  end
66
66
  answer
67
67
  when answer =~ yes
68
68
  if keypress
69
- output.puts " #{answer}"
69
+ output.puts "\u2705\uFE0F #{answer}"
70
70
  else
71
71
  output.puts "☑️ #{answer}"
72
72
  end
@@ -75,7 +75,7 @@ module OllamaChat::Dialog
75
75
  if keypress
76
76
  output.puts "🚫 #{answer}"
77
77
  else
78
- output.puts "⌛️ #{answer}"
78
+ output.puts "\u231B\uFE0F #{answer}"
79
79
  end
80
80
  nil
81
81
  end
@@ -11,7 +11,7 @@ module OllamaChat::FavouritesManagement
11
11
  # @param favourited [Boolean] whether the item is a favourite
12
12
  # @return [String] the decorated string
13
13
  def prefix_favourite(string, favourited)
14
- fav = favourited ? '❤️' : '🩶'
14
+ fav = favourited ? "\u2764\uFE0F" : '🩶'
15
15
  "%s %s" % [ fav, string ]
16
16
  end
17
17
 
@@ -134,7 +134,7 @@ module OllamaChat::Information
134
134
  output.print ' '; think_loud.show(output:)
135
135
  output.print ' '; think_strip.show(output:)
136
136
  output.print ' 🛠️ '; tools_support.show(output:)
137
- output.print '⚙️ Chat Settings'
137
+ output.print "\u2699\uFE0F Chat Settings"
138
138
  output.print ' '; markdown.show(output:)
139
139
  output.print ' '; stream.show(output:)
140
140
  output.print ' 🎙️ '; voice.show(output:)
@@ -108,8 +108,9 @@ module OllamaChat::ModelHandling
108
108
  # Ollama::Options instance based on the edited configuration.
109
109
  #
110
110
  # @param model_name [String] the name of the model whose options are to be
111
- # edited.
112
- def edit_model_options(model_name, profile: nil)
111
+ # edited, defaults to @model.
112
+ def edit_model_options(model_name = nil, profile: nil)
113
+ model_name ||= @model
113
114
  profile ||= 'default'
114
115
  model_options = get_stored_model_options(model_name, profile:)
115
116
  model_options = fill_up_model_options(model_options)
@@ -147,36 +148,60 @@ module OllamaChat::ModelHandling
147
148
  # This method retrieves the options stored for the current session and
148
149
  # updates the active model options to match, ensuring the model behavior
149
150
  # aligns with the session's specific configuration.
150
- def copy_model_options_from_session(profile: nil)
151
+ #
152
+ # @param model_name [String, nil] the model to use; defaults to @model
153
+ # @param profile [String, nil] the profile context for model options
154
+ def copy_model_options_from_session(model_name = nil, profile: nil)
151
155
  profile ||= 'default'
152
- model_name = @model
156
+ model_name ||= @model
153
157
  model_options = get_session_model_options
154
158
  store_model_options(model_name, model_options, profile:)
155
159
  STDOUT.puts "Model options #{italic{profile}} for #{bold{model_name}} were copied from session model options."
156
160
  end
157
161
 
158
162
  # Resets the session's model options to match the stored defaults for the
159
- # current model.
160
- def copy_model_options_to_session(profile: nil)
163
+ # specified model.
164
+ #
165
+ # @param model_name [String, nil] the model to use; defaults to @model
166
+ # @param profile [String, nil] the profile context for model options
167
+ def copy_model_options_to_session(model_name = nil, profile: nil)
161
168
  profile ||= 'default'
162
- model_name = @model
169
+ model_name ||= @model
163
170
  stored_model_options = get_stored_model_options(model_name, profile:)
164
171
  session.update(model_options: stored_model_options)
165
172
  STDOUT.puts "Model options #{italic{profile}} of #{bold{model_name}} were copied to session model options."
166
173
  end
167
174
 
168
- # Presents a list of stored profiles for the given model and prompts the user
169
- # to select one.
175
+ # Presents an interactive list of stored configuration profiles for the
176
+ # specified model and prompts the user to select one.
177
+ #
178
+ # If only one profile exists for the model, it is returned immediately without
179
+ # prompting. If the user cancels the selection or chooses `[EXIT]`, `nil` is
180
+ # returned.
170
181
  #
171
182
  # @param model_name [String] the name of the model whose profiles are to be listed
172
- # @return [String, nil] the selected profile name, or nil if none was chosen
173
- def choose_profile_for_model(model_name)
183
+ # @return [String, nil] the selected profile name, or `nil` if none was chosen
184
+ def choose_profile_for_model(model_name, allow_new: false)
174
185
  profiles = models::ModelOptions.where(model_name:).order(:profile).map(&:profile)
175
- profiles = [ '[EXIT]' ] + profiles
186
+
187
+ if allow_new
188
+ profiles = [ '[EXIT]', '[NEW]' ] + profiles
189
+ else
190
+ profiles.size < 2 and return profiles.first
191
+ profiles = [ '[EXIT]' ] + profiles
192
+ end
193
+
176
194
  case chosen = choose_entry(profiles, prompt: "Choose profile for #{bold{model_name}}: %s")
177
195
  when '[EXIT]', nil
178
196
  STDOUT.puts "Cancelled."
179
197
  return
198
+ when '[NEW]'
199
+ name = ask("Enter new profile name: ") or return
200
+ if models::ModelOptions.where(model_name:, profile: name).exists?
201
+ STDERR.puts "Profile #{name.inspect} already exists!"
202
+ return
203
+ end
204
+ name
180
205
  else
181
206
  chosen
182
207
  end
@@ -319,7 +344,7 @@ module OllamaChat::ModelHandling
319
344
  # metadata for the selected model.
320
345
  #
321
346
  # @param model [ String, nil ] the model name to use; if omitted, the current
322
- # model is retained
347
+ # model can be selected
323
348
  # @param keep_options [Boolean] if true, session-specific model options are
324
349
  # retained instead of reverting to model defaults.
325
350
  #
@@ -328,7 +353,7 @@ module OllamaChat::ModelHandling
328
353
  profile ||= 'default'
329
354
  old_model = @model
330
355
 
331
- if model.nil?
356
+ if model.blank?
332
357
  @model = choose_model('', @model)
333
358
  else
334
359
  @model = choose_model(model, config.model.name)
@@ -169,7 +169,11 @@ module OC
169
169
 
170
170
  # Run Tests tool configuration
171
171
  TEST_RUNNER = set do
172
- description 'Configured test runner for run_tests tool function'
172
+ description <<~EOT
173
+ Test runner command template. Use %{path} to specify where the test
174
+ path argument goes; otherwise it is appended at the end.
175
+ EOT
176
+
173
177
  default 'rspec'
174
178
  required true
175
179
  end
@@ -57,7 +57,7 @@ prompts:
57
57
  - Current directory is "%{current_directory}"
58
58
  - Client is %{client}.
59
59
  - These tools have access to these allowed paths: %{tool_paths_allowed}
60
- - Search in these collections with `retrieve_document_snippets`: %{collections}
60
+ - Search in these collections with `search_knowledge`: %{collections}
61
61
  dynamic_runtime_info: |
62
62
  There is usually no reason to mention this information to the user unless
63
63
  asked about it.
@@ -525,7 +525,7 @@ tools:
525
525
  default: true
526
526
  allowed:
527
527
  - './tmp'
528
- retrieve_document_snippets:
528
+ search_knowledge:
529
529
  result_display_timeout: 3
530
530
  default: true
531
531
  compute_bmi:
@@ -231,7 +231,7 @@ module OllamaChat::SessionManagement
231
231
  # @return [OllamaChat::Database::Models::Session] the initialized session
232
232
  def setup_session
233
233
  @session = if session_name = @opts[?l]
234
- choose_session(session_name, offer_new_session: true)
234
+ choose_session(session_name, allow_new: true)
235
235
  elsif @opts[?n]
236
236
  new_session
237
237
  else
@@ -262,7 +262,7 @@ module OllamaChat::SessionManagement
262
262
  will be deleted, pick a new session to switch to.
263
263
  EOT
264
264
  confirm?(prompt: "\n⏎ Press any key to continue (%s). ", timeout: 3)
265
- chosen = choose_session(??, except_id: current_session_id, offer_new_session: true, exit_app: true)
265
+ chosen = choose_session(??, except_id: current_session_id, allow_new: true, exit_app: true)
266
266
  if chosen == :quit_app
267
267
  STDOUT.puts "Exiting application."
268
268
  exit 0
@@ -423,7 +423,7 @@ module OllamaChat::SessionManagement
423
423
  name.full? or name = ??
424
424
  previous_session_id = nil
425
425
  loop do
426
- if chosen_session = choose_session(name, offer_new_session: true)
426
+ if chosen_session = choose_session(name, allow_new: true)
427
427
  if chosen_session.nil? || chosen_session == session
428
428
  confirm?(
429
429
  prompt: "\n⏎ Same session chosen, Press any key to continue (%s). ",
@@ -468,9 +468,9 @@ module OllamaChat::SessionManagement
468
468
  #
469
469
  # @param session_name [String] the name, ID, or pattern to search for
470
470
  # @param except_id [String, Integer, nil] an ID to exclude from the search results
471
- # @param offer_new_session [Boolean] whether to offer creating a new session
471
+ # @param allow_new [Boolean] whether to offer creating a new session
472
472
  # @return [OllamaChat::Database::Models::Session, nil] the chosen session or nil
473
- def choose_session(session_name, except_id: nil, offer_new_session: false, exit_app: false)
473
+ def choose_session(session_name, except_id: nil, allow_new: false, exit_app: false)
474
474
  session_name = session_name.to_s
475
475
  session_query = models::Session
476
476
  if except_id
@@ -514,7 +514,7 @@ module OllamaChat::SessionManagement
514
514
  session_name = if sessions.size == 1
515
515
  sessions.first.value
516
516
  else
517
- offer_new_session and sessions.unshift(SearchUI::Wrapper.new('[new]', display: '[NEW]'))
517
+ allow_new and sessions.unshift(SearchUI::Wrapper.new('[new]', display: '[NEW]'))
518
518
  if exit_app
519
519
  sessions.unshift(SearchUI::Wrapper.new('[quit-app]', display: '[QUIT-APP]'))
520
520
  end
@@ -23,8 +23,10 @@ class OllamaChat::Tools::RunTests
23
23
  description: <<~EOT,
24
24
  Test Runner - Runs all tests/specs under *path* the path were the
25
25
  tests/specs are located. `coverage=false` by default; set to true
26
- for a coverage report. Returns JSON with test counts and, if
27
- requested, coverage percentage.
26
+ for a coverage report. Returns JSON with the raw output and
27
+ status. After execution, provide a concise overview of the test
28
+ run, summarizing examples, failures, and coverage percentage
29
+ if available.
28
30
  EOT
29
31
  parameters: Tool::Function::Parameters.new(
30
32
  type: 'object',
@@ -57,8 +59,9 @@ class OllamaChat::Tools::RunTests
57
59
  coverage = tool_call.function.arguments.coverage || false
58
60
  path = check_path(path, config)
59
61
  output, success = run_tests(path, coverage)
62
+ result = JSON.parse(output.lines.last) rescue nil
60
63
  chat.log(:info, "Tests executed", data: {
61
- tool: name, path: path.to_s, success:
64
+ tool: name, path: path.to_s, success:, result:
62
65
  })
63
66
 
64
67
  message =
@@ -110,7 +113,11 @@ class OllamaChat::Tools::RunTests
110
113
  # @return [String, Boolean] the captured output and a success flag
111
114
  def run_tests(path, coverage)
112
115
  env = ENV.to_h | { 'START_SIMPLECOV' => coverage ? '1' : '0' }
113
- cmd = [ test_runner, Shellwords.escape(path) ].join(' ')
116
+ runner = test_runner
117
+ unless runner.include?('%{path}')
118
+ runner = runner.gsub('%', '%%') % ' %{path}'
119
+ end
120
+ cmd = runner % { path: Shellwords.escape(path) }
114
121
  output, success = execute_test_command(env, cmd)
115
122
  return output, success
116
123
  end
@@ -16,12 +16,12 @@
16
16
  #
17
17
  # @note The tool is deliberately read‑only; it never mutates the chat or
18
18
  # the underlying document store.
19
- class OllamaChat::Tools::RetrieveDocumentSnippets
19
+ class OllamaChat::Tools::SearchKnowledge
20
20
  include OllamaChat::Tools::Concern
21
21
  include Kramdown::ANSI::Width
22
22
 
23
23
  # @return [String] the registered name for this tool
24
- def self.register_name = 'retrieve_document_snippets'
24
+ def self.register_name = 'search_knowledge'
25
25
 
26
26
  # Function‑definition that the chat system exposes to the model.
27
27
  # It follows the same pattern as other tools in the project.
@@ -34,8 +34,8 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
34
34
  function: Tool::Function.new(
35
35
  name:,
36
36
  description: <<~EOT,
37
- Return document snippets from the current collection of documents
38
- that match the supplied query. The result is a JSON string containing
37
+ Search the local knowledge collections for text matching the
38
+ supplied query. The result is a JSON string containing
39
39
  a prompt header and an array of {text, tags} objects.
40
40
  EOT
41
41
  parameters: Tool::Function::Parameters.new(
@@ -44,7 +44,7 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
44
44
  query: Tool::Function::Parameters::Property.new(
45
45
  type: 'string',
46
46
  description: <<~EOT,
47
- The query or text to search for in the document collection.
47
+ The query or text to search for in the knowledge collections.
48
48
  EOT
49
49
  ),
50
50
  tags: Tool::Function::Parameters::Property.new(
@@ -58,7 +58,7 @@ class OllamaChat::Tools::RetrieveDocumentSnippets
58
58
  collection: Tool::Function::Parameters::Property.new(
59
59
  type: 'string',
60
60
  description: <<~EOT,
61
- The document collection to search in for the query or text.
61
+ The specific knowledge collection to search in.
62
62
  EOT
63
63
  ),
64
64
  min_similarity: Tool::Function::Parameters::Property.new(
@@ -68,7 +68,7 @@ require 'ollama_chat/tools/paste_into_editor'
68
68
  require 'ollama_chat/tools/patch_file'
69
69
  require 'ollama_chat/tools/read_file'
70
70
  require 'ollama_chat/tools/resolve_tag'
71
- require 'ollama_chat/tools/retrieve_document_snippets'
71
+ require 'ollama_chat/tools/search_knowledge'
72
72
  require 'ollama_chat/tools/roll_dice'
73
73
  require 'ollama_chat/tools/run_tests'
74
74
  require 'ollama_chat/tools/search_web'
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.102'
3
+ VERSION = '0.0.104'
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: