ollama_chat 0.0.116 → 0.0.117

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: beebfc1a29093b596fe008ba59b2f377922e2f7beeeb529ebed899fc374c6e02
4
- data.tar.gz: e704bce9b15101283e802a6010ee08c347cf94d8fcdc2ee785da3880debde736
3
+ metadata.gz: cbe0a034dee8079ea14e573b0e98624ebaa3311baaf60e1bd666d7f7b0d61dda
4
+ data.tar.gz: 2a2b0c1b00ce5db2fa4b20660d8cda86669f1bac50e62352a07953e0c327d863
5
5
  SHA512:
6
- metadata.gz: 7cab4e5d47d97dd215e058ab9960ad8801252a2ab950d3b30ce1e514fad30b22e87f917e3b1764592070f385fcfec748cc3b59398cadf8e3553f41e6ec48e9bb
7
- data.tar.gz: 0fb71bb0ab178cb1fed41ea2b257360fd19d3d180a2fc2f497d1372874d4665c3b82676ad8c056ab80a22e21e95deebb8afee8ef5f2809a07671e6cfb53ba5d7
6
+ metadata.gz: f187ae33f48c198b1aa15d680b5d7dd45e96c8ba7bcb71bf80adf5d0cb049a766d79d57d8bad32175363c490cfe94a94908b1eba4a1ba28a8b0e9896065079ed
7
+ data.tar.gz: 0d61b926d6e7018d5f21d52ed06d36e81ea859dc5f288a0247834def14245813f1306bf444baaf715c8ec37df20ea64d97f03279045e34eb669a29c9facadb23
data/CHANGES.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-09-03 v0.0.117
4
+
5
+ * Fixed `/favourite` subcommand completion rendering by replacing separate
6
+ `add`/`delete` and type arrays in `complete` with `.product`, ensuring each
7
+ subcommand renders as an explicit pair (e.g., `add model`, `delete
8
+ persona`) instead of being independently cross-multiplied by `arguments`.
9
+ * Added command categories to help output:
10
+ * Added `category(name)` and `current_category` class methods to
11
+ `command_concern.rb` for tracking the active category during
12
+ registration.
13
+ * Added `category:` keyword to `command` and `Command#initialize` with
14
+ `attr_reader :category`.
15
+ * Reworked `help_message` to sort commands by `[category, name]` and
16
+ insert bold full-width category header rows via `colspan: 4`.
17
+ * Added `extend Term::ANSIColor` to the `included` block for `bold{}`
18
+ access.
19
+ * Replaced `## Section` comments in `commands.rb` with `category
20
+ :Section` calls.
21
+ * Added two new categories: `Models` (`/model`, `/think`) and `Prompts`
22
+ (`/prompt`, `/system`, `/suggest`).
23
+ * Moved session-persisted commands (`/toggle`, `/tools`, `/voice`,
24
+ `/document_policy`, `/context_format`) under `category :Session`.
25
+ * Moved `/change_response` and `/conversation` under `category
26
+ :Conversation`.
27
+ * Reduced `Settings` to app-level commands only (`/config`,
28
+ `/favourite`).
29
+ * Made `report_session` a pure generator:
30
+ * Removed `&block` parameter and `block&.(result)` call from
31
+ `report_session`, eliminating the infobar side-effect that caused
32
+ double output.
33
+ * Simplified `report_conversation` to call `report_session(name:)`
34
+ without a block; display logic (pager or file write) is the sole
35
+ consumer of the returned string.
36
+ * Removed `@param block [Proc]` from `report_session` YARD docs.
37
+
3
38
  ## 2026-09-03 v0.0.116
4
39
 
5
40
  ### Added
@@ -11,6 +11,20 @@ module OllamaChat::CommandConcern
11
11
  # `Command` instances.
12
12
  attr_accessor :commands
13
13
 
