ollama_chat 0.0.114 → 0.0.116

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: e5e93e610536ac396d18e929ef76b3dcecac7d3b9d88a35b8d6ff141e7eba8e4
4
- data.tar.gz: a7792a3b397ebcc0d88552f0fa1417933f44ff00c6e0fad4eb62d567b5c98bfd
3
+ metadata.gz: beebfc1a29093b596fe008ba59b2f377922e2f7beeeb529ebed899fc374c6e02
4
+ data.tar.gz: e704bce9b15101283e802a6010ee08c347cf94d8fcdc2ee785da3880debde736
5
5
  SHA512:
6
- metadata.gz: 95a81969d48e98ff06623f887c33bd0acf94452639fabbf4eca30127ef4d300124f9e12d7bbb97a3d8d86263116d3c772e5d9c403d1e4f4cbdc2df241e1f719f
7
- data.tar.gz: 92201492f3a4a084c845d11f7957b6af6ea8630e7f242158458cb1bad059bababb8699f0dc2f24204ddfde38bcd47e8491812e03d5f38128f179b443f858a9dc
6
+ metadata.gz: 7cab4e5d47d97dd215e058ab9960ad8801252a2ab950d3b30ce1e514fad30b22e87f917e3b1764592070f385fcfec748cc3b59398cadf8e3553f41e6ec48e9bb
7
+ data.tar.gz: 0fb71bb0ab178cb1fed41ea2b257360fd19d3d180a2fc2f497d1372874d4665c3b82676ad8c056ab80a22e21e95deebb8afee8ef5f2809a07671e6cfb53ba5d7
data/CHANGES.md CHANGED
@@ -1,5 +1,111 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-09-03 v0.0.116
4
+
5
+ ### Added
6
+
7
+ * `session.roleplay_story` prompt in `default_config.yml` for narrative
8
+ retelling of roleplay sessions via `/conversation report`.
9
+ * `session.coding_brief` prompt in `default_config.yml`.
10
+ * `summarize` and `report` subcommands to `/conversation`.
11
+ * `summarize_conversation(sentence:, save:)` and `report_conversation(name:,
12
+ save:)` methods in `session_management.rb` to handle filename prompts,
13
+ overwrite checks, and I/O.
14
+ * `report_session(name:, &block)` method using `messages.compacted_messages` to
15
+ keep interpolated content bounded after compaction.
16
+ * `Status:` line with `✅`/`⛔` indicators to `collection_stats` in
17
+ `information.rb`.
18
+ * `✅`/`⛔` prefixes to `list_collections` in `rag_handling.rb` to replace
19
+ `[DISABLED]` text suffixes.
20
+ * `✅`/`⛔` indicators for enabled/disabled states and `❔`/`⭕` for
21
+ confirmation requirements in `list_tools` in `tool_calling.rb`.
22
+ * `ask_for_filename?(action:)` and `should_overwrite?(filename)` helpers in
23
+ `dialog.rb` with YARD documentation.
24
+ * Specs for `summarize_conversation`, `report_session`, and
25
+ `report_conversation` in `session_management_spec.rb`.
26
+ * Routing specs for `/conversation summarize` and `/conversation report` in
27
+ `commands_spec.rb`.
28
+ * YARD documentation for `repair_group_uuids`.
29
+
30
+ ### Changed
31
+
32
+ * Moved `summarize` subcommand from `/session` to `/conversation`.
33
+ * Reworked compaction prompt to a draft-rewrite model, treating previous
34
+ summaries as drafts to be rewritten rather than ambient context.
35
+ * Replaced "6-12 sentences" constraint in compaction prompt with "Be concise;
36
+ skip filler and repetition".
37
+ * Changed `assemble: |-` to `assemble: |` in compaction prompt to preserve
38
+ trailing newlines.
39
+ * Widened factuality scope in compaction prompt to include "groups or previous
40
+ summary above".
41
+ * Wrapped `list_tools` body in `use_pager`, redirecting writes through the
42
+ yielded `output` IO.
43
+ * Passed `output:` keyword argument to `tools_support.show(output:)`.
44
+ * Replaced inline `File.exist?` and `confirm?` blocks in
45
+ `conversation.rb#save_conversation`,
46
+ `message_output.rb#attempt_to_write_file`, `session_management.rb`, and
47
+ `file_editing.rb#determine_valid_output_filename` with the shared
48
+ `should_overwrite?` helper.
49
+ * Updated `chat_spec.rb` `collection_stats` regex to include the new `Status:
50
+ ✅` line.
51
+ * Updated `tool_calling_spec.rb` `list_tools` regex to use `✅`/`⛔` instead of
52
+ `✓`/`☐`.
53
+ * Updated `tool_calling_spec.rb` `#list_tools` example to stub `use_pager` with
54
+ a `StringIO` yield.
55
+ * Updated `conversation_spec.rb` expectations for `Pathname` type and
56
+ `should_overwrite?` STDERR output.
57
+ * Updated comment in `lib/ollama_chat/prompt_management.rb` to reflect new
58
+ naming convention for prompt templates (e.g., `suggest.coding`).
59
+ * Rewrapped `prompts.suggest.roleplaying` few-shot examples to stay within 80
60
+ columns in `default_config.yml`.
61
+ * Fixed stale YARD example in `session_management.rb#report_session`
62
+ (`roleplay_report` to `roleplay_story`).
63
+
64
+ ### Removed
65
+
66
+ * `pretty:` keyword argument from `summarize_session` and
67
+ `summarize_conversation`; markdown formatting is now the only path.
68
+ * `%{message_thinking}` from the `session_summarize` prompt.
69
+
70
+ ## 2026-09-01 v0.0.115
71
+
72
+ * Added `OllamaChat::Tools::ExecuteShell` in
73
+ `lib/ollama_chat/tools/execute_shell.rb`, which executes shell commands via
74
+ `sh -c` after a mandatory human review flow involving an `edit_text` editor
75
+ review and a `y/n/i` confirm prompt.
76
+ * Implemented a `y/n/i` gate in the `execute_shell` tool where `y` executes,
77
+ `n` cancels, and `i` captures user instructions for the LLM to revise the
78
+ command.
79
+ * Configured `require_confirmation: false` in `default_config.yml` to skip
80
+ the preflight confirm in `follow_chat`, relying on the in-tool `confirm?`
81
+ as the primary safety mechanism.
82
+ * Enabled output display via `use_pager` with bold `stdout:`/`stderr:` labels
83
+ and exit codes, with `monochrome: true` (default) stripping ANSI codes
84
+ before returning results to the LLM.
85
+ * Standardized error handling for `execute_shell` failure paths (blank
86
+ command, editor abandoned/cleared, user declined, instruct) to raise
87
+ `OllamaChat::ToolFunctionArgumentError`, which is rescued to log and return
88
+ structured JSON including the `command`.
89
+ * Added a `summary_template` class method to `execute_shell` for one-liner
90
+ output in `lookup_group` compaction.
91
+ * Registered `execute_shell` in `lib/ollama_chat/tools.rb` and configured it
92
+ in `default_config.yml` with `default: false` and `result_display_timeout:
93
+ 10`.
94
+ * Added 18 spec examples in `spec/ollama_chat/tools/execute_shell_spec.rb`
95
+ covering identity, execution, editor cancel, instruct, monochrome, pager
96
+ display, and `summary_template`.
97
+ * Introduced `OllamaChat::Utils::StripANSI` module in
98
+ `lib/ollama_chat/utils/strip_ansi.rb` with a regex-based `strip_ansi`
99
+ method handling both SGR and OSC escape sequences.
100
+ * Replaced `Term::ANSIColor.uncolor` calls with `strip_ansi` in
101
+ `lib/ollama_chat/tools/execute_shell.rb`, `lib/ollama_chat/commands.rb`
102
+ (`/input` path and default subcommands), and `bin/ollama_chat_send`.
103
+ * Registered `lib/ollama_chat/utils/strip_ansi.rb` in `ollama_chat.gemspec`
104
+ file lists.
105
+ * Fixed `read_file` and `write_file` spec assertions in `read_file_spec.rb`
106
+ and `write_file_spec.rb` to match the token-first output format (`tokens
107
+ (bytes)`) shipped in **v0.0.114**.
108
+
3
109
  ## 2026-09-01 v0.0.114
