ollama_chat 0.0.124 → 0.0.126
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 +4 -4
- data/CHANGES.md +177 -0
- data/Rakefile +2 -2
- data/bin/ollama_chat_log +1 -1
- data/lib/ollama_chat/chat.rb +5 -13
- data/lib/ollama_chat/collection_search.rb +102 -6
- data/lib/ollama_chat/commands.rb +29 -19
- data/lib/ollama_chat/compaction.rb +7 -3
- data/lib/ollama_chat/database/migrations/011_add_trigger_to_sessions.rb +7 -0
- data/lib/ollama_chat/database/models/session.rb +11 -0
- data/lib/ollama_chat/database/session_locking.rb +3 -2
- data/lib/ollama_chat/follow_chat.rb +1 -1
- data/lib/ollama_chat/information.rb +41 -23
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +45 -11
- data/lib/ollama_chat/pager.rb +5 -2
- data/lib/ollama_chat/rag_handling.rb +211 -22
- data/lib/ollama_chat/session_management.rb +104 -8
- data/lib/ollama_chat/source_fetching.rb +2 -2
- data/lib/ollama_chat/tool_calling.rb +3 -16
- data/lib/ollama_chat/tools/browse.rb +0 -1
- data/lib/ollama_chat/tools/compute_bmi.rb +1 -2
- data/lib/ollama_chat/tools/concern.rb +26 -0
- data/lib/ollama_chat/tools/copy_to_clipboard.rb +1 -3
- data/lib/ollama_chat/tools/delete_file.rb +4 -3
- data/lib/ollama_chat/tools/directory_structure.rb +0 -1
- data/lib/ollama_chat/tools/eval_ruby.rb +0 -1
- data/lib/ollama_chat/tools/execute_grep.rb +0 -2
- data/lib/ollama_chat/tools/execute_jira_twg.rb +0 -2
- data/lib/ollama_chat/tools/execute_ri.rb +0 -1
- data/lib/ollama_chat/tools/execute_shell.rb +4 -6
- data/lib/ollama_chat/tools/file_context.rb +0 -2
- data/lib/ollama_chat/tools/forget.rb +20 -8
- data/lib/ollama_chat/tools/gem_path_lookup.rb +0 -1
- data/lib/ollama_chat/tools/generate_image.rb +6 -8
- data/lib/ollama_chat/tools/generate_password.rb +0 -2
- data/lib/ollama_chat/tools/get_current_weather.rb +2 -4
- data/lib/ollama_chat/tools/get_cve.rb +0 -2
- data/lib/ollama_chat/tools/get_endoflife.rb +0 -2
- data/lib/ollama_chat/tools/get_ghr.rb +2 -4
- data/lib/ollama_chat/tools/get_jira_issue.rb +0 -2
- data/lib/ollama_chat/tools/get_location.rb +0 -2
- data/lib/ollama_chat/tools/get_rfc.rb +0 -2
- data/lib/ollama_chat/tools/get_time.rb +2 -3
- data/lib/ollama_chat/tools/get_url.rb +0 -2
- data/lib/ollama_chat/tools/lookup_group.rb +0 -2
- data/lib/ollama_chat/tools/memorize.rb +38 -13
- data/lib/ollama_chat/tools/move_file.rb +8 -4
- data/lib/ollama_chat/tools/open_file_in_editor.rb +0 -2
- data/lib/ollama_chat/tools/paste_from_clipboard.rb +1 -4
- data/lib/ollama_chat/tools/paste_into_editor.rb +3 -5
- data/lib/ollama_chat/tools/patch_file.rb +10 -7
- data/lib/ollama_chat/tools/read_file.rb +3 -5
- data/lib/ollama_chat/tools/resolve_tag.rb +1 -2
- data/lib/ollama_chat/tools/roll_dice.rb +0 -2
- data/lib/ollama_chat/tools/run_tests.rb +2 -2
- data/lib/ollama_chat/tools/search_knowledge.rb +14 -5
- data/lib/ollama_chat/tools/search_web.rb +0 -3
- data/lib/ollama_chat/tools/write_file.rb +4 -3
- data/lib/ollama_chat/tools.rb +50 -4
- data/lib/ollama_chat/utils/tag_resolver.rb +1 -1
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat/web_searching.rb +3 -3
- data/ollama_chat.gemspec +8 -8
- data/spec/ollama_chat/chat_spec.rb +1 -1
- data/spec/ollama_chat/collection_search_spec.rb +134 -0
- data/spec/ollama_chat/command_concern_spec.rb +174 -0
- data/spec/ollama_chat/commands_spec.rb +353 -11
- data/spec/ollama_chat/compaction_spec.rb +1 -1
- data/spec/ollama_chat/parsing_spec.rb +5 -5
- data/spec/ollama_chat/rag_handling_spec.rb +191 -18
- data/spec/ollama_chat/session_management_spec.rb +71 -3
- data/spec/ollama_chat/source_fetching_spec.rb +2 -2
- data/spec/ollama_chat/tool_calling_spec.rb +0 -11
- data/spec/ollama_chat/tools/browse_spec.rb +11 -7
- data/spec/ollama_chat/tools/compute_bmi_spec.rb +8 -8
- data/spec/ollama_chat/tools/concern_spec.rb +7 -1
- data/spec/ollama_chat/tools/copy_to_clipboard_spec.rb +8 -8
- data/spec/ollama_chat/tools/delete_file_spec.rb +7 -7
- data/spec/ollama_chat/tools/directory_structure_spec.rb +7 -7
- data/spec/ollama_chat/tools/execute_grep_spec.rb +10 -10
- data/spec/ollama_chat/tools/execute_jira_twg_spec.rb +8 -8
- data/spec/ollama_chat/tools/execute_ri_spec.rb +6 -6
- data/spec/ollama_chat/tools/execute_shell_spec.rb +1 -1
- data/spec/ollama_chat/tools/file_context_spec.rb +4 -4
- data/spec/ollama_chat/tools/forget_spec.rb +25 -15
- data/spec/ollama_chat/tools/gem_path_lookup_spec.rb +5 -5
- data/spec/ollama_chat/tools/generate_image_spec.rb +10 -10
- data/spec/ollama_chat/tools/generate_password_spec.rb +8 -8
- data/spec/ollama_chat/tools/get_current_weather_spec.rb +6 -6
- data/spec/ollama_chat/tools/get_cve_spec.rb +5 -5
- data/spec/ollama_chat/tools/get_endoflife_spec.rb +5 -5
- data/spec/ollama_chat/tools/get_ghr_spec.rb +11 -11
- data/spec/ollama_chat/tools/get_jira_issue_spec.rb +6 -6
- data/spec/ollama_chat/tools/get_location_spec.rb +6 -6
- data/spec/ollama_chat/tools/get_rfc_spec.rb +5 -5
- data/spec/ollama_chat/tools/get_time_spec.rb +4 -4
- data/spec/ollama_chat/tools/get_url_spec.rb +17 -17
- data/spec/ollama_chat/tools/lookup_group_spec.rb +5 -5
- data/spec/ollama_chat/tools/memorize_spec.rb +67 -11
- data/spec/ollama_chat/tools/move_file_spec.rb +8 -8
- data/spec/ollama_chat/tools/open_file_in_editor_spec.rb +6 -6
- data/spec/ollama_chat/tools/paste_from_clipboard_spec.rb +7 -7
- data/spec/ollama_chat/tools/paste_into_editor_spec.rb +6 -6
- data/spec/ollama_chat/tools/patch_file_spec.rb +9 -9
- data/spec/ollama_chat/tools/read_file_spec.rb +12 -12
- data/spec/ollama_chat/tools/resolve_tag_spec.rb +11 -15
- data/spec/ollama_chat/tools/roll_dice_spec.rb +6 -6
- data/spec/ollama_chat/tools/run_tests_spec.rb +13 -13
- data/spec/ollama_chat/tools/search_knowledge_spec.rb +33 -28
- data/spec/ollama_chat/tools/search_web_spec.rb +6 -6
- data/spec/ollama_chat/tools/write_file_spec.rb +15 -15
- metadata +12 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93612bbed949bff6bad6cf89f581b324165c0aa672f6f92b675b63a6a2dce7e0
|
|
4
|
+
data.tar.gz: 79aac9f7dada8df87035af5bdfd2913d16012af44a781b7a20c44a457163b313
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2eb715b50338ddb686e6aab7debd264591e1018216adef57146237a862a5f37f217a31bb481a724b4bb8fcc99144c1a40679e3048c64cb88f0eaaabd546661fc
|
|
7
|
+
data.tar.gz: 8fa30b91ba125939cd506078bcaf6c9549bb43aa6323f9186e0acae218c7814fd8add54aa75b39f907d4affc78889c52a45b2479ec57c4218d76e61e67843ed3
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,182 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-10-05 v0.0.126
|
|
4
|
+
|
|
5
|
+
* **Tool Registry Refactor**: Refactored the tool registry to store tool
|
|
6
|
+
classes instead of pre-built instances.
|
|
7
|
+
* `registered_class(name)` now returns the class for `summary_template`
|
|
8
|
+
access.
|
|
9
|
+
* `registered_tool(name, chat:)` instantiates a fresh instance bound to
|
|
10
|
+
the current session.
|
|
11
|
+
* `Concern#initialize(chat)` injects the chat reference; all tools now
|
|
12
|
+
access config via `self.chat` instead of `opts[:chat]`.
|
|
13
|
+
* Helper methods in `execute_shell`, `generate_image`,
|
|
14
|
+
`get_current_weather`, `get_ghr`, and `patch_file` now use `self.chat`
|
|
15
|
+
directly.
|
|
16
|
+
* Migrated all tool specs to use `described_class.new(chat)` and
|
|
17
|
+
`.execute(tool_call)`.
|
|
18
|
+
|
|
19
|
+
* **Path Allowlists**: Moved path allowlists into tool parameter
|
|
20
|
+
descriptions.
|
|
21
|
+
* Added `allowed_paths` to `tools/concern.rb` to return expanded,
|
|
22
|
+
existing paths for the calling tool's `allowed` config.
|
|
23
|
+
* Removed `tool_paths_allowed` from `tool_calling.rb` and its spec.
|
|
24
|
+
* Injected `allowed_paths.map(&:inspect).join(', ')` into the `path`,
|
|
25
|
+
`source`, and `destination` parameter descriptions of `delete_file`,
|
|
26
|
+
`move_file`, `patch_file`, `read_file`, and `write_file`.
|
|
27
|
+
|
|
28
|
+
* **RAG Handling & Runtime Info**: Relocated `collection_descriptions` from
|
|
29
|
+
`information.rb` to `rag_handling.rb`.
|
|
30
|
+
* Removed `collections` key from `static_runtime_information_values` and
|
|
31
|
+
`default_config.yml`.
|
|
32
|
+
* Migrated `static_runtime_information` and `dynamic_runtime_information`
|
|
33
|
+
from `String#%` to `named_placeholders_interpolate`.
|
|
34
|
+
|
|
35
|
+
* **Collection Commands**: Reworked collection clearing into three distinct
|
|
36
|
+
commands.
|
|
37
|
+
* Split monolithic `clear_collection` into `clear_whole_collection`,
|
|
38
|
+
`clear_collection_tags`, and `clear_collection_sources`.
|
|
39
|
+
* `clear_collection_tags` implements a two-level tag-to-source browser.
|
|
40
|
+
* `clear_collection_sources` implements a source-to-tags browser.
|
|
41
|
+
* Added `use_pager(force:)` keyword in `pager.rb` to bypass size checks
|
|
42
|
+
using `Float::INFINITY`.
|
|
43
|
+
* Added `Kramdown::ANSI::Width.wrap(..., percentage: 90)` to pager views
|
|
44
|
+
for terminal-width wrapping.
|
|
45
|
+
* Bumped `documentrix` minimum to **0.8.0** in `Rakefile` and
|
|
46
|
+
`ollama_chat.gemspec` for the new `records(tags:, sources:)` API.
|
|
47
|
+
* Extended `/collection` regexp and completion for `clear sources`.
|
|
48
|
+
|
|
49
|
+
* **Memory Tools**: Enhanced memory management tools.
|
|
50
|
+
* `memorize` now accepts an optional `update` kwarg (ISO timestamp tag)
|
|
51
|
+
to replace an existing memory entry, returning `replaced_timestamp` and
|
|
52
|
+
`replaced_text`.
|
|
53
|
+
* `forget` now returns `forgotten_text` in the JSON response and includes
|
|
54
|
+
an 80-character snippet in the human-readable `message`.
|
|
55
|
+
* Renamed `set_current_collection` to `set_documents_collection` in
|
|
56
|
+
`rag_handling.rb`, `session_management.rb`, and specs.
|
|
57
|
+
* Made `current_collection` public in `RAGHandling`.
|
|
58
|
+
* Enriched `search_knowledge` tool `collection` param with allowed
|
|
59
|
+
collections from `collection_descriptions` and current default.
|
|
60
|
+
|
|
61
|
+
* **Session Management**:
|
|
62
|
+
* Derive memory trigger from persona at session apply by adding a
|
|
63
|
+
`trigger` block to `default_config.yml`.
|
|
64
|
+
* Extracted `create_memory_collection` into `RAGHandling` as the single
|
|
65
|
+
canonical entry point.
|
|
66
|
+
* In `SessionManagement#session_apply`, auto-derive the session trigger
|
|
67
|
+
from `initial_persona_name` and `config.trigger` when no explicit
|
|
68
|
+
trigger is set.
|
|
69
|
+
* Advertise `C-u` random shortcut in the session prompt to clear prefill
|
|
70
|
+
and obtain a random session name.
|
|
71
|
+
|
|
72
|
+
* **Commands & UX**:
|
|
73
|
+
* Added `-r` flag to `/compose` to quote the last assistant reply as an
|
|
74
|
+
`edit_text` pre-fill.
|
|
75
|
+
* Removed the `confirm?` prompt before `compact_with_retry` in
|
|
76
|
+
`/conversation compact`; compaction now runs immediately.
|
|
77
|
+
* Split `/collection clear` into `clear tags` subcommand and bare `clear`
|
|
78
|
+
routing to `clear_whole_collection`.
|
|
79
|
+
|
|
80
|
+
* **Tool Descriptions & Logging**:
|
|
81
|
+
* Made `paste_into_editor` description imperative.
|
|
82
|
+
* Documented bottom-up edit order in `patch_file` to prevent models from
|
|
83
|
+
incorrectly compensating for line shifts.
|
|
84
|
+
* Log full `edits` array in `patch_file` tool info log payload instead of
|
|
85
|
+
just `edits_count`.
|
|
86
|
+
* Strip ANSI codes from `run_tests` captured output using
|
|
87
|
+
`OllamaChat::Utils::StripANSI`.
|
|
88
|
+
|
|
89
|
+
* **Compatibility & Fixes**:
|
|
90
|
+
* Include `persona_name` in the `default` system prompt template in
|
|
91
|
+
`default_config.yml`.
|
|
92
|
+
|
|
93
|
+
## 2026-10-03 v0.0.125
|
|
94
|
+
|
|
95
|
+
### Added
|
|
96
|
+
|
|
97
|
+
* Session-scoped trigger injection mechanism:
|
|
98
|
+
* New migration `011_add_trigger_to_sessions` adding a `:text` JSON column to
|
|
99
|
+
`sessions`.
|
|
100
|
+
* `Session#trigger` attribute with `plugin :serialization, :json` and `nil`
|
|
101
|
+
default.
|
|
102
|
+
* `CollectionSearch#trigger_inject` dispatch logic including embedding
|
|
103
|
+
guards, collection switching, document finding, and reranking.
|
|
104
|
+
* New `/session trigger edit` command registered in `commands.rb`.
|
|
105
|
+
* `edit_session_trigger` method in `session_management.rb` supporting dual
|
|
106
|
+
chooser and prefill.
|
|
107
|
+
* Trigger configuration display (⚡ block) added to `info_rag` in
|
|
108
|
+
`information.rb`.
|
|
109
|
+
* `runtime_information_inject` extracted from `chat.rb` into
|
|
110
|
+
`information.rb`.
|
|
111
|
+
* New prompt contexts: `prompts.rerank` (`default`, `memory_rerank`,
|
|
112
|
+
`lorebook_rerank`), `prompts.prompt.snippets_retrieval`, and
|
|
113
|
+
`prompts.prompt.snippets_trigger`.
|
|
114
|
+
* `persona_name` line added to `prompts.system.persona`.
|
|
115
|
+
* `TagResult` changed from `Data.define` to `Struct.new` to allow mutable
|
|
116
|
+
fields.
|
|
117
|
+
* `∅` fallback for empty patterns in `collection_stats`.
|
|
118
|
+
* Info-level logging for embedding requests/responses and rerank survivors in
|
|
119
|
+
`collection_search.rb`.
|
|
120
|
+
* New spec file `collection_search_spec.rb` with 7 examples for
|
|
121
|
+
`#trigger_inject`.
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
* `SessionLocking#lock?` now accepts a required `chat:` keyword argument to
|
|
126
|
+
decouple feedback delegation from the host object.
|
|
127
|
+
* `search_knowledge.rb` updated to use `snippets_retrieval` DB prompt,
|
|
128
|
+
`collection` block, and `database_collection?` guard.
|
|
129
|
+
* `@embedding` instance variable swept to `embedding` accessor in
|
|
130
|
+
`information.rb`, `source_fetching.rb`, and `web_searching.rb`.
|
|
131
|
+
* `Tins::Duration#format` used for compaction voice timing in
|
|
132
|
+
`report_compaction`, replacing `%.1f seconds`.
|
|
133
|
+
* `tins` dependency bumped from `~> **1.58**` to `~> **1.60**` to support
|
|
134
|
+
unpadded `%H`, `%M`, and `%u` directives.
|
|
135
|
+
* `resolve_tag_spec.rb` updated to replace an unreachable rescue-path test with
|
|
136
|
+
a "tagged file does not exist" test.
|
|
137
|
+
* `search_knowledge_spec.rb` updated for new prompt names, `collection` block,
|
|
138
|
+
and `tags_set` doubles.
|
|
139
|
+
* `compaction_spec.rb` regex updated to match the new duration format.
|
|
140
|
+
* `Tins::GO.go` flag string reordered in `bin/ollama_chat_log`.
|
|
141
|
+
|
|
142
|
+
### Fixed
|
|
143
|
+
|
|
144
|
+
* Spec expectations in `session_management_spec.rb`, `parsing_spec.rb`, and
|
|
145
|
+
`source_fetching_spec.rb` updated to use Ruby 3.1+ hash shorthand `chat:`.
|
|
146
|
+
|
|
147
|
+
### Tests
|
|
148
|
+
|
|
149
|
+
* Added specs for `CommandConcern` class methods:
|
|
150
|
+
* `help_message` via `OllamaChat::Commands`: table structure, category
|
|
151
|
+
headers, pattern filtering, subcommand expansion, and optional/mandatory
|
|
152
|
+
asterisks.
|
|
153
|
+
* `command_completions`: array shape, bare names, subcommand variants, and
|
|
154
|
+
sort order.
|
|
155
|
+
* `Command` class: `execute_if_match?` (match, captures, nil-regexp path,
|
|
156
|
+
no-context error), `completions` (product, optional bare, strict),
|
|
157
|
+
`command_names`, and `optional?`.
|
|
158
|
+
* Duplicate registration guard against the real `:copy` entry in
|
|
159
|
+
`OllamaChat::Commands`.
|
|
160
|
+
* Added specs for remaining command dispatch gaps:
|
|
161
|
+
* `/paste -i` stdin path via `paste_from_stdin`.
|
|
162
|
+
* `/last -v` voice output via `speak_last`.
|
|
163
|
+
* `/regenerate` success path (drop + return content).
|
|
164
|
+
* `/prompt delete` routes to `choose_and_delete_prompt`.
|
|
165
|
+
* `/web` without explicit count passes `nil`.
|
|
166
|
+
* `/character` JSON success paths: `info` (pager), `load` (raw content),
|
|
167
|
+
`import` (delegation).
|
|
168
|
+
* `/character` PNG `load` with `PNGMetadataExtractor`.
|
|
169
|
+
* Added specs for `SessionManagement#edit_session_trigger`:
|
|
170
|
+
* Setting trigger from `nil` to a configured hash with `enabled`,
|
|
171
|
+
`prompt_name`, and `text_count`.
|
|
172
|
+
* Updating config for an already-configured collection.
|
|
173
|
+
* Switching the trigger to a different collection name.
|
|
174
|
+
* Added specs for session model options and trigger edit:
|
|
175
|
+
* `/session model options` delegates to `edit_session_model_options` and
|
|
176
|
+
returns `:next`.
|
|
177
|
+
* `/session trigger edit` delegates to `edit_session_trigger` and returns
|
|
178
|
+
`:next`.
|
|
179
|
+
|
|
3
180
|
## 2026-10-02 v0.0.124
|
|
4
181
|
|
|
5
182
|
### 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.
|
|
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'
|
|
@@ -49,7 +49,7 @@ GemHadar do
|
|
|
49
49
|
dependency 'reverse_markdown', '~> 3.0'
|
|
50
50
|
dependency 'kramdown-ansi', '~> 0.5'
|
|
51
51
|
dependency 'complex_config', '~> 0.22', '>= 0.22.2'
|
|
52
|
-
dependency 'tins', '~> 1.
|
|
52
|
+
dependency 'tins', '~> 1.60'
|
|
53
53
|
dependency 'search_ui', '>= 0.2'
|
|
54
54
|
dependency 'amatch', '~> 0.4'
|
|
55
55
|
dependency 'pdf-reader', '~> 2.0'
|
data/bin/ollama_chat_log
CHANGED
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -314,10 +314,11 @@ class OllamaChat::Chat
|
|
|
314
314
|
# instance when a background thread was spawned (so callers can call
|
|
315
315
|
# `cancel_speaking`), or `nil` for inline playback or when voice is off
|
|
316
316
|
def speak(text, background: true)
|
|
317
|
+
session or return
|
|
317
318
|
voice.on? or return
|
|
318
|
-
|
|
319
|
+
current_voice = session.current_voice.full? or return
|
|
319
320
|
voice_handler.method_defined?(:speak) or return
|
|
320
|
-
voice_handler.new(chat: self, voice:).speak(text, background:)
|
|
321
|
+
voice_handler.new(chat: self, voice: current_voice).speak(text, background:)
|
|
321
322
|
end
|
|
322
323
|
|
|
323
324
|
# Returns a human-readable string representation of the Chat object,
|
|
@@ -553,17 +554,8 @@ class OllamaChat::Chat
|
|
|
553
554
|
group_uuid:
|
|
554
555
|
)
|
|
555
556
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
messages << OllamaChat::Message.new(
|
|
559
|
-
role: 'user',
|
|
560
|
-
tool_name: ,
|
|
561
|
-
sender_name: tool_name,
|
|
562
|
-
content: dynamic_runtime_information,
|
|
563
|
-
images: @images.dup,
|
|
564
|
-
group_uuid:
|
|
565
|
-
)
|
|
566
|
-
end
|
|
557
|
+
runtime_information_inject(group_uuid:)
|
|
558
|
+
trigger_inject(content, group_uuid:)
|
|
567
559
|
end
|
|
568
560
|
@images.clear
|
|
569
561
|
handler = OllamaChat::FollowChat.new(
|
|
@@ -24,14 +24,37 @@ module OllamaChat::CollectionSearch
|
|
|
24
24
|
tags = Documentrix::Utils::Tags.new(
|
|
25
25
|
tags, valid_tag: /\A#*([-\w.\]\[]+)/
|
|
26
26
|
)
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
effective_query = query.first(
|
|
28
|
+
config.embedding.model.context_length
|
|
29
|
+
)
|
|
30
|
+
embedding_prompt = config.embedding.model.prompt?
|
|
31
|
+
log(
|
|
32
|
+
:info, 'Embedding search request',
|
|
33
|
+
data: {
|
|
34
|
+
model: config.embedding.model.to_h,
|
|
35
|
+
collection: collection,
|
|
36
|
+
query: effective_query,
|
|
37
|
+
prompt: embedding_prompt,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
records = @documents.find_where(
|
|
41
|
+
effective_query,
|
|
29
42
|
tags:,
|
|
30
|
-
prompt:
|
|
43
|
+
prompt: embedding_prompt,
|
|
31
44
|
text_size:,
|
|
32
45
|
text_count:,
|
|
33
46
|
min_similarity:
|
|
34
47
|
)
|
|
48
|
+
log(
|
|
49
|
+
:info, 'Embedding search response',
|
|
50
|
+
data: {
|
|
51
|
+
collection: collection,
|
|
52
|
+
query: effective_query,
|
|
53
|
+
result_count: records.size,
|
|
54
|
+
top: records.first&.similarity&.round(4),
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
records
|
|
35
58
|
end
|
|
36
59
|
|
|
37
60
|
# Reranks a set of records using the LLM with the `rerank` prompt.
|
|
@@ -43,11 +66,11 @@ module OllamaChat::CollectionSearch
|
|
|
43
66
|
# @return [Array<Documentrix::Utils::TagResult>] filtered records
|
|
44
67
|
def rerank_records(query, records, prompt_name: nil)
|
|
45
68
|
candidates = records.each_with_index.map { |r, i|
|
|
46
|
-
"[#{i}] #{truncate(r.text.
|
|
69
|
+
"[#{i}] #{r.tags_set.to_s(link: false)} #{truncate(r.text.squeeze, length: 300)}"
|
|
47
70
|
}.join("\n")
|
|
48
71
|
|
|
49
|
-
prompt_name ||= '
|
|
50
|
-
rerank_prompt = prompt(prompt_name) or
|
|
72
|
+
prompt_name ||= 'default'
|
|
73
|
+
rerank_prompt = prompt(prompt_name, context: 'rerank') or
|
|
51
74
|
raise 'missing prompt %s' % prompt_name.inspect
|
|
52
75
|
rerank_prompt = rerank_prompt.to_s
|
|
53
76
|
.named_placeholders_interpolate({ query:, candidates: })
|
|
@@ -63,4 +86,77 @@ module OllamaChat::CollectionSearch
|
|
|
63
86
|
end
|
|
64
87
|
records
|
|
65
88
|
end
|
|
89
|
+
|
|
90
|
+
# Injects relevant snippets from the session's trigger collection
|
|
91
|
+
# into the conversation as a tool message.
|
|
92
|
+
#
|
|
93
|
+
# Reads the first entry of the session's `trigger` hash, performs a
|
|
94
|
+
# vector search in the configured collection, reranks the candidates
|
|
95
|
+
# via the LLM, and appends a `trigger_inject` tool message containing
|
|
96
|
+
# the surviving snippets (text, similarity, tags). The message is
|
|
97
|
+
# grouped with the current user message via `group_uuid`.
|
|
98
|
+
#
|
|
99
|
+
# @param content [String] the parsed user message text used as the
|
|
100
|
+
# search query
|
|
101
|
+
# @param group_uuid [String, nil] the group UUID for message grouping
|
|
102
|
+
# (shared with the user message and runtime-info message)
|
|
103
|
+
#
|
|
104
|
+
# @return [self, nil] self if snippets were injected, nil if no
|
|
105
|
+
# trigger is configured, the trigger or embedding is disabled, the
|
|
106
|
+
# collection or prompt is missing, or no snippets survived reranking
|
|
107
|
+
def trigger_inject(content, group_uuid:)
|
|
108
|
+
embedding.on? or return
|
|
109
|
+
trigger = session.trigger&.first or return
|
|
110
|
+
collection, config = trigger
|
|
111
|
+
unless config['enabled']
|
|
112
|
+
log(:info, 'Trigger for collection %s disabled.' % collection)
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
unless col = database_collection?(collection)
|
|
116
|
+
log(:error, 'Unknown collection named %s' % collection)
|
|
117
|
+
return
|
|
118
|
+
end
|
|
119
|
+
prompt_name = config['prompt_name']
|
|
120
|
+
unless rerank_prompt = prompt(prompt_name, context: 'rerank').full?(:to_s)
|
|
121
|
+
log(
|
|
122
|
+
:error, 'Unknown rerank prompt named %s' % prompt_name,
|
|
123
|
+
data: { config: }
|
|
124
|
+
)
|
|
125
|
+
return
|
|
126
|
+
end
|
|
127
|
+
records = []
|
|
128
|
+
switch_collection(collection) do
|
|
129
|
+
records = find_document_records(content, text_count: config['text_count'])
|
|
130
|
+
records.empty? and return
|
|
131
|
+
pre_rerank = records.size
|
|
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: })
|
|
135
|
+
records.empty? and return
|
|
136
|
+
end
|
|
137
|
+
snippets = records.map { |record|
|
|
138
|
+
{
|
|
139
|
+
text: record.text,
|
|
140
|
+
similarity: record.similarity.to_f,
|
|
141
|
+
tags: record.tags_set.to_s(link: false),
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
message_content = {
|
|
145
|
+
prompt: prompt('snippets_trigger').to_s,
|
|
146
|
+
collection: {
|
|
147
|
+
name: collection,
|
|
148
|
+
description: col.description&.to_s,
|
|
149
|
+
},
|
|
150
|
+
snippets:
|
|
151
|
+
}.to_json
|
|
152
|
+
tool_name = 'trigger_inject'
|
|
153
|
+
messages << OllamaChat::Message.new(
|
|
154
|
+
role: 'user',
|
|
155
|
+
tool_name: ,
|
|
156
|
+
sender_name: tool_name,
|
|
157
|
+
content: message_content,
|
|
158
|
+
group_uuid:
|
|
159
|
+
)
|
|
160
|
+
self
|
|
161
|
+
end
|
|
66
162
|
end
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -113,15 +113,16 @@ module OllamaChat::Commands
|
|
|
113
113
|
|
|
114
114
|
command(
|
|
115
115
|
name: :session,
|
|
116
|
-
regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|delete|model options change|model options))?((?:\s+-(?:p\s*\w+))*)(?:\s+([^-].*))?$),
|
|
117
|
-
complete: [ 'session', %w[ change previous list new duplicate rename delete model\ options\ change model\ options ] ],
|
|
116
|
+
regexp: %r(^/session(?:\s+(change|previous|list|new|duplicate|rename|delete|model options change|model options|trigger edit))?((?:\s+-(?:p\s*\w+))*)(?:\s+([^-].*))?$),
|
|
117
|
+
complete: [ 'session', %w[ change previous list new duplicate rename delete model\ options\ change model\ options trigger\ edit ] ],
|
|
118
118
|
optional: true,
|
|
119
119
|
options: "[-p profile]\n[name]",
|
|
120
120
|
help: <<~EOT
|
|
121
121
|
💬 Manage sessions:
|
|
122
122
|
- list/new/delete/rename/duplicate
|
|
123
123
|
- change [name]/previous
|
|
124
|
-
|
|
124
|
+
- model options/change
|
|
125
|
+
- trigger edit
|
|
125
126
|
EOT
|
|
126
127
|
) do |subcommand, opts, name|
|
|
127
128
|
case subcommand
|
|
@@ -152,6 +153,8 @@ module OllamaChat::Commands
|
|
|
152
153
|
else
|
|
153
154
|
feedback("No previous session defined.", type: :info)
|
|
154
155
|
end
|
|
156
|
+
when 'trigger edit'
|
|
157
|
+
edit_session_trigger
|
|
155
158
|
end
|
|
156
159
|
:next
|
|
157
160
|
end
|
|
@@ -424,15 +427,7 @@ module OllamaChat::Commands
|
|
|
424
427
|
feedback("Denied.", type: :denied)
|
|
425
428
|
end
|
|
426
429
|
when 'compact'
|
|
427
|
-
|
|
428
|
-
prompt: '🔔 Compact conversation? Old messages will be summarized. (y/n) ',
|
|
429
|
-
yes: /\Ay/i
|
|
430
|
-
)
|
|
431
|
-
then
|
|
432
|
-
compact_with_retry
|
|
433
|
-
else
|
|
434
|
-
feedback("Denied.", type: :denied)
|
|
435
|
-
end
|
|
430
|
+
compact_with_retry
|
|
436
431
|
when 'summarize'
|
|
437
432
|
opts = go_command('s', opts)
|
|
438
433
|
summarize_conversation(sentence: opts[?s])
|
|
@@ -645,12 +640,12 @@ module OllamaChat::Commands
|
|
|
645
640
|
|
|
646
641
|
command(
|
|
647
642
|
name: :collection,
|
|
648
|
-
regexp: %r(^/collection(?:\s+(change|clear|list|rename|update(?: all)?|new|edit|delete|query))?((?:\s+-[er])*)?$),
|
|
649
|
-
complete: [ 'collection', %w[ change clear list rename update update\ all new edit delete query ] ],
|
|
643
|
+
regexp: %r(^/collection(?:\s+(change|clear(?: (?:tags|sources))?|list|rename|update(?: all)?|new|edit|delete|query))?((?:\s+-[er])*)?$),
|
|
644
|
+
complete: [ 'collection', %w[ change clear\ tags clear\ sources clear list rename update update\ all new edit delete query ] ],
|
|
650
645
|
optional: true,
|
|
651
646
|
help: <<~EOT
|
|
652
647
|
📚 Manage RAG collections:
|
|
653
|
-
|
|
648
|
+
- change/clear/clear tags/clear sources/list/rename
|
|
654
649
|
- update: Re-index modified docs
|
|
655
650
|
- update all: Re-index all collections
|
|
656
651
|
- new: Interactively create a new collection
|
|
@@ -662,7 +657,11 @@ module OllamaChat::Commands
|
|
|
662
657
|
) do |subcommand, opts|
|
|
663
658
|
case subcommand
|
|
664
659
|
when 'clear'
|
|
665
|
-
|
|
660
|
+
clear_whole_collection
|
|
661
|
+
when 'clear tags'
|
|
662
|
+
clear_collection_tags
|
|
663
|
+
when 'clear sources'
|
|
664
|
+
clear_collection_sources
|
|
666
665
|
when 'change'
|
|
667
666
|
choose_collection(collection)
|
|
668
667
|
when 'list'
|
|
@@ -826,12 +825,23 @@ module OllamaChat::Commands
|
|
|
826
825
|
|
|
827
826
|
command(
|
|
828
827
|
name: :compose,
|
|
829
|
-
regexp: %r(^/compose
|
|
828
|
+
regexp: %r(^/compose(\s+-r)?\s*$),
|
|
829
|
+
options: '[-r]',
|
|
830
830
|
help: <<~EOT
|
|
831
831
|
\u270D Compose message in external editor
|
|
832
|
+
Options: -r pre-fill with quoted last assistant reply
|
|
832
833
|
EOT
|
|
833
|
-
) do
|
|
834
|
-
|
|
834
|
+
) do |opts|
|
|
835
|
+
opts = go_command('r', opts)
|
|
836
|
+
prefill = if opts[?r]
|
|
837
|
+
if msg = messages.find_last(content: true) { !_1.tool? && _1.role == 'assistant' }
|
|
838
|
+
msg.content.to_s.lines.map { "> #{_1}" }.join + "\n\n"
|
|
839
|
+
else
|
|
840
|
+
feedback('No assistant message to quote.', type: :warn)
|
|
841
|
+
next :next
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
edit_text(prefill).full? or :next
|
|
835
845
|
end
|
|
836
846
|
|
|
837
847
|
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.
|
|
24
|
+
klass = OllamaChat::Tools.registered_class(tool_name)
|
|
25
25
|
klass&.summary_template(result:) || default_summary
|
|
26
26
|
rescue StandardError
|
|
27
27
|
default_summary
|
|
@@ -295,11 +295,15 @@ module OllamaChat::Compaction
|
|
|
295
295
|
Context: #{result.context_before} → #{result.context_after}
|
|
296
296
|
Stored total: #{result.stored_total}
|
|
297
297
|
EOT
|
|
298
|
+
duration = Tins::Duration.new(duration)
|
|
299
|
+
duration_string = duration.format(
|
|
300
|
+
duration.minutes? ? '%M minutes and %u seconds' : '%u seconds'
|
|
301
|
+
)
|
|
298
302
|
speak(
|
|
299
|
-
'Compressed conversation context from %.f to %.f in
|
|
303
|
+
'Compressed conversation context from %.f to %.f in %s.' % [
|
|
300
304
|
100 * result.context_filled_before,
|
|
301
305
|
100 * result.context_filled_after,
|
|
302
|
-
|
|
306
|
+
duration_string,
|
|
303
307
|
]
|
|
304
308
|
)
|
|
305
309
|
end
|
|
@@ -12,6 +12,7 @@ class OllamaChat::Database::Models::Session < Sequel::Model(OllamaChat::DB)
|
|
|
12
12
|
plugin :touch
|
|
13
13
|
plugin :serialization, :json, :tools_default_enabled
|
|
14
14
|
plugin :serialization, :json, :model_options
|
|
15
|
+
plugin :serialization, :json, :trigger
|
|
15
16
|
plugin :validation_helpers
|
|
16
17
|
|
|
17
18
|
# Validates the session instance.
|
|
@@ -133,6 +134,15 @@ class OllamaChat::Database::Models::Session < Sequel::Model(OllamaChat::DB)
|
|
|
133
134
|
# @!attribute [v] model_options
|
|
134
135
|
# @return [String, nil] A JSON-serialized string containing model-specific options.
|
|
135
136
|
#
|
|
137
|
+
# @!attribute [v] trigger
|
|
138
|
+
# @return [Hash, nil] Maps collection names to search/rerank
|
|
139
|
+
# overrides, e.g.
|
|
140
|
+
# `{ 'memory-miyu' => { 'prompt_name' => 'memory_rerank',
|
|
141
|
+
# 'text_count' => 5 } }`.
|
|
142
|
+
# Recognized keys: `prompt_name`, `text_count`, `text_size`,
|
|
143
|
+
# `min_similarity`.
|
|
144
|
+
# `nil` when the trigger mechanism is disabled for this session.
|
|
145
|
+
#
|
|
136
146
|
# @!attribute [v] messages
|
|
137
147
|
# @return [String] The full conversation history, stored in JSONL format.
|
|
138
148
|
#
|
|
@@ -184,6 +194,7 @@ class OllamaChat::Database::Models::Session < Sequel::Model(OllamaChat::DB)
|
|
|
184
194
|
context_format: chat.config.context.format,
|
|
185
195
|
working_directory: Dir.pwd,
|
|
186
196
|
messages: '',
|
|
197
|
+
trigger: nil,
|
|
187
198
|
}
|
|
188
199
|
new(attributes)
|
|
189
200
|
end
|
|
@@ -25,10 +25,11 @@ module OllamaChat::Database::SessionLocking
|
|
|
25
25
|
|
|
26
26
|
# Attempts to acquire a lock on the session.
|
|
27
27
|
#
|
|
28
|
+
# @param chat [OllamaChat] the chat instance that receives feedback
|
|
28
29
|
# @return [Boolean] true if the lock was successfully acquired, false if already locked.
|
|
29
|
-
def lock?
|
|
30
|
+
def lock?(chat:)
|
|
30
31
|
if running_pid = locked?
|
|
31
|
-
feedback("session #{id} locked by running process #{running_pid}", type: :warn)
|
|
32
|
+
chat.feedback("session #{id} locked by running process #{running_pid}", type: :warn)
|
|
32
33
|
false
|
|
33
34
|
else
|
|
34
35
|
lock
|
|
@@ -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.
|
|
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
|
|