ollama_chat 0.0.125 → 0.0.127

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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +152 -0
  3. data/Rakefile +1 -1
  4. data/lib/ollama_chat/chat.rb +2 -2
  5. data/lib/ollama_chat/collection_search.rb +14 -2
  6. data/lib/ollama_chat/commands.rb +33 -23
  7. data/lib/ollama_chat/compaction.rb +29 -2
  8. data/lib/ollama_chat/database/models/session.rb +21 -0
  9. data/lib/ollama_chat/follow_chat.rb +1 -1
  10. data/lib/ollama_chat/information.rb +6 -20
  11. data/lib/ollama_chat/ollama_chat_config/default_config.yml +5 -3
  12. data/lib/ollama_chat/pager.rb +5 -2
  13. data/lib/ollama_chat/rag_handling.rb +217 -28
  14. data/lib/ollama_chat/session_management.rb +24 -4
  15. data/lib/ollama_chat/switches.rb +79 -9
  16. data/lib/ollama_chat/tool_calling.rb +3 -16
  17. data/lib/ollama_chat/tools/browse.rb +0 -1
  18. data/lib/ollama_chat/tools/compute_bmi.rb +1 -2
  19. data/lib/ollama_chat/tools/concern.rb +26 -0
  20. data/lib/ollama_chat/tools/copy_to_clipboard.rb +1 -3
  21. data/lib/ollama_chat/tools/delete_file.rb +4 -3
  22. data/lib/ollama_chat/tools/directory_structure.rb +0 -1
  23. data/lib/ollama_chat/tools/eval_ruby.rb +0 -1
  24. data/lib/ollama_chat/tools/execute_grep.rb +0 -2
  25. data/lib/ollama_chat/tools/execute_jira_twg.rb +0 -2
  26. data/lib/ollama_chat/tools/execute_ri.rb +0 -1
  27. data/lib/ollama_chat/tools/execute_shell.rb +5 -7
  28. data/lib/ollama_chat/tools/file_context.rb +0 -2
  29. data/lib/ollama_chat/tools/forget.rb +20 -8
  30. data/lib/ollama_chat/tools/gem_path_lookup.rb +0 -1
  31. data/lib/ollama_chat/tools/generate_image.rb +6 -8
  32. data/lib/ollama_chat/tools/generate_password.rb +0 -2
  33. data/lib/ollama_chat/tools/get_current_weather.rb +2 -4
  34. data/lib/ollama_chat/tools/get_cve.rb +0 -2
  35. data/lib/ollama_chat/tools/get_endoflife.rb +0 -2
  36. data/lib/ollama_chat/tools/get_ghr.rb +2 -4
  37. data/lib/ollama_chat/tools/get_jira_issue.rb +0 -2
  38. data/lib/ollama_chat/tools/get_location.rb +0 -2
  39. data/lib/ollama_chat/tools/get_rfc.rb +0 -2
  40. data/lib/ollama_chat/tools/get_time.rb +2 -3
  41. data/lib/ollama_chat/tools/get_url.rb +0 -2
  42. data/lib/ollama_chat/tools/lookup_group.rb +0 -2
  43. data/lib/ollama_chat/tools/memorize.rb +38 -13
  44. data/lib/ollama_chat/tools/move_file.rb +8 -4
  45. data/lib/ollama_chat/tools/open_file_in_editor.rb +0 -2
  46. data/lib/ollama_chat/tools/paste_from_clipboard.rb +1 -4
  47. data/lib/ollama_chat/tools/paste_into_editor.rb +3 -5
  48. data/lib/ollama_chat/tools/patch_file.rb +10 -7
  49. data/lib/ollama_chat/tools/read_file.rb +3 -5
  50. data/lib/ollama_chat/tools/resolve_tag.rb +1 -2
  51. data/lib/ollama_chat/tools/roll_dice.rb +0 -2
  52. data/lib/ollama_chat/tools/run_tests.rb +2 -2
  53. data/lib/ollama_chat/tools/search_knowledge.rb +19 -17
  54. data/lib/ollama_chat/tools/search_web.rb +0 -3
  55. data/lib/ollama_chat/tools/write_file.rb +4 -3
  56. data/lib/ollama_chat/tools.rb +50 -4
  57. data/lib/ollama_chat/version.rb +1 -1
  58. data/ollama_chat.gemspec +4 -4
  59. data/spec/ollama_chat/commands_spec.rb +41 -7
  60. data/spec/ollama_chat/rag_handling_spec.rb +191 -18
  61. data/spec/ollama_chat/session_management_spec.rb +6 -2
  62. data/spec/ollama_chat/switches_spec.rb +28 -0
  63. data/spec/ollama_chat/tool_calling_spec.rb +0 -11
  64. data/spec/ollama_chat/tools/browse_spec.rb +11 -7
  65. data/spec/ollama_chat/tools/compute_bmi_spec.rb +8 -8
  66. data/spec/ollama_chat/tools/concern_spec.rb +7 -1
  67. data/spec/ollama_chat/tools/copy_to_clipboard_spec.rb +8 -8
  68. data/spec/ollama_chat/tools/delete_file_spec.rb +7 -7
  69. data/spec/ollama_chat/tools/directory_structure_spec.rb +7 -7
  70. data/spec/ollama_chat/tools/execute_grep_spec.rb +10 -10
  71. data/spec/ollama_chat/tools/execute_jira_twg_spec.rb +8 -8
  72. data/spec/ollama_chat/tools/execute_ri_spec.rb +6 -6
  73. data/spec/ollama_chat/tools/execute_shell_spec.rb +2 -1
  74. data/spec/ollama_chat/tools/file_context_spec.rb +4 -4
  75. data/spec/ollama_chat/tools/forget_spec.rb +25 -15
  76. data/spec/ollama_chat/tools/gem_path_lookup_spec.rb +5 -5
  77. data/spec/ollama_chat/tools/generate_image_spec.rb +10 -10
  78. data/spec/ollama_chat/tools/generate_password_spec.rb +8 -8
  79. data/spec/ollama_chat/tools/get_current_weather_spec.rb +6 -6
  80. data/spec/ollama_chat/tools/get_cve_spec.rb +5 -5
  81. data/spec/ollama_chat/tools/get_endoflife_spec.rb +5 -5
  82. data/spec/ollama_chat/tools/get_ghr_spec.rb +11 -11
  83. data/spec/ollama_chat/tools/get_jira_issue_spec.rb +6 -6
  84. data/spec/ollama_chat/tools/get_location_spec.rb +6 -6
  85. data/spec/ollama_chat/tools/get_rfc_spec.rb +5 -5
  86. data/spec/ollama_chat/tools/get_time_spec.rb +4 -4
  87. data/spec/ollama_chat/tools/get_url_spec.rb +17 -17
  88. data/spec/ollama_chat/tools/lookup_group_spec.rb +5 -5
  89. data/spec/ollama_chat/tools/memorize_spec.rb +67 -11
  90. data/spec/ollama_chat/tools/move_file_spec.rb +8 -8
  91. data/spec/ollama_chat/tools/open_file_in_editor_spec.rb +6 -6
  92. data/spec/ollama_chat/tools/paste_from_clipboard_spec.rb +7 -7
  93. data/spec/ollama_chat/tools/paste_into_editor_spec.rb +6 -6
  94. data/spec/ollama_chat/tools/patch_file_spec.rb +9 -9
  95. data/spec/ollama_chat/tools/read_file_spec.rb +12 -12
  96. data/spec/ollama_chat/tools/resolve_tag_spec.rb +6 -6
  97. data/spec/ollama_chat/tools/roll_dice_spec.rb +6 -6
  98. data/spec/ollama_chat/tools/run_tests_spec.rb +13 -13
  99. data/spec/ollama_chat/tools/search_knowledge_spec.rb +22 -25
  100. data/spec/ollama_chat/tools/search_web_spec.rb +6 -6
  101. data/spec/ollama_chat/tools/write_file_spec.rb +15 -15
  102. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3de94c682281a4667e89feee589883bd33acf082165f37ce443072117a773167