4
110
 
5
111
  ### Added
data/bin/ollama_chat_send CHANGED
@@ -43,7 +43,7 @@ begin
43
43
  opts[?r] ? :socket_input_with_response : :socket_input
44
44
  end
45
45
  content = STDIN.read
46
- content = Term::ANSIColor.uncolor(content) if opts[?m]
46
+ content = OllamaChat::Utils::StripANSI.strip_ansi(content) if opts[?m]
47
47
  if opts[?e]
48
48
  basename = %w[ text ]
49
49
  basename << opts[?F]&.sub(/\A(?=[^.])/, ?.) || '.md'
@@ -291,15 +291,14 @@ module OllamaChat::Commands
291
291
 
292
292
  command(
293
293
  name: :session,
294
- regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|summarize|delete|model options change|model options))?((?:\s+-(?:[sf]|p\s*\w+))*)(?:\s+([^-].*))?$),
295
- complete: [ 'session', %w[ change previous list new duplicate rename summarize delete model\ options\ change model\ options ] ],
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
296
  optional: true,
297
- options: "[-s|-f|-p profile]\n[name]",
297
+ options: "[-p profile]\n[name]",
298
298
  help: <<~EOT
299
299
  💬 Manage sessions:
300
300
  - list/new/delete/rename/duplicate