14
+ # @return [Symbol] the category currently in effect for new commands
15
+ def current_category
16
+ (@category || :Misc).to_sym
17
+ end
18
+
19
+ # Set the category that subsequent `command` registrations will be
20
+ # assigned to. Commands registered without an explicit `category:`
21
+ # keyword inherit the current category (defaults to `:Misc`).
22
+ #
23
+ # @param name [String, Symbol] the category name
24
+ def category(name)
25
+ @category = name.to_sym
26
+ end
27
+
14
28
  # Register a new command.
15
29
  #
16
30
  # @param name [String, Symbol] The primary name of the command.
@@ -24,17 +38,19 @@ module OllamaChat::CommandConcern
24
38
  # @param options [String, nil] A string describing command options
25
39
  # for help output.
26
40
  # @param help [String, nil] Short help text for the command.
41
+ # @param category [Symbol] Category for grouping in help output
42
+ # (defaults to `current_category`).
27
43
  # @yield [context] Block that receives a binding context for
28
44
  # execution. The block must be provided.
29
45
  #
30
46
  # @raise [ArgumentError] if a command with the same name already
31
47
  # exists or if no block is given.
32
- def command(name:, regexp:, complete: nil, optional: false, options: nil, help: nil, &block)
48
+ def command(name:, regexp:, complete: nil, optional: false, options: nil, help: nil, category: current_category, &block)
33
49
  name = name.to_sym
34
50
  commands.key?(name) and
35
51
  raise ArgumentError, "command #{name} already registered!"
36
- commands[name] =Command.new(
37
- name:, regexp:, complete:, optional:, options:, help:, &block
52
+ commands[name] = Command.new(
53
+ name:, regexp:, complete:, optional:, options:, help:, category:, &block
38
54
  )
39
55
  end
40
56
 
@@ -52,15 +68,18 @@ module OllamaChat::CommandConcern
52
68
  #
53
69
  # @param pattern [String, Regexp, nil] An optional pattern to filter
54
70
  # commands by their names.
55
- # @return [Terminal::Table] A table with columns CMD, SUBCMD, OPTS, HELP.
71
+ # @return [Terminal::Table] A table with columns CMD, SUBCMD, OPTS, HELP,
72
+ # with bold category header rows inserted between groups.
56
73
  def help_message(pattern = nil)
57
74
  table = Terminal::Table.new
58
75
  table.style = {
59
76
  all_separators: true,
60
77
  border: :unicode_round,
61
78
  }
62
- table.headings = %w[ CMD SUBCMD OPTS HELP ]
63
- commands.each_value do |command|
79
+ table.headings = %w[ CMD SUBCMD OPTS HELP ]
80
+ sorted_commands = self.commands.sort_by { [ _2.category, _2.name ] }.map(&:last)
81
+ cat = nil
82
+ sorted_commands.each do |command|
64
83
  command.help or next
65
84
  if pattern
66
85
  command.command_names.any? { _1 =~ pattern } or next
@@ -72,6 +91,10 @@ module OllamaChat::CommandConcern
72
91
  [ _1, (?﹡ unless command.optional?) ].compact.join
73
92
  }.sort.join(?\n)
74
93
  }