4
- data.tar.gz: 94cccbb92af48198a70879cf1028a0aebfe0cda49e25ccd82352cb35d9054bf7
3
+ metadata.gz: a72761f0d0b34c0ba21859589410e914dda692d669a39629e4e6bb8f6e2857ea
4
+ data.tar.gz: 374fa95c62c5510e94c6a7624200a6193a15e9ed842a4b49b5364d43eeecac52
5
5
  SHA512:
6
- metadata.gz: d3bad30e34ad309fe6c2f2263802af2778eded9459affc6c6713c6383f58706fe54411e7a4b6f087c487718d0a6ea8e07e90dfed22ca1a64b563d207ce61287e
7
- data.tar.gz: 8f9befaa4a6a519b8f7b4424f0d16380663b863e039f08142fc667b01ecb83aa989b9e635ea5373b22191c7ba8f568e97dd210d732d1d6d5099dd3e5cffb74ee
6
+ metadata.gz: ea024b4607101da7037f0234970cb6e655c6d2b1af46fc1eac1b8dc901aebd5ef95a091d079653bfb58e86d381c4bb56173172f9fb0861e9d8a3424667bfdd32
7
+ data.tar.gz: dfbbe6cddbb4aac1f047cb39719ed58e8920e22a42775cb9f18a4d3731d0c53cc7c632733241f58f6cd6c132e5979b0a3117bf38e7e0095417310e839fb7421b
data/CHANGES.md CHANGED
@@ -1,5 +1,157 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-06 v0.0.127
4
+
5
+ ## Changes
6
+
7
+ * **Switches and Configuration**
8
+ * Added `memory_trigger` switch, registered in `/toggle` (regexp,
9
+ completion list, help string, and fallback feedback).
10
+ * Refactored `Switch` to accept callable values alongside plain values;
11
+ plain values are now wrapped via a new private `adhoc_closure` method
12
+ using a `UNSET` sentinel for read/write disambiguation.
13
+ * Hardened `Switch#initialize` with an arity guard: callable values
14
+ responding to `:arity` must return `-1` (optional single parameter
15
+ defaulting to `UNSET`), otherwise a `TypeError` is raised.
16
+ * Updated `set` methods in `OllamaChat::Switches` to explicitly return
17
+ `nil` for consistent behavior.
18
+ * Added `@raise [TypeError]` tag to `Switch#initialize` and expanded
19
+ `@param value` YARD documentation for `CombinedSwitch`.
20
+ * Added arity guard (`ask_and_send(:arity) <= 0`) to
21
+ `CombinedSwitch#initialize`.
22
+
23
+ * **Session and Model Updates**
24
+ * Added `trigger_enabled?` and `set_trigger_enabled` to the `Session`
25
+ model to encapsulate trigger hash shape.
26
+ * Added YARD documentation for `adhoc_closure` and the `:memory_trigger`
27
+ reader.
28
+
29
+ * **Conversation and Compaction**
30
+ * Added `/conversation compact summary` command.
31
+ * Introduced `show_compaction_summary` in `Compaction` to retrieve the
32
+ most recent summary message via `messages.find_summary` and render its
33
+ content (narrative + `tool_calls` lookup index) through the pager,
34
+ prefixed with a size header and entry count.
35
+ * Registered the new `compact summary` subcommand in the `/conversation`
36
+ regexp alternation, completion list, help text, and dispatch block.
37
+ * Excluded system-injected messages (`runtime_information`,
38
+ `trigger_inject`) from the compaction summary's `tool_calls` block to
39
+ keep the index focused on user-initiated tool calls.
40
+
41
+ * **RAG and Search**
42
+ * Moved `set_documents_collection` above the `private` keyword in
43
+ `rag_handling.rb` to make it callable from outside `RAGHandling`.
44
+ * Updated `choose_collection` to call `set_documents_collection` instead
45
+ of assigning `@documents.collection` directly.
46
+ * Replaced direct `chat.documents.collection` reads/writes in `chat.rb`
47
+ and `search_knowledge.rb` with public accessors `chat.collection` and
48
+ `chat.set_documents_collection`.
49
+ * Consolidated two `chat.log` calls in `search_knowledge.rb` into one,
50
+ adding `rerank:` and `pre_rerank:` to the structured data hash with
51
+ `.compact`.
52
+ * Removed `String#%` interpolation in the old rerank log line and
53
+ eliminated the `collection_name` local variable.
54
+ * Updated `trigger_inject` in `collection_search.rb` to include the
55
+ surviving `records` array (text, similarity, tags) in the log `data:`
56
+ hash instead of only logging the count.
57
+
58
+ * **Shell Execution**
59
+ * Forced pager for all `execute_shell` output by passing `force: true` to
60
+ `use_pager`, ensuring consistent UX with other pager-based tools.
61
+ * Updated test-mode spec examples to include a `stub_success` call with
62
+ sample stdout to exercise the always-active pager path with real
63
+ content.
64
+
65
+ ## 2026-10-05 v0.0.126
66
+
67
+ * **Tool Registry Refactor**: Refactored the tool registry to store tool
68
+ classes instead of pre-built instances.
69
+ * `registered_class(name)` now returns the class for `summary_template`
70
+ access.
71
+ * `registered_tool(name, chat:)` instantiates a fresh instance bound to
72
+ the current session.
73
+ * `Concern#initialize(chat)` injects the chat reference; all tools now
74
+ access config via `self.chat` instead of `opts[:chat]`.
75
+ * Helper methods in `execute_shell`, `generate_image`,
76
+ `get_current_weather`, `get_ghr`, and `patch_file` now use `self.chat`
77
+ directly.
78
+ * Migrated all tool specs to use `described_class.new(chat)` and
79
+ `.execute(tool_call)`.
80
+
81
+ * **Path Allowlists**: Moved path allowlists into tool parameter
82
+ descriptions.
83
+ * Added `allowed_paths` to `tools/concern.rb` to return expanded,
84
+ existing paths for the calling tool's `allowed` config.
85
+ * Removed `tool_paths_allowed` from `tool_calling.rb` and its spec.
86
+ * Injected `allowed_paths.map(&:inspect).join(', ')` into the `path`,
87
+ `source`, and `destination` parameter descriptions of `delete_file`,
88
+ `move_file`, `patch_file`, `read_file`, and `write_file`.
89
+
90
+ * **RAG Handling & Runtime Info**: Relocated `collection_descriptions` from
91
+ `information.rb` to `rag_handling.rb`.
92
+ * Removed `collections` key from `static_runtime_information_values` and
93
+ `default_config.yml`.
94
+ * Migrated `static_runtime_information` and `dynamic_runtime_information`
95
+ from `String#%` to `named_placeholders_interpolate`.
96
+
97
+ * **Collection Commands**: Reworked collection clearing into three distinct
98
+ commands.
99
+ * Split monolithic `clear_collection` into `clear_whole_collection`,
100
+ `clear_collection_tags`, and `clear_collection_sources`.
101
+ * `clear_collection_tags` implements a two-level tag-to-source browser.
102
+ * `clear_collection_sources` implements a source-to-tags browser.
103
+ * Added `use_pager(force:)` keyword in `pager.rb` to bypass size checks
104
+ using `Float::INFINITY`.
105
+ * Added `Kramdown::ANSI::Width.wrap(..., percentage: 90)` to pager views
106
+ for terminal-width wrapping.
107
+ * Bumped `documentrix` minimum to **0.8.0** in `Rakefile` and
108
+ `ollama_chat.gemspec` for the new `records(tags:, sources:)` API.
109
+ * Extended `/collection` regexp and completion for `clear sources`.
110
+
111
+ * **Memory Tools**: Enhanced memory management tools.
112
+ * `memorize` now accepts an optional `update` kwarg (ISO timestamp tag)
113
+ to replace an existing memory entry, returning `replaced_timestamp` and
114
+ `replaced_text`.
115
+ * `forget` now returns `forgotten_text` in the JSON response and includes
116
+ an 80-character snippet in the human-readable `message`.
117
+ * Renamed `set_current_collection` to `set_documents_collection` in
118
+ `rag_handling.rb`, `session_management.rb`, and specs.
119
+ * Made `current_collection` public in `RAGHandling`.
120
+ * Enriched `search_knowledge` tool `collection` param with allowed
121
+ collections from `collection_descriptions` and current default.
122
+
123
+ * **Session Management**:
124
+ * Derive memory trigger from persona at session apply by adding a
125
+ `trigger` block to `default_config.yml`.
126
+ * Extracted `create_memory_collection` into `RAGHandling` as the single
127
+ canonical entry point.
128
+ * In `SessionManagement#session_apply`, auto-derive the session trigger
129
+ from `initial_persona_name` and `config.trigger` when no explicit
130
+ trigger is set.
131
+ * Advertise `C-u` random shortcut in the session prompt to clear prefill
132
+ and obtain a random session name.
133
+
134
+ * **Commands & UX**:
135
+ * Added `-r` flag to `/compose` to quote the last assistant reply as an
136
+ `edit_text` pre-fill.
137
+ * Removed the `confirm?` prompt before `compact_with_retry` in
138
+ `/conversation compact`; compaction now runs immediately.
139
+ * Split `/collection clear` into `clear tags` subcommand and bare `clear`
140
+ routing to `clear_whole_collection`.
141
+
142
+ * **Tool Descriptions & Logging**:
143
+ * Made `paste_into_editor` description imperative.
144
+ * Documented bottom-up edit order in `patch_file` to prevent models from
145
+ incorrectly compensating for line shifts.
146
+ * Log full `edits` array in `patch_file` tool info log payload instead of
147
+ just `edits_count`.
148
+ * Strip ANSI codes from `run_tests` captured output using
149
+ `OllamaChat::Utils::StripANSI`.
150
+
151
+ * **Compatibility & Fixes**:
152
+ * Include `persona_name` in the `default` system prompt template in
153
+ `default_config.yml`.
154
+
3
155
  ## 2026-10-03 v0.0.125
