ollama_chat 0.0.126 → 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.
- checksums.yaml +4 -4
- data/CHANGES.md +62 -0
- data/lib/ollama_chat/chat.rb +2 -2
- data/lib/ollama_chat/collection_search.rb +14 -2
- data/lib/ollama_chat/commands.rb +10 -7
- data/lib/ollama_chat/compaction.rb +28 -1
- data/lib/ollama_chat/database/models/session.rb +21 -0
- data/lib/ollama_chat/rag_handling.rb +10 -10
- data/lib/ollama_chat/switches.rb +79 -9
- data/lib/ollama_chat/tools/execute_shell.rb +1 -1
- data/lib/ollama_chat/tools/search_knowledge.rb +15 -14
- data/lib/ollama_chat/version.rb +1 -1
- data/ollama_chat.gemspec +2 -2
- data/spec/ollama_chat/commands_spec.rb +20 -0
- data/spec/ollama_chat/switches_spec.rb +28 -0
- data/spec/ollama_chat/tools/execute_shell_spec.rb +1 -0
- data/spec/ollama_chat/tools/search_knowledge_spec.rb +5 -8
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a72761f0d0b34c0ba21859589410e914dda692d669a39629e4e6bb8f6e2857ea
|
|
4
|
+
data.tar.gz: 374fa95c62c5510e94c6a7624200a6193a15e9ed842a4b49b5364d43eeecac52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea024b4607101da7037f0234970cb6e655c6d2b1af46fc1eac1b8dc901aebd5ef95a091d079653bfb58e86d381c4bb56173172f9fb0861e9d8a3424667bfdd32
|
|
7
|
+
data.tar.gz: dfbbe6cddbb4aac1f047cb39719ed58e8920e22a42775cb9f18a4d3731d0c53cc7c632733241f58f6cd6c132e5979b0a3117bf38e7e0095417310e839fb7421b
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
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
|
+
|
|
3
65
|
## 2026-10-05 v0.0.126
|
|
4
66
|
|
|
5
67
|
* **Tool Registry Refactor**: Refactored the tool registry to store tool
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -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{
|
|
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{
|
|
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(
|
|
134
|
-
|
|
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|
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -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
|
-
|
|
170
|
-
|
|
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[
|
|
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,6 +427,8 @@ 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
433
|
compact_with_retry
|
|
431
434
|
when 'summarize'
|
|
@@ -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
|
|
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
|
#
|
|
@@ -66,6 +66,14 @@ module OllamaChat::RAGHandling
|
|
|
66
66
|
@documents.collection
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Sets the documents collection to collection.
|
|
70
|
+
#
|
|
71
|
+
# @param collection [String, Symbol] the name of the collection to set
|
|
72
|
+
# @return [String, Symbol] the newly set collection name
|
|
73
|
+
def set_documents_collection(collection)
|
|
74
|
+
@documents.collection = collection
|
|
75
|
+
end
|
|
76
|
+
|
|
69
77
|
# Retrieves a hash of collection names and their descriptions from the
|
|
70
78
|
# database.
|
|
71
79
|
#
|
|
@@ -264,14 +272,6 @@ module OllamaChat::RAGHandling
|
|
|
264
272
|
end
|
|
265
273
|
end
|
|
266
274
|
|
|
267
|
-
# Sets the documents collection to collection.
|
|
268
|
-
#
|
|
269
|
-
# @param collection [String, Symbol] the name of the collection to set
|
|
270
|
-
# @return [String, Symbol] the newly set collection name
|
|
271
|
-
def set_documents_collection(collection)
|
|
272
|
-
@documents.collection = collection
|
|
273
|
-
end
|
|
274
|
-
|
|
275
275
|
# The choose_collection method presents a menu to select or create a document
|
|
276
276
|
# collection. It displays existing collections along with options to create a
|
|
277
277
|
# new one or exit.
|
|
@@ -290,12 +290,12 @@ module OllamaChat::RAGHandling
|
|
|
290
290
|
case collection = collection&.to_s
|
|
291
291
|
when '[NEW]'
|
|
292
292
|
if name = create_collection
|
|
293
|
-
|
|
293
|
+
set_documents_collection(name)
|
|
294
294
|
end
|
|
295
295
|
when nil, '[EXIT]'
|
|
296
296
|
feedback("Exiting chooser.")
|
|
297
297
|
when /./
|
|
298
|
-
|
|
298
|
+
set_documents_collection(collection)
|
|
299
299
|
end
|
|
300
300
|
ensure
|
|
301
301
|
if collection
|
data/lib/ollama_chat/switches.rb
CHANGED
|
@@ -99,31 +99,70 @@ module OllamaChat::Switches
|
|
|
99
99
|
# switch.off? # Returns false
|
|
100
100
|
# switch.on? # Returns true
|
|
101
101
|
class Switch
|
|
102
|
+
UNSET = Object.new.freeze
|
|
103
|
+
|
|
102
104
|
# Initializes a new Switch instance.
|
|
103
105
|
#
|
|
104
106
|
# @param msg [Hash{Boolean => String}] a hash containing true and false messages
|
|
105
|
-
# @param value [Object] the initial state of the switch
|
|
107
|
+
# @param value [Object, Proc] the initial state of the switch. A plain
|
|
108
|
+
# value is coerced to a boolean and wrapped in an internal closure;
|
|
109
|
+
# a callable is used directly and must be invokable both bare (read)
|
|
110
|
+
# and with an explicit boolean (write). If the callable responds to
|
|
111
|
+
# `arity`, it must return -1 (a `TypeError` is raised otherwise);
|
|
112
|
+
# callables without an `arity` method are accepted as-is.
|
|
106
113
|
# @param callbacks [Hash{[Boolean, Boolean] => Proc}] optional mapping of
|
|
107
114
|
# state transitions to callback procs. Keys are `[old_value, new_value]`.
|
|
115
|
+
# @raise [TypeError] if `value` is a callable that responds to `arity`
|
|
116
|
+
# and the arity is not -1
|
|
108
117
|
def initialize(msg:, value:, callbacks: {})
|
|
109
|
-
|
|
118
|
+
if value.respond_to?(:call)
|
|
119
|
+
if arity = value.ask_and_send(:arity)
|
|
120
|
+
arity != -1 and raise TypeError, 'value Proc requires arity -1'
|
|
121
|
+
end
|
|
122
|
+
@value = value
|
|
123
|
+
else
|
|
124
|
+
@value = adhoc_closure(value)
|
|
125
|
+
end
|
|
110
126
|
@msg = msg
|
|
111
127
|
@callbacks = callbacks.to_h
|
|
112
128
|
end
|
|
113
129
|
|
|
130
|
+
# Wraps a plain (non-callable) value in a closure so that every switch
|
|
131
|
+
# state is stored and accessed uniformly via a `Proc`.
|
|
132
|
+
#
|
|
133
|
+
# The returned closure reads the coerced (`!!`) boolean state when called
|
|
134
|
+
# with no argument (or the `UNSET` sentinel) and rebinds the captured
|
|
135
|
+
# `original_value` when called with an explicit value.
|
|
136
|
+
#
|
|
137
|
+
# @param original_value [Object] the initial value to be coerced to a
|
|
138
|
+
# boolean on read
|
|
139
|
+
# @return [Proc] a closure that reads or writes the switch state
|
|
140
|
+
def adhoc_closure(original_value)
|
|
141
|
+
-> new_value = UNSET {
|
|
142
|
+
if new_value == UNSET
|
|
143
|
+
!!original_value
|
|
144
|
+
else
|
|
145
|
+
original_value = new_value
|
|
146
|
+
end
|
|
147
|
+
}
|
|
148
|
+
end
|
|
149
|
+
private :adhoc_closure
|
|
150
|
+
|
|
114
151
|
# @!attribute [r] value
|
|
115
152
|
# @return [Boolean] the current state of the switch
|
|
116
|
-
|
|
153
|
+
def value
|
|
154
|
+
@value.()
|
|
155
|
+
end
|
|
117
156
|
|
|
118
157
|
# Assigns a boolean value to the switch and optionally displays the result.
|
|
119
158
|
#
|
|
120
159
|
# @param value [Object] the value to be coerced to a boolean and assigned
|
|
121
160
|
# @param show [Boolean] determines whether to display the status message
|
|
122
161
|
# @param output [IO] the output stream to write the message to
|
|
123
|
-
# @return [String, nil, Boolean] the result of the display operation or the show flag
|
|
124
162
|
def set(value, show: false, output: STDOUT)
|
|
125
|
-
@value
|
|
163
|
+
@value.(value)
|
|
126
164
|
show && self.show(output:)
|
|
165
|
+
nil
|
|
127
166
|
end
|
|
128
167
|
|
|
129
168
|
# Toggles the current boolean value and optionally displays the result.
|
|
@@ -131,7 +170,7 @@ module OllamaChat::Switches
|
|
|
131
170
|
# @param show [Boolean] determines whether to show the value after toggling
|
|
132
171
|
# @return [String, nil, Boolean] the result of the display operation or the show flag
|
|
133
172
|
def toggle(show: true)
|
|
134
|
-
@value
|
|
173
|
+
@value.(!@value.())
|
|
135
174
|
show && self.show
|
|
136
175
|
end
|
|
137
176
|
|
|
@@ -175,10 +214,10 @@ module OllamaChat::Switches
|
|
|
175
214
|
# @param value [Object] the value to be coerced to a boolean and saved
|
|
176
215
|
# @param show [Boolean] whether to show the updated value
|
|
177
216
|
# @param output [IO] the output stream to use when showing the value
|
|
178
|
-
# @return [String, nil, Boolean] the result of the display operation or the show flag
|
|
179
217
|
def set(value, show: false, output: STDOUT)
|
|
180
218
|
@chat.session.update("#{attribute}": !!value)
|
|
181
219
|
show && self.show(output:)
|
|
220
|
+
nil
|
|
182
221
|
end
|
|
183
222
|
|
|
184
223
|
# Toggles the value of a session attribute and optionally displays the new state.
|
|
@@ -207,9 +246,18 @@ module OllamaChat::Switches
|
|
|
207
246
|
class CombinedSwitch
|
|
208
247
|
# Initializes a new CombinedSwitch instance.
|
|
209
248
|
#
|
|
210
|
-
# @param value [Proc] the proc used to determine the current state
|
|
211
|
-
#
|
|
249
|
+
# @param value [Proc] the proc used to determine the current state.
|
|
250
|
+
# Must be invokable with no arguments. If the proc responds to
|
|
251
|
+
# `arity`, it must return 0 or -1 (a `TypeError` is raised
|
|
252
|
+
# otherwise); procs without an `arity` method are accepted as-is.
|
|
253
|
+
# @param msg [Hash{Boolean => String}] the message hash containing
|
|
254
|
+
# true and false keys
|
|
255
|
+
# @raise [TypeError] if `value` responds to `arity` and returns a
|
|
256
|
+
# value greater than 0 (the proc must be invokable with no args)
|
|
212
257
|
def initialize(value:, msg:)
|
|
258
|
+
if arity = value.ask_and_send(:arity)
|
|
259
|
+
arity <= 0 or raise TypeError, 'value Proc requires arity <= 0'
|
|
260
|
+
end
|
|
213
261
|
@value = value
|
|
214
262
|
@msg = msg
|
|
215
263
|
end
|
|
@@ -279,6 +327,14 @@ module OllamaChat::Switches
|
|
|
279
327
|
# @return [OllamaChat::Switches::DatabaseSwitch] the tools support setting switch
|
|
280
328
|
attr_reader :tools_support
|
|
281
329
|
|
|
330
|
+
# Controls whether the session's memory trigger is active. The enabled
|
|
331
|
+
# state is read from and written to the session's `trigger` hash; the
|
|
332
|
+
# switch is a no-op when no trigger is configured.
|
|
333
|
+
#
|
|
334
|
+
# @!attribute [r] memory_trigger
|
|
335
|
+
# @return [OllamaChat::Switches::Switch] the memory trigger switch instance
|
|
336
|
+
attr_reader :memory_trigger
|
|
337
|
+
|
|
282
338
|
# Initializes the various switches for configuring the application's behavior.
|
|
283
339
|
#
|
|
284
340
|
# This method creates and configures the database and local switch objects
|
|
@@ -387,5 +443,19 @@ module OllamaChat::Switches
|
|
|
387
443
|
false => "Tools support disabled.",
|
|
388
444
|
}
|
|
389
445
|
)
|
|
446
|
+
@memory_trigger = Switch.new(
|
|
447
|
+
value: -> new_value = OllamaChat::Switches::Switch::UNSET {
|
|
448
|
+
if new_value == OllamaChat::Switches::Switch::UNSET
|
|
449
|
+
chat.session.trigger_enabled?
|
|
450
|
+
else
|
|
451
|
+
chat.session.set_trigger_enabled(new_value)
|
|
452
|
+
nil
|
|
453
|
+
end
|
|
454
|
+
},
|
|
455
|
+
msg: {
|
|
456
|
+
true => "Memory trigger active.",
|
|
457
|
+
false => "Memory trigger inactive.",
|
|
458
|
+
},
|
|
459
|
+
)
|
|
390
460
|
end
|
|
391
461
|
end
|
|
@@ -139,7 +139,7 @@ class OllamaChat::Tools::ExecuteShell
|
|
|
139
139
|
|
|
140
140
|
# Display command output through the pager.
|
|
141
141
|
def display(stdout, stderr, exit_code)
|
|
142
|
-
chat.use_pager do |io|
|
|
142
|
+
chat.use_pager(force: true) do |io|
|
|
143
143
|
if stdout.present?
|
|
144
144
|
io.puts bold { "stdout:" }, ""
|
|
145
145
|
io.puts stdout
|
|
@@ -123,28 +123,29 @@ class OllamaChat::Tools::SearchKnowledge
|
|
|
123
123
|
raise OllamaChat::ToolFunctionArgumentError,
|
|
124
124
|
"Collection #{collection} is disabled."
|
|
125
125
|
end
|
|
126
|
-
old_collection
|
|
127
|
-
chat.
|
|
126
|
+
old_collection = chat.collection
|
|
127
|
+
chat.set_documents_collection(collection)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
records = chat.find_document_records(query, tags:, text_size:, text_count:, min_similarity:)
|
|
131
131
|
|
|
132
|
+
pre_rerank = records.size
|
|
133
|
+
prompt_name = 'default'
|
|
132
134
|
if rerank && records.any?
|
|
133
|
-
pre_rerank = records.size
|
|
134
|
-
prompt_name = 'default'
|
|
135
135
|
records = chat.rerank_records(query, records, prompt_name:)
|
|
136
|
-
chat.log(:info, 'Tool: %d/%d passed rerank for %s' % [ records.size, pre_rerank, collection ],
|
|
137
|
-
data: { collection:, prompt_name: })
|
|
138
136
|
end
|
|
139
137
|
|
|
140
138
|
chat.log(:info, "Snippets retrieved", data: {
|
|
141
|
-
tool: name,
|
|
142
|
-
|
|
139
|
+
tool: name,
|
|
140
|
+
collection: chat.collection,
|
|
141
|
+
rerank:,
|
|
142
|
+
pre_rerank:,
|
|
143
|
+
hits: records.size
|
|
144
|
+
}.compact)
|
|
143
145
|
|
|
144
|
-
collection_name = chat.documents.collection
|
|
145
146
|
message =
|
|
146
147
|
if records.any?
|
|
147
|
-
"Retrieved #{records.size} relevant snippets from collection #{
|
|
148
|
+
"Retrieved #{records.size} relevant snippets from collection #{chat.collection.inspect} for query #{query.inspect}. See snippets below:\n\n" +
|
|
148
149
|
records.map { |record|
|
|
149
150
|
link = if record.source =~ %r(\Ahttps?://)
|
|
150
151
|
record.source
|
|
@@ -155,14 +156,14 @@ class OllamaChat::Tools::SearchKnowledge
|
|
|
155
156
|
[ link, ?# + record.tags.first ]
|
|
156
157
|
}.flat_map { |l, t| chat.hyperlink(l, t) }.join(' ')
|
|
157
158
|
else
|
|
158
|
-
"No relevant snippets found for query #{query.inspect} in collection #{
|
|
159
|
+
"No relevant snippets found for query #{query.inspect} in collection #{chat.collection.inspect}."
|
|
159
160
|
end
|
|
160
161
|
|
|
161
162
|
{
|
|
162
163
|
prompt: chat.prompt('snippets_retrieval').to_s,
|
|
163
164
|
collection: {
|
|
164
|
-
name:
|
|
165
|
-
description: chat.database_collection?(
|
|
165
|
+
name: chat.collection,
|
|
166
|
+
description: chat.database_collection?(chat.collection)&.description&.to_s,
|
|
166
167
|
},
|
|
167
168
|
snippets: records.map do |record|
|
|
168
169
|
{
|
|
@@ -183,7 +184,7 @@ class OllamaChat::Tools::SearchKnowledge
|
|
|
183
184
|
chat.log(:error, e, data: { tool: name, query: args.query })
|
|
184
185
|
{ error: e.class.name, message: e.message }.to_json
|
|
185
186
|
ensure
|
|
186
|
-
old_collection and chat.
|
|
187
|
+
old_collection and chat.set_documents_collection(old_collection)
|
|
187
188
|
end
|
|
188
189
|
|
|
189
190
|
self
|
data/lib/ollama_chat/version.rb
CHANGED
data/ollama_chat.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: ollama_chat 0.0.
|
|
2
|
+
# stub: ollama_chat 0.0.127 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "ollama_chat".freeze
|
|
6
|
-
s.version = "0.0.
|
|
6
|
+
s.version = "0.0.127".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]
|
|
@@ -111,6 +111,21 @@ describe OllamaChat::Commands, protect_env: true do
|
|
|
111
111
|
expect(chat.stream).to receive(:set).with(false, show: true)
|
|
112
112
|
expect(chat.handle_input("/toggle stream -n")).to eq :next
|
|
113
113
|
end
|
|
114
|
+
|
|
115
|
+
it 'returns :next when input is "/toggle memory_trigger"' do
|
|
116
|
+
expect(chat.memory_trigger).to receive(:toggle)
|
|
117
|
+
expect(chat.handle_input("/toggle memory_trigger")).to eq :next
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'returns :next when input is "/toggle memory_trigger -y"' do
|
|
121
|
+
expect(chat.memory_trigger).to receive(:set).with(true, show: true)
|
|
122
|
+
expect(chat.handle_input("/toggle memory_trigger -y")).to eq :next
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'returns :next when input is "/toggle memory_trigger -n"' do
|
|
126
|
+
expect(chat.memory_trigger).to receive(:set).with(false, show: true)
|
|
127
|
+
expect(chat.handle_input("/toggle memory_trigger -n")).to eq :next
|
|
128
|
+
end
|
|
114
129
|
end
|
|
115
130
|
|
|
116
131
|
describe '/voice' do
|
|
@@ -794,6 +809,11 @@ describe OllamaChat::Commands, protect_env: true do
|
|
|
794
809
|
expect(chat.handle_input("/conversation compact")).to eq :next
|
|
795
810
|
end
|
|
796
811
|
|
|
812
|
+
it 'returns :next when input is "/conversation compact summary"' do
|
|
813
|
+
expect(chat).to receive(:show_compaction_summary)
|
|
814
|
+
expect(chat.handle_input("/conversation compact summary")).to eq :next
|
|
815
|
+
end
|
|
816
|
+
|
|
797
817
|
it 'returns :next when input is "/conversation summarize"' do
|
|
798
818
|
expect(chat).to receive(:summarize_conversation)
|
|
799
819
|
.with(sentence: false)
|
|
@@ -95,6 +95,34 @@ describe OllamaChat::Switches do
|
|
|
95
95
|
}.from(true).to(false)
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
context 'callable value (non-adhoc closure)' do
|
|
100
|
+
let(:store) { { enabled: false } }
|
|
101
|
+
let :switch do
|
|
102
|
+
described_class.new(
|
|
103
|
+
value: -> nv = described_class::UNSET do
|
|
104
|
+
nv == described_class::UNSET ? store[:enabled]
|
|
105
|
+
: (store[:enabled] = nv; nil)
|
|
106
|
+
end,
|
|
107
|
+
msg: { true => 'On', false => 'Off' }
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'reads without writing' do
|
|
112
|
+
expect(switch.on?).to eq false
|
|
113
|
+
expect(store[:enabled]).to eq false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'set calls the closure with the explicit value' do
|
|
117
|
+
expect { switch.set(true) }
|
|
118
|
+
.to change { store[:enabled] }.from(false).to(true)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'toggle reads then writes the negation' do
|
|
122
|
+
expect { switch.toggle(show: false) }
|
|
123
|
+
.to change { store[:enabled] }.from(false).to(true)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
98
126
|
end
|
|
99
127
|
|
|
100
128
|
describe OllamaChat::Switches::DatabaseSwitch do
|
|
@@ -134,6 +134,7 @@ describe OllamaChat::Tools::ExecuteShell do
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
it 'skips editor and confirm in test mode' do
|
|
137
|
+
stub_success(stdout: "file1\nfile2", stderr: '')
|
|
137
138
|
expect(OllamaChat).to receive(:test_mode?).and_return(true)
|
|
138
139
|
expect(chat).not_to receive(:edit_text)
|
|
139
140
|
expect(chat).not_to receive(:confirm?)
|
|
@@ -118,17 +118,14 @@ describe OllamaChat::Tools::SearchKnowledge do
|
|
|
118
118
|
)
|
|
119
119
|
)
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
expect(chat).to receive(:collection).
|
|
122
|
+
and_return('default_collection').at_least(:once)
|
|
123
|
+
expect(chat).to receive(:set_documents_collection).with('tolkien').ordered
|
|
124
|
+
expect(chat).to receive(:set_documents_collection).
|
|
125
|
+
with('default_collection').ordered
|
|
123
126
|
expect(chat).to receive(:database_collection?)
|
|
124
127
|
.and_return(double('Col', description: 'Desc', enabled: true))
|
|
125
128
|
.at_least(:once)
|
|
126
|
-
|
|
127
|
-
expect(mock_docs).to receive(:collection).and_return('default_collection').
|
|
128
|
-
at_least(:once)
|
|
129
|
-
expect(mock_docs).to receive(:collection=).with('tolkien').ordered
|
|
130
|
-
expect(mock_docs).to receive(:collection=).with('default_collection').ordered
|
|
131
|
-
|
|
132
129
|
tool = described_class.new(chat)
|
|
133
130
|
expect(chat).to receive(:find_document_records).and_return([])
|
|
134
131
|
|