301
301
  - change [name]/previous
302
- - summarize (-s sentence, -f save to file)
303
302
  - model options/change
304
303
  EOT
305
304
  ) do |subcommand, opts, name|
@@ -316,44 +315,6 @@ module OllamaChat::Commands
316
315
  delete_session
317
316
  when 'rename'
318
317
  rename_session
319
- when 'summarize'
320
- opts = go_command('fs', opts)
321
- if opts[?f] and
322
- filename = switch_history(:filename) {
323
- ask?(prompt: "❓ Enter filename: ")
324
- }.full? { Pathname.new(_1) }
325
- then
326
- if filename.exist? && !confirm?(
327
- prompt: "🔔 File #{filename.to_s.inspect} already exists, overwrite? (y/n) ",
328
- yes: /\Ay/i
329
- )
330
- then
331
- STDERR.puts "File not written!"
332
- next :next
333
- end
334
- summary = summarize_session(pretty: true, sentence: opts[?s]) do |content|
335
- infobar.puts kramdown_ansi_parse(content)
336
- end
337
- if summary.full?
338
- filename.write(summary)
339
- STDOUT.puts "File successfully written."
340
- next :next
341
- else
342
- STDERR.puts "Nothing to summarize!"
343
- next :next
344
- end
345
- end
346
- summary = summarize_session(pretty: true, sentence: opts[?s]) do |content|
347
- infobar.puts kramdown_ansi_parse(content) << ?\n
348
- end
349
- if summary.full?
350
- use_pager do |output|
351
- output.puts kramdown_ansi_parse(summary)
352
- end
353
- else
354
- STDERR.puts "Nothing to summarize!"
355
- next :next
356
- end
357
318
  when 'change'
358
319
  change_session(name)
359
320
  when 'model options'
@@ -598,15 +559,16 @@ module OllamaChat::Commands
598
559
 
599
560
  command(
600
561
  name: :conversation,
601
- regexp: %r(^/conversation\s+(clean|compact|save|load)(\s+-c)?(?:\s+([^-].*\.jsonl?))?$),
602
- complete: [ 'conversation', %w[ save load clean compact ] ],
603
- options: '[-c] [FILENAME]',
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]',
604
565
  help: <<~EOT
605
- 💾 Save/Load conversation state
606
- (-c to clean before saving)
607
- FILENAME ends with .json or .jsonl
608
- Or clean inplace (removes tool content, images, and thinking)
609
- Or compact (summarize old messages, keep recent)
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
610
572
  EOT
611
573
  ) do |subcommand,opts,path|
612
574
  if %w[ save load ].include?(subcommand) && path.blank?
@@ -642,6 +604,12 @@ module OllamaChat::Commands
642
604
  else
643
605
  STDOUT.puts 'Cancelled.'
644
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])
645
613
  end
646
614
  :next
647
615
  end
@@ -926,14 +894,14 @@ module OllamaChat::Commands
926
894
  read = -> pathname {
927
895
  STDOUT.puts "Reading #{pathname.to_s.inspect}."
928
896
  content = pathname.read
929
- opts[?m] ? Term::ANSIColor.uncolor(content) : content
897
+ opts[?m] ? OllamaChat::Utils::StripANSI.strip_ansi(content) : content
930
898
  }
931
899
  next provide_file_set_content(patterns, all:, &read) || :next
932
900
  elsif arg
933
901
  filename = Pathname.new(arg).expand_path