94
+ if cat != command.category
95
+ cat = command.category
96
+ table << [ { value: bold{cat}, colspan: 4 } ]
97
+ end
75
98
  table << [
76
99
  "%s" % command.command_names.map { ?/ + _1 }.join(?\n),
77
100
  '%s' % subcommands,
@@ -91,6 +114,8 @@ module OllamaChat::CommandConcern
91
114
  delegate :command_completions, to: self
92
115
 
93
116
  delegate :help_message, to: self
117
+
118
+ extend Term::ANSIColor
94
119
  end
95
120
 
96
121
  # Represents a registered command in the OllamaChat command DSL.
@@ -117,13 +142,14 @@ module OllamaChat::CommandConcern
117
142
  # @param optional [Boolean] Whether the command is optional.
118
143
  # @param options [String, nil] Options description.
119
144
  # @param help [String] Help text.
145
+ # @param category [Symbol] Category for grouping in help output.
120
146
  # @yield [context] Execution block.
121
147
  #
122
148
  # @raise [ArgumentError] if no block is given.
123
- def initialize(name:, regexp:, complete: nil, optional: false, options: nil, help:, &block)
149
+ def initialize(name:, regexp:, complete: nil, optional: false, options: nil, help:, category:, &block)
124
150
  block or raise ArgumentError, 'require &block'
125
- @name, @regexp, @optional, @options, @help, @block =
126
- name, regexp, optional, options, help, block
151
+ @name, @regexp, @optional, @options, @help, @category, @block =
152
+ name, regexp, optional, options, help, category, block
127
153
  @complete = Array(complete || name.to_s).map { Array(_1) }
128
154
  end
129
155
 
@@ -133,6 +159,9 @@ module OllamaChat::CommandConcern
133
159
  # @return [String] Help text for the command.
134
160
  attr_reader :help
135
161
 
162
+ # @return [Symbol] Category for grouping in help output.
163
+ attr_reader :category
164
+
136
165
  # @return [String, nil] Options description.
137
166
  attr_reader :options
138
167
 
@@ -22,7 +22,7 @@ require 'ollama_chat/command_concern'
22
22
  module OllamaChat::Commands
23
23
  include OllamaChat::CommandConcern
24
24
 
25
- ## Clipboard
25
+ category :Clipboard
26
26
 
27
27
  command(
28
28
  name: :copy,
@@ -58,7 +58,7 @@ module OllamaChat::Commands
58
58
  end
59
59
  end
60
60
 
61
- ## Settings
61
+ category :Settings
62
62
 
63
63
  command(
64
64
  name: :config,
@@ -85,14 +85,67 @@ module OllamaChat::Commands
85
85
  end
86
86
 
87
87
  command(
88
- name: :document_policy,
89
- regexp: %r(^/document policy$),
90
- complete: %w[ document policy ],
88
+ name: :favourite,
89
+ regexp: %r(^/favourite(?:\s+(add|delete))?(?:\s+(model|prompt|system|persona|suggest))$),
90
+ complete: [ 'favourite', %w[ add delete ].product(%w[ model prompt system persona suggest ]) ],
91
91
  help: <<~EOT
92
- 📜 Select a scanning policy for documents
92
+ \u2B50\uFE0F Manage favorites (add/delete models,
93
+ prompts, personae)
93
94
  EOT
94
- ) do
95
- document_policy.choose
95
+ ) do |subcommand, type|
96
+ case subcommand
97
+ when 'add'
98
+ add_favourite(type)
99
+ when 'delete'
100
+ delete_favourite(type)
101
+ end
102
+ :next
103
+ end
104
+
105
+ category :Session
106
+
107
+ command(
108
+ name: :session,
109
+ regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|delete|model options change|model options))?((?:\s+-(?:p\s*\w+))*)(?:\s+([^-].*))?$),
110
+ complete: [ 'session', %w[ change previous list new duplicate rename delete model\ options\ change model\ options ] ],
111
+ optional: true,
112
+ options: "[-p profile]\n[name]",
113
+ help: <<~EOT
114
+ 💬 Manage sessions:
115
+ - list/new/delete/rename/duplicate
116
+ - change [name]/previous
117
+ - model options/change
118
+ EOT
119
+ ) do |subcommand, opts, name|
120
+ case subcommand
121
+ when nil
122
+ info_session
123
+ when 'list'
124
+ list_sessions
125
+ when 'new'
126
+ set_new_session
127
+ when 'duplicate'
128
+ duplicate_session
129
+ when 'delete'
130
+ delete_session
131
+ when 'rename'
132
+ rename_session
133
+ when 'change'
134
+ change_session(name)
135
+ when 'model options'
136
+ edit_session_model_options
137
+ when 'model options change'
138
+ opts = go_command('p:', opts)
139
+ if profile = opts[?p] || choose_profile_for_model(@model)
140
+ copy_model_options_to_session(profile:)
141
+ end
142
+ when 'previous'
143
+ if prev = previous_session
144
+ change_session(prev.id)
145
+ else
146
+ STDOUT.puts "No previous session defined."
147
+ end
148
+ end
96
149
  :next
97
150
  end
98
151
 