4
156
 
5
157
  ### Added
data/Rakefile CHANGED
@@ -40,7 +40,7 @@ GemHadar do
40
40
 
41
41
  dependency 'excon', '~> 1.0'
42
42
  dependency 'ollama-ruby', '~> 1.23'
43
- dependency 'documentrix', '>= 0.7.0'
43
+ dependency 'documentrix', '>= 0.8.0'
44
44
  dependency 'unix_socks', '>= 0.4'
45
45
  dependency 'rss', '~> 0.3'
46
46
  dependency 'term-ansicolor', '~> 1.11'
@@ -712,7 +712,7 @@ class OllamaChat::Chat
712
712
  # @note Progress is reported to STDOUT during processing
713
713
  def add_documents_from_argv(document_list)
714
714
  if document_list.any?(&:empty?)
715
- feedback("Clearing collection #{bold{documents.collection}}.", type: :info)
715
+ feedback("Clearing collection #{bold{collection}}.", type: :info)
716
716
  documents.clear
717
717
  document_list.reject!(&:empty?)
718
718
  end
@@ -724,7 +724,7 @@ class OllamaChat::Chat
724
724
  File.expand_path(doc)
725
725
  end
726
726
  end
727
- feedback("Collection #{bold{documents.collection}}: Adding #{document_list.size} documents…", type: :info)
727
+ feedback("Collection #{bold{collection}}: Adding #{document_list.size} documents…", type: :info)
728
728
  count = 1