934
902
  filename.file? or next :next
935
903
  content = filename.read
936
- content = Term::ANSIColor.uncolor(content) if opts[?m]
904
+ content = OllamaChat::Utils::StripANSI.strip_ansi(content) if opts[?m]
937
905
  content = edit_text(content) if opts[?e]
938
906
  content
939
907
  else
@@ -947,12 +915,12 @@ module OllamaChat::Commands
947
915
  patterns = extract_patterns(arg)
948
916
  next provide_file_set_content(patterns, all:, skip_blank: true) do |src|
949
917
  content = import(src)
950
- opts[?m] ? Term::ANSIColor.uncolor(content) : content
918
+ opts[?m] ? OllamaChat::Utils::StripANSI.strip_ansi(content) : content
951
919
  end || :next
952
920
  elsif arg
953
921
  source = arg
954
922
  content = import(source) or next :next
955
- content = Term::ANSIColor.uncolor(content) if opts[?m]
923
+ content = OllamaChat::Utils::StripANSI.strip_ansi(content) if opts[?m]
956
924
  content = edit_text(content) if opts[?e]
957
925
  content
958
926
  else
@@ -26,12 +26,8 @@ module OllamaChat::Conversation
26
26
  # @example Save conversation with explicit filename
27
27
  # chat.save_conversation('conversations/2023-10-15_my_session.json')
28
28
  def save_conversation(filename, clean: false)
29
- if File.exist?(filename)
30
- confirm?(
31
- prompt: "🔔 File #{filename.to_s.inspect} already exists, overwrite? (y/n) ",
32
- yes: /\Ay/i
33
- ) or return
34
- end
29
+ filename = Pathname.new(filename)
30
+ should_overwrite?(filename) or return
35
31
  if messages.save_conversation(filename, messages: clean ? messages.clean_messages : messages.messages)
36
32
  STDOUT.puts "Saved conversation to #{filename.to_s.inspect}."
37
33
  else
@@ -149,4 +149,38 @@ module OllamaChat::Dialog
149
149
  def go_command(s, opt, defaults: {})
150
150
  Tins::GO.go(s, opt.to_s.strip.split(/\s+/), defaults:)
151
151
  end
152
+
153
+ # Prompts the user for a filename with history support.
154
+ #
155
+ # @param action [String, nil] an optional action descriptor appended to the
156
+ # prompt, e.g. "for summarization" ("❓ Enter filename for summarization…")
157
+ #
158
+ # @return [Pathname, nil] the user-supplied filename as a Pathname, or nil
159
+ # if the user cancels (C-c) or provides empty input
160
+ def ask_for_filename?(action: nil)
161
+ action and action = " #{action}"
162
+ switch_history(:filename) {
163
+ ask?(prompt: "❓ Enter filename#{action}, C-c ⇒ cancel: ")
164
+ }.full? { Pathname.new(_1) }
165
+ end
166
+
167
+ # Checks whether a file can be written, prompting for overwrite
168
+ # confirmation if the file already exists.
169
+ #
170
+ # @param filename [Pathname] the target file to check
171
+ #
172
+ # @return [Boolean] `true` if the file does not exist or the user confirms
173
+ # overwriting; `false` if the file exists and the user declines
174
+ def should_overwrite?(filename)
175
+ if filename.exist? && !confirm?(
176
+ prompt: "🔔 File #{filename.to_s.inspect} already exists, overwrite? (y/n) ",
177
+ yes: /\Ay/i
178
+ )
179
+ then
180
+ STDERR.puts "File not written!"
181
+ false
182
+ else
183
+ true
184
+ end
185
+ end
152
186
  end
@@ -113,15 +113,12 @@ module OllamaChat::FileEditing
113
113
  def determine_valid_output_filename(action)
114
114
  switch_history(:filename) do
115
115
  loop do
116
- filename_str = ask?(
117
- prompt: "❓ Enter filename #{action}, C-c ⇒ cancel: "
118
- )
119
- if filename_str.nil?
116
+ filename = ask_for_filename?(action:)
117
+ unless filename
120
118
  STDOUT.puts "Cancelled."
121
119
  return nil
122
120
  end
123
121
 
124
- filename = Pathname.new(filename_str)
125
122
  if filename.exist?
126
123
  STDERR.puts "File #{filename.to_path.inspect} already exists!"
127
124
  else