@@ -132,123 +185,6 @@ module OllamaChat::Commands
132
185
  :next
133
186
  end
134
187
 
135
- command(
136
- name: :favourite,
137
- regexp: %r(^/favourite(?:\s+(add|delete))?(?:\s+(model|prompt|system|persona|suggest))$),
138
- complete: [ 'favourite', %w[ add delete ], %w[ model prompt system persona suggest ] ],
139
- help: <<~EOT
140
- \u2B50\uFE0F Manage favorites (add/delete models,
141
- prompts, personae)
142
- EOT
143
- ) do |subcommand, type|
144
- case subcommand
145
- when 'add'
146
- add_favourite(type)
147
- when 'delete'
148
- delete_favourite(type)
149
- end
150
- :next
151
- end
152
-
153
- command(
154
- name: :model,
155
- regexp: %r(^/model(?:\s+(change|options(?: copy| delete| export| import)?|options from session|options to session))?((?:\s+(?:-m|-p\s+[\S]+))*)$),
156
- complete: [ 'model', %w[ change options options\ copy options\ delete options\ export options\ import options\ from\ session options\ to\ session ] ],
157
- options: '[-m|-p pattern]',
158
- help: <<~EOT
159
- 🤖 Manage AI models & profiles:
160
- - change: Switch active model
161
- - options: Edit saved profile config
162
- - options copy: Copy profile from another model
163
- - options delete: Delete a saved profile
164
- - options export: Export ALL model profiles to JSON
165
- - options import: Selectively import profiles from JSON
166
- - options from session: Save live → Saved
167
- - options to session: Apply Saved → Live
168
- -m interactively choose a model
169
- -p PATTERN narrow file search for import
170
- EOT
171
- ) do |subcommand, opts|
172
- if subcommand == 'change'
173
- begin
174
- model = choose_model('', @model)
175
- profile = choose_profile_for_model(model) || 'default'
176
- use_model(model, profile:)
177
- rescue OllamaChat::UnknownModelError => e
178
- msg = "Caught #{e.class}: #{e}"
179
- log(:error, msg, data: { command: 'model', profile: }, warn: true)
180
- end
181
- next :next
182
- end
183
- opts = go_command('mp:', opts)
184
- model = opts[?m] ? choose_model('', @model) : @model
185
- case subcommand
186
- when 'options'
187
- profile = choose_profile_for_model(model, allow_new: true) or next :next
188
- edit_model_options(model, profile:)
189
- when 'options copy'
190
- copy_model_options_profile(model)
191
- when 'options delete'
192
- delete_model_options_profile(model)
193
- when 'options from session'
194
- profile = choose_profile_for_model(model) || 'default'
195
- copy_model_options_from_session(model, profile:)
196
- when 'options to session'
197
- profile = choose_profile_for_model(model) || 'default'
198
- copy_model_options_to_session(model, profile:)
199
- when 'options export'
200
- export_model_options
201
- when 'options import'
202
- pattern = opts[?p] || '**/*.json'
203
- filename = choose_filename(pattern) or next :next
204
- import_model_options(filename)
205
- end
206
- :next
207
- end
208
-
209
- command(
210
- name: :system,
211
- regexp: %r(^/system(?:\s+(change))?$),
212
- complete: [ 'system', %w[ change ] ],
213
- optional: true,
214
- help: <<~EOT,
215
- 🧬 Manage active system prompt (change)
216
- Note: Use '/prompt -c system' for managing
217
- (add, delete, edit, list, etc.) system templates.
218
- EOT
219
- ) do |subcommand, filename|
220
- case subcommand
221
- when 'change'
222
- change_system_prompt(@messages.system_name)
223
- @messages.show_system_prompt
224
- when nil
225
- @messages.show_system_prompt
226
- end
227
- :next
228
- end
229
-
230
- command(
231
- name: :think,
232
- regexp: %r(^/think$),
233
- help: <<~EOT
234
- 🧠 Configure model thinking mode
235
- EOT
236
- ) do
237
- think_mode.choose
238
- :next
239
- end
240
-
241
- command(
242
- name: :context_format,
243
- regexp: %r(^/context_format$),
244
- help: <<~EOT,
245
- 📐 Set context format (JSON|TOON)
246
- EOT
247
- ) do
248
- context_format.choose
249
- :next
250
- end
251
-
252
188
  command(
253
189
  name: :tools,
254
190
  regexp: %r(^/tools(?:\s+(on|off|enable|disable))?),
@@ -287,54 +223,31 @@ module OllamaChat::Commands
287
223
  :next
288
224
  end
289
225
 
290
- ## Session
291
-
292
226
  command(
293
- name: :session,
294
- regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|delete|model options change|model options))?((?:\s+-(?:p\s*\w+))*)(?:\s+([^-].*))?$),
295
- complete: [ 'session', %w[ change previous list new duplicate rename delete model\ options\ change model\ options ] ],
296
- optional: true,
297
- options: "[-p profile]\n[name]",
227
+ name: :document_policy,
228
+ regexp: %r(^/document policy$),
229
+ complete: %w[ document policy ],
298
230
  help: <<~EOT