729
729
  document_list.each_slice(25) do |docs|
730
730
  docs.each do |doc|
@@ -130,8 +130,20 @@ module OllamaChat::CollectionSearch
130
130
  records.empty? and return
131
131
  pre_rerank = records.size
132
132
  records = rerank_records(content, records, prompt_name:)
133
- log(:info, 'Trigger: %d/%d passed rerank for %s' % [ records.size, pre_rerank, collection ],
134
- data: { collection:, prompt_name: })
133
+ log(
134
+ :info,
135
+ 'Trigger: %d/%d passed rerank for %s' % [ records.size, pre_rerank, collection ],
136
+ data: {
137
+ collection:,
138
+ prompt_name:,
139
+ records: records.map { |r|
140
+ {
141
+ text: r.text,
142
+ similarity: r.similarity&.round(4),
143
+ tags: r.tags_set.to_s(link: false)
144
+ }
145
+ }
146
+ })
135
147
  records.empty? and return
136
148
  end
137
149
  snippets = records.map { |record|
@@ -161,13 +161,13 @@ module OllamaChat::Commands
161
161
 
162
162
  command(
163
163
  name: :toggle,
164
- regexp: %r(^/toggle(?:\s+(markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding)(?:\s+(-[yn]))?)?$),
165
- complete: [ 'toggle', %w[ markdown stream location runtime_info voice think_loud think_strip embedding ] ],
164
+ regexp: %r(^/toggle(?:\s+(markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding|memory_trigger)(?:\s+(-[yn]))?)?$),
165
+ complete: [ 'toggle', %w[ markdown stream location runtime_info voice think_loud think_strip embedding memory_trigger ] ],
166
166
  options: '[-y|-n]',
167
167
  help: <<~EOT
168
168
  🎛️ Toggle feature switches
169
- (markdown, stream, location, runtime_info,
170
- voice, think_loud, think_strip, embedding)
169
+ (markdown, stream, location, runtime_info,
170
+ voice, think_loud, think_strip, embedding, memory_trigger)
171
171
  Options: -y (on), -n (off)
172
172
  EOT
173
173
  ) do |toggle_name, flag|
@@ -191,7 +191,7 @@ module OllamaChat::Commands
191
191
  end
192
192
  else
193
193
  feedback(
194
- "Available toggles: markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding"
194
+ "Available toggles: markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding|memory_trigger"
195
195
  )
196
196
  end
197
197
  :next
@@ -391,14 +391,15 @@ module OllamaChat::Commands
391
391
 
392
392
  command(
393
393
  name: :conversation,
394
- regexp: %r(^/conversation\s+(clean|compact|save|load|summarize|report)((?:\s+-[sc])*)(?:\s+([^-].*\.jsonl?))?$),
395
- complete: [ 'conversation', %w[ save load clean compact summarize report ] ],
394
+ regexp: %r(^/conversation\s+(clean|compact summary|compact|save|load|summarize|report)((?:\s+-[sc])*)(?:\s+([^-].*\.jsonl?))?$),
395
+ complete: [ 'conversation', %w[ compact clean report compact\ summary summarize save load ] ],
396
396
  options: '[-s|-c] [FILENAME]',
397
397
  help: <<~EOT
398
398
  💾 Manage conversation content:
399
399
  - save/load: Export/import as .json or .jsonl
400
400
  - clean: Remove tool content, images, thinking
401
401
  - compact: Summarize old messages, keep recent
402
+ - compact summary: Show last compaction summary
402
403
  - summarize: Per-message narrative (-s sentence)
403
404
  - report: Generate a session report document
404
405
  EOT
@@ -426,16 +427,10 @@ module OllamaChat::Commands
426
427
  else
427
428
  feedback("Denied.", type: :denied)
428
429
  end
430
+ when 'compact summary'
431
+ show_compaction_summary
429
432
  when 'compact'
430
- if confirm?(
431
- prompt: '🔔 Compact conversation? Old messages will be summarized. (y/n) ',
432
- yes: /\Ay/i
433
- )
434
- then
435
- compact_with_retry
436
- else
437
- feedback("Denied.", type: :denied)
438
- end
433
+ compact_with_retry
439
434
  when 'summarize'
440
435
  opts = go_command('s', opts)
441
436
  summarize_conversation(sentence: opts[?s])
@@ -648,12 +643,12 @@ module OllamaChat::Commands
648
643
 
649
644
  command(
650
645
  name: :collection,
651
- regexp: %r(^/collection(?:\s+(change|clear|list|rename|update(?: all)?|new|edit|delete|query))?((?:\s+-[er])*)?$),
652
- complete: [ 'collection', %w[ change clear list rename update update\ all new edit delete query ] ],
646
+ regexp: %r(^/collection(?:\s+(change|clear(?: (?:tags|sources))?|list|rename|update(?: all)?|new|edit|delete|query))?((?:\s+-[er])*)?$),
647
+ complete: [ 'collection', %w[ change clear\ tags clear\ sources clear list rename update update\ all new edit delete query ] ],
653
648
  optional: true,
654
649
  help: <<~EOT
655
650
  📚 Manage RAG collections:
656
- - change/clear/list/rename
651
+ - change/clear/clear tags/clear sources/list/rename
657
652
  - update: Re-index modified docs
658
653
  - update all: Re-index all collections
659
654
  - new: Interactively create a new collection
@@ -665,7 +660,11 @@ module OllamaChat::Commands
665
660
  ) do |subcommand, opts|
666
661
  case subcommand
667
662
  when 'clear'
668
- clear_collection
663
+ clear_whole_collection
664
+ when 'clear tags'
665
+ clear_collection_tags
666
+ when 'clear sources'
667
+ clear_collection_sources
669
668
  when 'change'
670
669
  choose_collection(collection)
671
670
  when 'list'
@@ -829,12 +828,23 @@ module OllamaChat::Commands
829
828
 
830
829
  command(
831
830
  name: :compose,
832
- regexp: %r(^/compose$),
831
+ regexp: %r(^/compose(\s+-r)?\s*$),
832
+ options: '[-r]',
833
833
  help: <<~EOT
834
834
  \u270D Compose message in external editor
835
+ Options: -r pre-fill with quoted last assistant reply
835
836
  EOT
836
- ) do
837
- edit_text.full? or :next
837
+ ) do |opts|
838
+ opts = go_command('r', opts)
839
+ prefill = if opts[?r]
840
+ if msg = messages.find_last(content: true) { !_1.tool? && _1.role == 'assistant' }
841
+ msg.content.to_s.lines.map { "> #{_1}" }.join + "\n\n"
842
+ else
843
+ feedback('No assistant message to quote.', type: :warn)
844
+ next :next
845
+ end
846
+ end
847
+ edit_text(prefill).full? or :next
838
848
  end
839
849
 
840
850
  command(
@@ -21,7 +21,7 @@ module OllamaChat::Compaction
21
21
  # @return [String] a short natural-language description of the call.
22
22
  def tool_summary_line(tool_name, result)
23
23
  default_summary = "was called."
24
- klass = OllamaChat::Tools.registered[tool_name.to_s]&.class
24
+ klass = OllamaChat::Tools.registered_class(tool_name)
25
25
  klass&.summary_template(result:) || default_summary
26
26
  rescue StandardError
27
27
  default_summary
@@ -134,6 +134,33 @@ module OllamaChat::Compaction
134
134
  false
135
135
  end
136
136
 
137
+ # Displays the most recent compaction summary in the pager.
138
+ #
139
+ # Shows the narrative and the tool-call lookup index (the
140
+ # `lookup_group` entries with short UUIDs) carried in the summary
141
+ # message, prefixed with size metadata.
142
+ #
143
+ # @return [nil] always returns nil (command block handles :next).
144
+ def show_compaction_summary
145
+ unless msg = messages.find_summary
146
+ feedback('No compaction summary yet.', type: :info)
147
+ return
148
+ end
149
+ es = OllamaChat::TokenEstimator.estimate(msg.content.to_s)
150
+ use_pager do |output|
151
+ output.puts <<~EOT
152
+ #{bold{'Compaction Summary'}}
153
+ #{'─' * Tins::Terminal.columns}
154
+
155
+ #{kramdown_ansi_parse(msg.content.to_s)}
156
+
157
+ #{'─' * Tins::Terminal.columns}
158
+ Size: 👾#{es.bytes_formatted} 🧩#{es.tokens_formatted}
159
+ Tools: #{msg.tool_calls&.size || 0} lookup_group entries
160
+ EOT
161
+ end
162
+ end
163
+
137
164
  private
138
165
 
139
166
  # Serializes non-system messages into a readable block for the prompt.
@@ -172,7 +199,7 @@ module OllamaChat::Compaction
172
199
  def build_tool_entries(messages)
173
200
  messages.filter_map do |msg|
174
201
  next unless tool_name = msg.tool_name.full?
175
- next if tool_name == 'runtime_information'
202
+ next if %w[ runtime_information trigger_inject ].include?(tool_name)
176
203
  uuid = msg.group_uuid.to_s[-8..]
177
204
  summary = OllamaChat::Compaction.tool_summary_line(
178
205
  tool_name, msg.content.to_s
@@ -65,6 +65,27 @@ class OllamaChat::Database::Models::Session < Sequel::Model(OllamaChat::DB)
65
65
  messages.to_s.count(?\n)
66
66
  end
67
67
 
68
+ # Returns the `enabled` flag of the first configured trigger entry.
69
+ #
70
+ # @return [Boolean, nil] true when the trigger is active, false when
71
+ # explicitly disabled, nil when no trigger is configured
72
+ def trigger_enabled?
73
+ trigger&.values&.first&.[]('enabled')
74
+ end
75
+
76
+ # Sets the `enabled` flag of the first configured trigger entry and
77
+ # persists the change.
78
+ #
79
+ # No-op when no trigger is configured.
80
+ #
81
+ # @param value [Boolean] the new enabled state
82
+ def set_trigger_enabled(value)
83
+ if hash = trigger&.values&.first
84
+ hash['enabled'] = value
85
+ save
86
+ end
87
+ end
88
+
68
89
  # @!attribute [v] id
69
90
  # @return [Integer] The primary key for the session.
70
91
  #
@@ -180,7 +180,7 @@ class OllamaChat::FollowChat
180
180
  feedback(
181
181
  ("\n%s Execution of tool %s confirmed.\n\n" % [ symbol, bold { name } ])
182
182
  )
183
- result = OllamaChat::Tools.registered[name].execute(tool_call, chat:)
183
+ result = OllamaChat::Tools.registered_tool(name, chat:).execute(tool_call)
184
184
  chat.log(:info, "Tool execution confirmed", data: { tool: name, confirmed: })
185
185
  end
186
186
 
@@ -327,22 +327,6 @@ module OllamaChat::Information
327
327
  config.infobar.message.to_h
328
328
  end
329
329
 
330
- # Retrieves a hash of collection names and their descriptions from the
331
- # database.
332
- #
333
- # This is used to provide context to the AI model about available RAG
334
- # collections.
335
- #
336
- # @return [Hash{String => String}] a hash mapping collection names to their
337
- # descriptions
338
- def collection_descriptions
339
- cols = models::Collection.where(enabled: true)
340
- .select(:name, :description).order(:name)
341
- cols.each_with_object({}) do |c, hash|
342
- hash[c.name] = c.description
343
- end
344
- end
345
-
346
330
  # Generates a hash containing static runtime information.
347
331
  #
348
332
  # This method collects session-level constants including the user,
@@ -353,11 +337,9 @@ module OllamaChat::Information
353
337
  def static_runtime_information_values
354
338
  {
355
339
  client: ,
356
- collections: JSON.pretty_generate(collection_descriptions),
357
340
  current_directory: Pathname.pwd.expand_path.to_path,
358
341
  languages: config.languages * ', ',
359
342
  location: location.on?.full? { location_description } || 'n/a',
360
- tool_paths_allowed: JSON.pretty_generate(tool_paths_allowed),
361
343
  user: ,
362
344
  }
363
345
  end
@@ -369,7 +351,9 @@ module OllamaChat::Information
369
351
  #
370
352
  # @return [String] a formatted static runtime information string.
371
353
  def static_runtime_information
372
- prompt(:static_runtime_info).to_s % static_runtime_information_values
354
+ prompt(:static_runtime_info).to_s.named_placeholders_interpolate(
355
+ static_runtime_information_values
356
+ )
373
357
  end
374
358
 
375
359
  # Returns a formatted string representing the estimated text length of
@@ -423,7 +407,9 @@ module OllamaChat::Information
423
407
  #
424
408
  # @return [String] the formatted dynamic runtime information string.
425
409
  def dynamic_runtime_information
426
- prompt(:dynamic_runtime_info).to_s % dynamic_runtime_information_values
410
+ prompt(:dynamic_runtime_info).to_s.named_placeholders_interpolate(
411
+ dynamic_runtime_information_values
412
+ )
427
413
  end
428
414
 
429
415
  # Injects the current dynamic runtime information (the "heartbeat")
@@ -56,8 +56,6 @@ prompts:
56
56
  - Location: %{location}
57
57
  - Current directory is "%{current_directory}"
58
58
  - Client is %{client}.
59
- - These tools have access to these allowed paths: %{tool_paths_allowed}
60
- - Search in these collections with `search_knowledge`: %{collections}
61
59
  dynamic_runtime_info: |
62
60
  There is usually no reason to mention this information to the user unless
63
61
  asked about it.
@@ -424,7 +422,7 @@ prompts:
424
422
  To see the full output of any tool call above, use lookup_group
425
423
  with the group UUID in parentheses.
426
424
  system:
427
- default: <%= OC::OLLAMA::CHAT::SYSTEM || "%{persona}\n\n%{runtime_info}".inspect %>
425
+ default: <%= OC::OLLAMA::CHAT::SYSTEM || "`persona_name`: %{persona_name}\n\n%{persona}\n\n%{runtime_info}".inspect %>
428
426
  persona: |
429
427
  `persona_name`: %{persona_name}
430
428
 
@@ -497,6 +495,10 @@ document_policy: importing
497
495
  persona:
498
496
  # Basename (without .md) of the default persona file in the personae directory.
499
497
  default_name: personal_assistant
498
+ trigger:
499
+ enabled: true
500
+ prompt_name: memory_rerank
501
+ text_count: 3
500
502
  parsing:
501
503
  directory_structure_max_depth: 1
502
504
  think:
@@ -12,14 +12,17 @@ module OllamaChat::Pager
12
12
  # If the output would exceed the terminal's line capacity, it pipes the content
13
13
  # through an appropriate pager command (like 'less' or 'more').
14
14
  #
15
+ # @param force [Boolean] bypass the line-count threshold and always
16
+ # invoke the pager, regardless of output length.
15
17
  # @yield A block that yields an IO object to write output to
16
18
  # @yieldparam [IO] the IO object to write to
17
- def use_pager
19
+ def use_pager(force: false)
18
20
  command = determine_pager_command
19
21
  output_buffer = StringIO.new
20
22
  yield output_buffer
21
23
  buffer = output_buffer.string
22
- Kramdown::ANSI::Pager.pager(command:, lines: buffer.count(?\n)) do |output|
24
+ lines = force ? Float::INFINITY : buffer.count(?\n)
25
+ Kramdown::ANSI::Pager.pager(command:, lines:) do |output|
23
26
  output.puts buffer
24
27
  end
25
28
  end