@@ -80,6 +80,7 @@ module OllamaChat::Information
80
80
  output.puts <<~EOT
81
81
  Current Collection
82
82
  Name: #{bold{collection}}
83
+ Status: #{col&.enabled ? '✅' : '⛔'}
83
84
  Patterns: #{italic{col&.patterns&.join(' ')}}
84
85
  #Embeddings: #{@documents.size}
85
86
  #Tags: #{@documents.tags.size}
@@ -89,17 +89,9 @@ module OllamaChat::MessageOutput
89
89
  # error occurred
90
90
  def attempt_to_write_file(filename, content)
91
91
  path = Pathname.new(filename.to_s).expand_path
92
- if !path.exist? ||
93
- confirm?(
94
- prompt: "🔔 File #{path.to_s.inspect} already exists, overwrite? (y/n) ",
95
- yes: /\Ay/i
96
- )
97
- then
98
- File.open(path, ?w) do |output|
99
- output.write(content)
100
- end
101
- else
102
- return
92
+ should_overwrite?(path) or return
93
+ File.open(path, ?w) do |output|
94
+ output.write(content)
103
95
  end
104
96
  true
105
97
  end
@@ -151,21 +151,22 @@ prompts:
151
151
  - **Format**: [Markdown, plain text, code blocks, etc.]
152
152
  - **Vocabulary**: [Technical terms, slang, formal language]
153
153
  - **Structure**: [How you organize your responses]
154
+ context_template_suggest: |
155
+ Conversation History:
156
+ %{history}
157
+
158
+ Create and output text following this instruction:
159
+ %{instruction}
154
160
  session_summarize: |
155
- Context is
161
+ Narrative so far:
156
162
 
157
163
  %{context}
158
164
 
159
- Summarize the %{sender_name} message below in one %{unit}.
160
-
161
- NEVER add any information to this message summary that already was included
162
- in the context above.
163
-
164
- Message
165
-
166
- Thinking content was
167
-
168
- %{message_thinking}
165
+ Extend the narrative above with the key contribution of the
166
+ %{sender_name} message below in one %{unit}. Skip tool-call
167
+ plumbing; focus on decisions, findings, and state changes. Do
168
+ not repeat information already present in the narrative.
169
+ Output only the summary text, without any sender name or prefix.
169
170
 
170
171
  Response content was
171
172
 
@@ -175,12 +176,26 @@ prompts:
175
176
 
176
177
  Create a title with a length of **less than %{length}** characters for
177
178
  the conversation above. Output only the title and nothing else.
178
- context_template_suggest: |
179
- Conversation History:
180
- %{history}
179
+ session:
180
+ coding_brief: |
181
+ %{content}
181
182
 
182
- Create and output text following this instruction:
183
- %{instruction}
183
+ Write a brief of the session above. Your brief MUST:
184
+ - Describe the goal and how it evolved.
185
+ - Name key decisions, files, and architectural choices.
186
+ - State the current state: what works, what is pending.
187
+ - Be factual. Be concise.
188
+ roleplay_story: |
189
+ %{content}
190
+
191
+ Write a narrative retelling of the roleplay session
192
+ above. Your story MUST:
193
+ - Capture the emotional arc and key plot beats.
194
+ - Stay in the established setting and character voices.
195
+ - Use vivid, evocative prose; show, don't tell.
196
+ - Highlight turning points, revelations, and character
197
+ growth.
198
+ - Read it like a short story chapter, not a log.
184
199
  suggest:
185
200
  coding: |
186
201
  ## Context
@@ -318,25 +333,33 @@ prompts:
318
333
 
319
334
  ## Few-Shot Examples
320
335
 
321
- Input: [Scene where a party is arguing in a rainy forest while being hunted]
322
- Output:
323
- Demand that everyone stop shouting and listen for the sound of footsteps in the brush.
336
+ Input: [Scene where a party is arguing in a rainy forest while being
337
+ hunted] Output: Demand that everyone stop shouting and listen for the
338
+ sound of footsteps in the brush.
324
339
 
325
- Quietly admit to the party leader that you are terrified, leaning into their shoulder for support.
340
+ Quietly admit to the party leader that you are terrified, leaning into
341
+ their shoulder for support.
326
342
 
327
- Examine the muddy tracks near the campfire to see if the hunters are human or something else. Roll 1d20.
343
+ Examine the muddy tracks near the campfire to see if the hunters are
344
+ human or something else. Roll 1d20.
328
345
 