299
- 💬 Manage sessions:
300
- - list/new/delete/rename/duplicate
301
- - change [name]/previous
302
- - model options/change
231
+ 📜 Select a scanning policy for documents
303
232
  EOT
304
- ) do |subcommand, opts, name|
305
- case subcommand
306
- when nil
307
- info_session
308
- when 'list'
309
- list_sessions
310
- when 'new'
311
- set_new_session
312
- when 'duplicate'
313
- duplicate_session
314
- when 'delete'
315
- delete_session
316
- when 'rename'
317
- rename_session
318
- when 'change'
319
- change_session(name)
320
- when 'model options'
321
- edit_session_model_options
322
- when 'model options change'
323
- opts = go_command('p:', opts)
324
- if profile = opts[?p] || choose_profile_for_model(@model)
325
- copy_model_options_to_session(profile:)
326
- end
327
- when 'previous'
328
- if prev = previous_session
329
- change_session(prev.id)
330
- else
331
- STDOUT.puts "No previous session defined."
332
- end
333
- end
233
+ ) do
234
+ document_policy.choose
235
+ :next
236
+ end
237
+
238
+ command(
239
+ name: :context_format,
240
+ regexp: %r(^/context_format$),
241
+ help: <<~EOT,
242
+ 📐 Set context format (JSON|TOON)
243
+ EOT
244
+ ) do
245
+ context_format.choose
334
246
  :next
335
247
  end
336
248
 
337
- ## Conversation
249
+
250
+ category :Conversation
338
251
 