329
- Secretly slip the map out of the leader's pocket while they are distracted by the argument. Roll 1d20.
346
+ Secretly slip the map out of the leader's pocket while they are
347
+ distracted by the argument. Roll 1d20.
330
348
 
331
- Raise your voice and challenge every single person present to state their true loyalty right now.
349
+ Raise your voice and challenge every single person present to state their
350
+ true loyalty right now.
332
351
 
333
- Attempt to leap across the ravine to flank the hunters, risking a fall into the rapids. Roll 1d20.
352
+ Attempt to leap across the ravine to flank the hunters, risking a fall
353
+ into the rapids. Roll 1d20.
334
354
 
335
- Obsessively polish your sword with a rag, ignoring the argument entirely until it is perfectly mirrored.
355
+ Obsessively polish your sword with a rag, ignoring the argument entirely
356
+ until it is perfectly mirrored.
336
357
 
337
- Suddenly reveal that you were actually sent here by the enemy as a double agent.
358
+ Suddenly reveal that you were actually sent here by the enemy as a double
359
+ agent.
338
360
 
339
- A sudden lightning strike hits a nearby tree, knocking everyone off balance and creating a deafening blast.
361
+ A sudden lightning strike hits a nearby tree, knocking everyone off
362
+ balance and creating a deafening blast.
340
363
 
341
364
  ## Output Format
342
365
 
@@ -356,7 +379,10 @@ prompts:
356
379
  conversation:
357
380
  %{groups}
358
381
 
359
- Summarize the conversation above. Your narrative MUST:
382
+ The previous summary (if present) is a draft. Rewrite it
383
+ to incorporate the new conversation above. The result must
384
+ read as one continuous account of the entire session, not a
385
+ concatenation of two separate summaries. Your narrative MUST:
360
386
  - Name every file created or significantly modified (with
361
387
  path), and the key methods or classes they define.
362
388
  - State the architectural or design decisions made (e.g.
@@ -366,8 +392,8 @@ prompts:
366
392
  - Do NOT merely report test counts or coverage percentages;
367
393
  those are outcomes, not accomplishments.
368
394
  - Be factual; do not invent details not present in the groups
369
- above. Keep it to 6–12 sentences.
370
- assemble: |-
395
+ or previous summary above. Be concise; skip filler and repetition.
396
+ assemble: |
371
397
  %{narrative}
372
398
 
373
399
  tool_calls:
@@ -494,6 +520,10 @@ tools:
494
520
  result_display_timeout: 3
495
521
  cmd: |
496
522
  grep #{'-i' if ignore_case} -m #{max_results} -r #{before.full? { "-B %u " % it }}#{after.full? { "-A %u " % it }}#{context.full? { "-C %u " % it }}#{pattern} #{path}
523
+ execute_shell:
524
+ default: false
525
+ require_confirmation: false # Preflight confirm is skipped, but in-tool it's mandatory.
526
+ result_display_timeout: 0
497
527
  browse:
498
528
  result_display_timeout: 3
499
529
  default: true
@@ -333,7 +333,7 @@ module OllamaChat::PromptManagement
333
333
  # Let the user write a suggestion instruction on the fly
334
334
  instruction = edit_text('').full? or return
335
335
  else
336
- # Let the user pick a prompt template (e.g., suggest_coding, suggest_roleplaying)
336
+ # Let the user pick a prompt template (e.g., suggest.coding, suggest.roleplaying)
337
337
  instruction = choose_prompt(
338
338
  prompt: 'Which suggestion strategy shall we employ? %s',
339
339
  context: 'suggest'
@@ -163,10 +163,11 @@ module OllamaChat::RAGHandling
163
163
  collections = all_collections.select(:name, :description, :enabled)
164
164
  use_pager do |output|
165
165
  collections.each { |c|
166
- collection_name = current_collection == c.name ? bold { c.name } : c.name
166
+ enabled = c.enabled ? '✅' : '⛔'
167
+ collection_name = current_collection == c.name ? bold { c.name } : c.name
167
168
  collection_description = c.description
168
- suffix = c.enabled ? '' : ' [DISABLED]'
169
- output.puts '%s: %s%s' % [ collection_name, collection_description, suffix ]
169
+
170
+ output.puts '%s %s: %s' % [ enabled, collection_name, collection_description ]
170
171
  }
171
172
  end
172
173
  end