339
252
  command(
340
253
  name: :list,
@@ -447,6 +360,77 @@ module OllamaChat::Commands
447
360
  content
448
361
  end
449
362
 
363
+ command(
364
+ name: :change_response,
365
+ regexp: %r(^/change response$),
366
+ complete: %w[ change response ],
367
+ help: <<~EOT,
368
+ ✏️ Edit last AI response in editor
369
+ EOT
370
+ ) do
371
+ change_response
372
+ :next
373
+ end
374
+
375
+ command(
376
+ name: :conversation,
377
+ regexp: %r(^/conversation\s+(clean|compact|save|load|summarize|report)((?:\s+-(?:[sf]|c))*)(?:\s+([^-].*\.jsonl?))?$),
378
+ complete: [ 'conversation', %w[ save load clean compact summarize report ] ],
379
+ options: '[-s|-f|-c] [FILENAME]',
380
+ help: <<~EOT
381
+ 💾 Manage conversation content:
382
+ - save/load: Export/import as .json or .jsonl
383
+ - clean: Remove tool content, images, thinking
384
+ - compact: Summarize old messages, keep recent
385
+ - summarize: Per-message narrative (-s sentence, -f save)
386
+ - report: Generate a session report document
387
+ EOT
388
+ ) do |subcommand,opts,path|
389
+ if %w[ save load ].include?(subcommand) && path.blank?
390
+ STDERR.puts "Require a path as argument to save/load!"
391
+ next :next
392
+ end
393
+ case subcommand
394
+ when 'save'
395
+ opts = go_command('c', opts.to_s)
396
+ save_conversation(path, clean: opts[?c])
397
+ when 'load'
398
+ load_conversation(path)
399
+ repair_group_uuids
400
+ when 'clean'
401
+ if confirm?(
402
+ prompt: '🔔 Clean tool content, images, and thinking from conversation? (y/n) ',
403
+ yes: /\Ay/i
404
+ )
405
+ then
406
+ messages.clean_messages!
407
+ session_sync
408
+ STDOUT.puts "Conversation cleaned."
409
+ else
410
+ STDOUT.puts 'Cancelled.'
411
+ end
412
+ when 'compact'
413
+ if confirm?(
414
+ prompt: '🔔 Compact conversation? Old messages will be summarized. (y/n) ',
415
+ yes: /\Ay/i
416
+ )
417
+ then
418
+ compact_with_retry
419
+ else
420
+ STDOUT.puts 'Cancelled.'
421
+ end
422
+ when 'summarize'
423
+ opts = go_command('sf', opts)
424
+ summarize_conversation(save: opts[?f], sentence: opts[?s])
425
+ when 'report'
426
+ opts = go_command('f', opts)
427
+ report_conversation(save: opts[?f])
428
+ end
429
+ :next
430
+ end
431
+
432
+ category :Prompts
433
+
450
434
  command(
451
435
  name: :prompt,
452
436
  regexp: %r(^/prompt(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|rename|sync|-e))?(\s+(?:-[ef]|-c\s+(?:\w+|\?)))?(?:\s+([^-].*))?$),
@@ -528,6 +512,27 @@ module OllamaChat::Commands
528
512
  :next
529
513
  end
530
514
 
515
+ command(
516
+ name: :system,
517
+ regexp: %r(^/system(?:\s+(change))?$),
518
+ complete: [ 'system', %w[ change ] ],
519
+ optional: true,
520
+ help: <<~EOT,
521
+ 🧬 Manage active system prompt (change)
522
+ Note: Use '/prompt -c system' for managing
523
+ (add, delete, edit, list, etc.) system templates.
524
+ EOT
525
+ ) do |subcommand, filename|
526
+ case subcommand
527
+ when 'change'
528
+ change_system_prompt(@messages.system_name)
529
+ @messages.show_system_prompt
530
+ when nil
531
+ @messages.show_system_prompt
532
+ end
533
+ :next
534
+ end
535
+
531
536
  command(
532
537
  name: :suggest,
533
538
  regexp: %r(^/suggest(\s+(?:-e))?$),
@@ -545,76 +550,76 @@ module OllamaChat::Commands
545
550
  :next
546
551
  end
547
552
 
548
- command(
549
- name: :change_response,
550
- regexp: %r(^/change response$),
551
- complete: %w[ change response ],
552
- help: <<~EOT,
553
- ✏️ Edit last AI response in editor
554
- EOT
555
- ) do
556
- change_response
557
- :next
558
- end
553
+ category :Models
559
554
 
560
555
  command(
561
- name: :conversation,
562
- regexp: %r(^/conversation\s+(clean|compact|save|load|summarize|report)((?:\s+-(?:[sf]|c))*)(?:\s+([^-].*\.jsonl?))?$),
563
- complete: [ 'conversation', %w[ save load clean compact summarize report ] ],
564
- options: '[-s|-f|-c] [FILENAME]',
556
+ name: :model,
557
+ regexp: %r(^/model(?:\s+(change|options(?: copy| delete| export| import)?|options from session|options to session))?((?:\s+(?:-m|-p\s+[\S]+))*)$),
558
+ complete: [ 'model', %w[ change options options\ copy options\ delete options\ export options\ import options\ from\ session options\ to\ session ] ],
559
+ options: '[-m|-p pattern]',
565
560
  help: <<~EOT
566
- 💾 Manage conversation content:
567
- - save/load: Export/import as .json or .jsonl
568
- - clean: Remove tool content, images, thinking
569
- - compact: Summarize old messages, keep recent
570
- - summarize: Per-message narrative (-s sentence, -f save)
571
- - report: Generate a session report document
561
+ 🤖 Manage AI models & profiles:
562
+ - change: Switch active model
563
+ - options: Edit saved profile config
564
+ - options copy: Copy profile from another model
565
+ - options delete: Delete a saved profile
566
+ - options export: Export ALL model profiles to JSON
567
+ - options import: Selectively import profiles from JSON
568
+ - options from session: Save live → Saved
569
+ - options to session: Apply Saved → Live
570
+ -m interactively choose a model
571
+ -p PATTERN narrow file search for import
572
572
  EOT
573
- ) do |subcommand,opts,path|
574
- if %w[ save load ].include?(subcommand) && path.blank?
575
- STDERR.puts "Require a path as argument to save/load!"
573
+ ) do |subcommand, opts|
574
+ if subcommand == 'change'
575
+ begin
576
+ model = choose_model('', @model)
577
+ profile = choose_profile_for_model(model) || 'default'
578
+ use_model(model, profile:)
579
+ rescue OllamaChat::UnknownModelError => e
580
+ msg = "Caught #{e.class}: #{e}"
581
+ log(:error, msg, data: { command: 'model', profile: }, warn: true)
582
+ end
576
583
  next :next
577
584
  end
585
+ opts = go_command('mp:', opts)
586
+ model = opts[?m] ? choose_model('', @model) : @model
578
587
  case subcommand
579
- when 'save'
580
- opts = go_command('c', opts.to_s)
581
- save_conversation(path, clean: opts[?c])
582
- when 'load'
583
- load_conversation(path)
584
- repair_group_uuids
585
- when 'clean'
586
- if confirm?(
587
- prompt: '🔔 Clean tool content, images, and thinking from conversation? (y/n) ',
588
- yes: /\Ay/i
589
- )
590
- then
591
- messages.clean_messages!
592
- session_sync
593
- STDOUT.puts "Conversation cleaned."
594
- else
595
- STDOUT.puts 'Cancelled.'
596
- end
597
- when 'compact'
598
- if confirm?(
599
- prompt: '🔔 Compact conversation? Old messages will be summarized. (y/n) ',
600
- yes: /\Ay/i
601
- )
602
- then
603
- compact_with_retry
604
- else
605
- STDOUT.puts 'Cancelled.'
606
- end
607
- when 'summarize'
608
- opts = go_command('sf', opts)
609
- summarize_conversation(save: opts[?f], sentence: opts[?s])
610
- when 'report'
611
- opts = go_command('f', opts)
612
- report_conversation(save: opts[?f])
588
+ when 'options'
589
+ profile = choose_profile_for_model(model, allow_new: true) or next :next
590
+ edit_model_options(model, profile:)
591
+ when 'options copy'
592
+ copy_model_options_profile(model)
593
+ when 'options delete'
594
+ delete_model_options_profile(model)
595
+ when 'options from session'
596
+ profile = choose_profile_for_model(model) || 'default'
597
+ copy_model_options_from_session(model, profile:)
598
+ when 'options to session'
599
+ profile = choose_profile_for_model(model) || 'default'
600
+ copy_model_options_to_session(model, profile:)
601
+ when 'options export'
602
+ export_model_options
603
+ when 'options import'
604
+ pattern = opts[?p] || '**/*.json'
605
+ filename = choose_filename(pattern) or next :next
606
+ import_model_options(filename)
613
607
  end
614
608
  :next
615
609
  end
616
610
 
617
- ## Collection
611
+ command(
612
+ name: :think,
613
+ regexp: %r(^/think$),
614
+ help: <<~EOT
615
+ 🧠 Configure model thinking mode
616
+ EOT
617
+ ) do
618
+ think_mode.choose
619
+ :next
620
+ end
621
+
622
+ category :Collection
618
623
 
619
624
  command(
620
625
  name: :collection,
@@ -666,7 +671,7 @@ module OllamaChat::Commands
666
671
  :next
667
672
  end
668
673
 
669
- ## Persona
674
+ category :Persona
670
675
 
671
676
  command(
672
677
  name: :persona,
@@ -788,7 +793,7 @@ module OllamaChat::Commands
788
793
  end
789
794
  end
790
795
 
791
- ## Input
796
+ category :Input
792
797
 
793
798
  command(
794
799
  name: :compose,
@@ -930,7 +935,7 @@ module OllamaChat::Commands
930
935
  end
931
936
  end
932
937
 
933
- ## Output
938
+ category :Output
934
939
 
935
940
  command(
936
941
  name: :pipe,
@@ -977,7 +982,7 @@ module OllamaChat::Commands
977
982
  :next
978
983
  end
979
984
 
980
- ## Actions
985
+ category :Actions
981
986
 
982
987
  command(
983
988
  name: :reconnect,
@@ -1003,7 +1008,7 @@ module OllamaChat::Commands
1003
1008
  quit_app
1004
1009
  end
1005
1010
 
1006
- ## Information
1011
+ category :Information
1007
1012
 
1008
1013
  command(
1009
1014
  name: :info,
@@ -1072,5 +1077,4 @@ module OllamaChat::Commands
1072
1077
  STDOUT.puts "Type /quit to quit."
1073
1078
  :next
1074
1079
  end
1075
-
1076
1080
  end
@@ -425,9 +425,8 @@ module OllamaChat::SessionManagement
425
425
  # stays bounded even after multiple compaction rounds.
426
426
  #
427
427
  # @param name [String, nil] specific template name (skips chooser)
428
- # @param block [Proc] a block to handle the report content
429
428
  # @return [String, nil] the report or nil if empty
430
- def report_session(name: nil, &block)
429
+ def report_session(name: nil)
431
430
  content = messages.compacted_messages.inject('') do |c, message|
432
431
  message.content.present? or next c
433
432
  sender = sender_name_displayed(message)
@@ -445,9 +444,7 @@ module OllamaChat::SessionManagement
445
444
  end
446
445
  template or return
447
446
 
448
- result = generate(prompt: template.to_s % { content: })
449
- block&.(result)
450
- result
447
+ generate(prompt: template.to_s % { content: })
451
448
  end
452
449
 
453
450
  # Generates a report and displays or saves the result.
@@ -458,9 +455,7 @@ module OllamaChat::SessionManagement
458
455
  if save
459
456
  filename = ask_for_filename?(action: 'for report') or return
460
457
  should_overwrite?(filename) or return
461
- result = report_session(name:) do |content|
462
- infobar.puts kramdown_ansi_parse(content)
463
- end
458
+ result = report_session(name:)
464
459
  if result.full?
465
460
  filename.write(result)
466
461
  STDOUT.puts "File successfully written."
@@ -468,9 +463,7 @@ module OllamaChat::SessionManagement
468
463
  STDERR.puts "Nothing to report!"
469
464
  end
470
465
  else
471
- result = report_session(name:) do |content|
472
- infobar.puts kramdown_ansi_parse(content) << ?\n
473
- end
466
+ result = report_session(name:)
474
467
  if result.full?
475
468
  use_pager do |output|
476
469
  output.puts kramdown_ansi_parse(result)
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.116'
3
+ VERSION = '0.0.117'
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.116 ruby lib
2
+ # stub: ollama_chat 0.0.117 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama_chat".freeze
6
- s.version = "0.0.116".freeze
6
+ s.version = "0.0.117".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]
@@ -352,10 +352,8 @@ describe OllamaChat::SessionManagement do
352
352
  expect(chat).to receive(:choose_prompt).and_return(double(to_s: '%{content}'))
353
353
  expect(chat).to receive(:generate).and_return('Generated report')
354
354
 
355
- results = []
356
- result = chat.report_session { |c| results << c }
355
+ result = chat.report_session
357
356
  expect(result).to eq('Generated report')
358
- expect(results).to eq(['Generated report'])
359
357
  end
360
358
 
361
359
  it 'returns nil when no messages have content' do
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.116
4
+ version: 0.0.117
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank