ollama_chat 0.0.130 → 0.0.132
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 +65 -0
- data/Rakefile +1 -1
- data/lib/ollama_chat/asr.rb +3 -3
- data/lib/ollama_chat/context_usage.rb +123 -0
- data/lib/ollama_chat/dialog.rb +1 -1
- data/lib/ollama_chat/feedback.rb +4 -1
- data/lib/ollama_chat/information.rb +21 -58
- data/lib/ollama_chat/message_list.rb +2 -2
- data/lib/ollama_chat/rag_handling.rb +64 -18
- data/lib/ollama_chat/session_management.rb +1 -1
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat.rb +1 -0
- data/ollama_chat.gemspec +6 -6
- data/spec/ollama_chat/asr_spec.rb +1 -4
- data/spec/ollama_chat/commands_spec.rb +6 -6
- data/spec/ollama_chat/context_usage_spec.rb +65 -0
- data/spec/ollama_chat/conversation_spec.rb +2 -2
- data/spec/ollama_chat/message_list_spec.rb +11 -8
- data/spec/ollama_chat/model_handling_spec.rb +2 -2
- data/spec/ollama_chat/parsing_spec.rb +5 -5
- data/spec/ollama_chat/prompt_handling_spec.rb +2 -2
- data/spec/ollama_chat/prompt_management_spec.rb +1 -1
- data/spec/ollama_chat/rag_handling_spec.rb +56 -16
- data/spec/ollama_chat/session_management_spec.rb +2 -2
- data/spec/ollama_chat/source_fetching_spec.rb +2 -2
- data/spec/ollama_chat/tools/delete_file_spec.rb +5 -5
- data/spec/ollama_chat/tools/list_directory_spec.rb +1 -1
- data/spec/ollama_chat/tools/move_file_spec.rb +10 -10
- data/spec/ollama_chat/tools/patch_file_spec.rb +2 -2
- data/spec/ollama_chat/tools/resolve_tag_spec.rb +3 -4
- data/spec/ollama_chat/tools/write_file_spec.rb +2 -2
- data/spec/spec_helper.rb +23 -0
- metadata +7 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 57100c5a17ee0794ecbbb0e468caf3c5ec176d83c89afc80a0cfb8a494a01914
|
|
4
|
+
data.tar.gz: 9233a943fb0ad3f7d319e4b2312d63ec5f0b00959d9800dc651f0b039c8a8f59
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c29e1b8ba010a29f6f6a7d502cbe9b6cae7e101aba823f104b71e32575e5dccc5cb998dd385b7b6d16872b6ca3bd0935de04d6357576d8d27877d475e814723
|
|
7
|
+
data.tar.gz: 50a98b4ad252faf970fd68774d9d234224d6ff3e4539ab69ab52a6939095ea1d413ceeb2031d8cee767b40a00c383be86e47226e1f2e4a0fe744d04fbfe5a3f9
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-10-12 v0.0.132
|
|
4
|
+
|
|
5
|
+
* `collection` now returns `@documents.collection.to_s`, making the return
|
|
6
|
+
type strictly `[String]`
|
|
7
|
+
* `clear_whole_collection` replaces the y/n `confirm?` with an `ask?` prompt
|
|
8
|
+
that requires typing the full collection name before clearing
|
|
9
|
+
* Log message includes `target.inspect` for greppability
|
|
10
|
+
* `commands_spec.rb`: `:default` → `'default'` in `rename_collection` and
|
|
11
|
+
`update_collection` expectations
|
|
12
|
+
* `rag_handling_spec.rb`: both `clear_whole_collection` specs rewritten to
|
|
13
|
+
stub `ask?` + `switch_history` instead of the removed `confirm?`
|
|
14
|
+
* Updated the `tins` runtime dependency constraint from `~> 1.60`, `>=
|
|
15
|
+
1.60.1` to `~> 1.61` in `Rakefile` and `ollama_chat.gemspec`
|
|
16
|
+
* `feedback` gains a `timeout:` kwarg; when set, calls `chat.confirm?` with a
|
|
17
|
+
"press any key to continue (timeout in Xs)" prompt so the message doesn't
|
|
18
|
+
flash by
|
|
19
|
+
* `clear_tag_records` and `clear_collection_sources` in `rag_handling.rb`
|
|
20
|
+
pass `timeout: 3`
|
|
21
|
+
* `dialog.rb` adds `IOError` to the `STDIN.raw` exception rescue list
|
|
22
|
+
* `rag_handling_spec.rb` updated with `timeout: 3` in four `feedback`
|
|
23
|
+
expectations
|
|
24
|
+
|
|
25
|
+
## 2026-10-10 v0.0.131
|
|
26
|
+
|
|
27
|
+
* Extracted ANSI, emoji, and formatting logic from `Information` into a new
|
|
28
|
+
`OllamaChat::ContextUsage` class, providing a `colored`, `plain`, `filled`,
|
|
29
|
+
and `percent` API.
|
|
30
|
+
* Converted `context_usage_colored`, `context_filled`, and
|
|
31
|
+
`context_usage_plain` into one-line delegators on `Information`.
|
|
32
|
+
* Removed `context_percentage` and `context_gauge` methods, absorbing their
|
|
33
|
+
logic into `ContextUsage` private helpers.
|
|
34
|
+
* Updated `MessageList#compact!` to capture `context_usage_colored` for both
|
|
35
|
+
before and after states, ensuring the compaction report renders
|
|
36
|
+
threshold-colored values.
|
|
37
|
+
* Changed the plain format to be percent-first: `27.9% · 73.1 KT of 262.1 KT`.
|
|
38
|
+
* Updated `session_management.rb` log data to use `context_usage_plain`.
|
|
39
|
+
* Added `spec/ollama_chat/context_usage_spec.rb` to pin green/yellow/red
|
|
40
|
+
thresholds, plain format, nil-context fallback, and fill ratio.
|
|
41
|
+
* Added per-letter emojis to clear menu prompts in `rag_handling.rb` (🔍 view,
|
|
42
|
+
🧹 clear, 🔙 other) to improve scannability of single-keypress `confirm?`
|
|
43
|
+
letter menus.
|
|
44
|
+
* Updated `asr.rb` to use `%w[]` for `Tempfile.new` prefix/suffix arguments and
|
|
45
|
+
replaced `File.size(wav.path)` with `wav.size`.
|
|
46
|
+
* Updated `asr_spec.rb` to stub the `Tempfile#size` instance method instead of
|
|
47
|
+
the `File.size` class method.
|
|
48
|
+
* Migrated spec temporary paths to the `asset_tmp_path` helper across 15 spec
|
|
49
|
+
files, replacing hardcoded `tmp/` paths, `Dir.tmpdir` + `$$` PID suffixes,
|
|
50
|
+
hand-rolled `Tins::Token.new(bits: 128)` strings, and `Time.now.to_i` epoch
|
|
51
|
+
hacks.
|
|
52
|
+
* Converted `File.write(pathname, ...)` calls to `pathname.write(...)` in
|
|
53
|
+
`delete_file_spec`, `parsing_spec`, `resolve_tag_spec`, and
|
|
54
|
+
`prompt_handling_spec`.
|
|
55
|
+
* Updated `prompt_handling_spec` to use `asset_pathname('prompt_file.txt')` for
|
|
56
|
+
the `Pathname#write` idiom.
|
|
57
|
+
* Removed `.txt` suffix from `include` assertions in `move_file_spec` as
|
|
58
|
+
tokenized basenames no longer match the original extension.
|
|
59
|
+
* Added a collection chooser to `memory_restore`, allowing users to select
|
|
60
|
+
which collections from a dump file to restore, with `[ALL]` / `[DONE]`
|
|
61
|
+
support.
|
|
62
|
+
* Updated `memory_dump` to use `Set#sort` directly instead of `Set#to_a.sort`.
|
|
63
|
+
* Added a new `asset_tmp_path` helper in `spec_helper.rb` that generates
|
|
64
|
+
collision-free temp paths via `Tins::Token` (128-bit).
|
|
65
|
+
* Updated restore specs to include chooser stubs, cancel and selective-restore
|
|
66
|
+
cases, and switched temp files to `asset_tmp_path`.
|
|
67
|
+
|
|
3
68
|
## 2026-10-08 v0.0.130
|
|
4
69
|
|
|
5
70
|
* Replace `ask?` with `confirm?` in `rag_handling.rb` for the `[v]iew` /
|
data/Rakefile
CHANGED
|
@@ -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.61'
|
|
53
53
|
dependency 'search_ui', '>= 0.2'
|
|
54
54
|
dependency 'amatch', '~> 0.4'
|
|
55
55
|
dependency 'pdf-reader', '~> 2.0'
|
data/lib/ollama_chat/asr.rb
CHANGED
|
@@ -26,8 +26,8 @@ module OllamaChat
|
|
|
26
26
|
def transcribe(source_io, chat:, language: nil)
|
|
27
27
|
asr_url = OC::OLLAMA::CHAT::ASR::URL
|
|
28
28
|
asr_model = OC::OLLAMA::CHAT::ASR::MODEL
|
|
29
|
-
input = Tempfile.new([
|
|
30
|
-
wav = Tempfile.new([
|
|
29
|
+
input = Tempfile.new(%w[ asr_in ])
|
|
30
|
+
wav = Tempfile.new(%w[ asr .wav ])
|
|
31
31
|
begin
|
|
32
32
|
IO.copy_stream(source_io, input)
|
|
33
33
|
input.flush
|
|
@@ -41,7 +41,7 @@ module OllamaChat
|
|
|
41
41
|
chat.feedback("ASR: #{executable} not found in PATH.", type: :warn)
|
|
42
42
|
return
|
|
43
43
|
end
|
|
44
|
-
unless
|
|
44
|
+
unless wav.size > 0
|
|
45
45
|
chat.feedback("ASR: #{executable} produced no output.", type: :warn)
|
|
46
46
|
return
|
|
47
47
|
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'term/ansicolor'
|
|
2
|
+
require 'ollama_chat/utils/value_formatter'
|
|
3
|
+
|
|
4
|
+
module OllamaChat
|
|
5
|
+
# Renders the current context-window usage as colored or plain strings.
|
|
6
|
+
#
|
|
7
|
+
# Wraps an {OllamaChat::Chat} instance and concentrates the ANSI coloring,
|
|
8
|
+
# emoji, and token-formatting logic that was previously inlined in
|
|
9
|
+
# {OllamaChat::Information}. The color reflects how full the context is
|
|
10
|
+
# relative to the compaction `keep_recent` / `reserve` budgets:
|
|
11
|
+
#
|
|
12
|
+
# 🟢 green — below `keep_recent` (plenty of room)
|
|
13
|
+
# 🟡 yellow — between `keep_recent` and `reserve` (getting tight)
|
|
14
|
+
# 🔴 red — above `reserve` (compaction imminent)
|
|
15
|
+
class ContextUsage
|
|
16
|
+
include Term::ANSIColor
|
|
17
|
+
include OllamaChat::Utils::ValueFormatter
|
|
18
|
+
|
|
19
|
+
EMOJI = { green: '🟢', yellow: '🟡', red: '🔴' }.freeze
|
|
20
|
+
|
|
21
|
+
# @param chat [OllamaChat::Chat] the chat instance to read state from
|
|
22
|
+
def initialize(chat)
|
|
23
|
+
@chat = chat
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Colored usage string, e.g. `🟢 73.1 KT of 262.1 KT (27.9%)`.
|
|
27
|
+
#
|
|
28
|
+
# Every value (used tokens, context limit, percentage) is painted with the
|
|
29
|
+
# threshold color; the surrounding text is bold. Returns a bold `n/a` when
|
|
30
|
+
# the context length cannot be determined.
|
|
31
|
+
#
|
|
32
|
+
# @return [String] the ANSI-colored usage string
|
|
33
|
+
def colored
|
|
34
|
+
ctx = @chat.current_context_length
|
|
35
|
+
return bold { 'n/a' } unless ctx
|
|
36
|
+
|
|
37
|
+
es = estimate
|
|
38
|
+
color = color_for(es.tokens, ctx)
|
|
39
|
+
percent = percent_for(es.tokens, ctx)
|
|
40
|
+
|
|
41
|
+
[
|
|
42
|
+
EMOJI[color], ' ',
|
|
43
|
+
bold { paint(color, percent) },
|
|
44
|
+
' · ',
|
|
45
|
+
paint(color, es.tokens_formatted),
|
|
46
|
+
' of ',
|
|
47
|
+
paint(color, format_tokens(ctx)),
|
|
48
|
+
] * ''
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Plain (uncolored) usage string, e.g. `73.1 KT of 262.1 KT (27.9%)`.
|
|
52
|
+
#
|
|
53
|
+
# @return [String, nil] the usage string, or nil when the context length
|
|
54
|
+
# is unknown.
|
|
55
|
+
def plain
|
|
56
|
+
ctx = @chat.current_context_length
|
|
57
|
+
return nil unless ctx
|
|
58
|
+
|
|
59
|
+
es = estimate
|
|
60
|
+
'%s · %s of %s' % [
|
|
61
|
+
percent_for(es.tokens, ctx),
|
|
62
|
+
es.tokens_formatted,
|
|
63
|
+
format_tokens(ctx),
|
|
64
|
+
]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Fraction of the context window currently in use, clamped to 0.0–1.0.
|
|
68
|
+
#
|
|
69
|
+
# @return [Float] the fill ratio (e.g. `0.279`)
|
|
70
|
+
def filled
|
|
71
|
+
es = estimate
|
|
72
|
+
(es.tokens.to_f / @chat.current_context_length).clamp(0..1).to_f
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Formatted percentage string, e.g. `27.9%`.
|
|
76
|
+
#
|
|
77
|
+
# @return [String] the percentage
|
|
78
|
+
def percent
|
|
79
|
+
format('%.1f%%', 100 * filled)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# @return [OllamaChat::TokenEstimator::Estimate] the compacted estimate
|
|
85
|
+
def estimate
|
|
86
|
+
@chat.messages.compacted_estimate_tokens
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @param tokens [Integer] used tokens
|
|
90
|
+
# @param ctx [Integer] context length
|
|
91
|
+
# @return [String] the formatted percentage
|
|
92
|
+
def percent_for(tokens, ctx)
|
|
93
|
+
format('%.1f%%', 100 * (tokens.to_f / ctx).clamp(0..1))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Resolves the threshold color for a given fill level.
|
|
97
|
+
#
|
|
98
|
+
# @param tokens [Integer] used tokens
|
|
99
|
+
# @param ctx [Integer] context length
|
|
100
|
+
# @return [Symbol] one of :green, :yellow, :red
|
|
101
|
+
def color_for(tokens, ctx)
|
|
102
|
+
keep_recent = @chat.compact_ratio_tokens(:keep_recent, ctx)
|
|
103
|
+
reserve = @chat.compact_ratio_tokens(:reserve, ctx)
|
|
104
|
+
if tokens < keep_recent then :green
|
|
105
|
+
elsif tokens <= reserve then :yellow
|
|
106
|
+
else :red
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Paints a string with the given threshold color.
|
|
111
|
+
#
|
|
112
|
+
# @param color [Symbol] one of :green, :yellow, :red
|
|
113
|
+
# @param string [String] the text to colorize
|
|
114
|
+
# @return [String] the ANSI-colored string
|
|
115
|
+
def paint(color, string)
|
|
116
|
+
case color
|
|
117
|
+
when :green then green { string }
|
|
118
|
+
when :yellow then yellow { string }
|
|
119
|
+
else red { string }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
data/lib/ollama_chat/dialog.rb
CHANGED
|
@@ -73,7 +73,7 @@ module OllamaChat::Dialog
|
|
|
73
73
|
min = 0
|
|
74
74
|
time = timeout
|
|
75
75
|
end
|
|
76
|
-
exceptions = [ (IRB::Abort if defined? IRB), Interrupt ].compact
|
|
76
|
+
exceptions = [ (IRB::Abort if defined? IRB), Interrupt, IOError ].compact
|
|
77
77
|
begin
|
|
78
78
|
keypress = STDIN.raw(min:, time:, intr: true) do |io|
|
|
79
79
|
io.getc
|
data/lib/ollama_chat/feedback.rb
CHANGED
|
@@ -33,9 +33,12 @@ module OllamaChat::Feedback
|
|
|
33
33
|
# message ends with exactly one newline before writing.
|
|
34
34
|
# Set to false for mid-line or no-trailing-newline output.
|
|
35
35
|
# @return [nil]
|
|
36
|
-
def feedback(msg, type: nil, output: STDOUT, newline: true)
|
|
36
|
+
def feedback(msg, type: nil, output: STDOUT, newline: true, timeout: nil)
|
|
37
37
|
prefix = PREFIXES[type&.to_sym]&.+(' ')
|
|
38
38
|
newline and msg = msg.sub(/(?<!\n)\z/, ?\n)
|
|
39
39
|
output.print(prefix.to_s + msg)
|
|
40
|
+
timeout.nil? and return
|
|
41
|
+
chat.confirm?(prompt: '⏎ Press any key to continue (%s). ', timeout:)
|
|
42
|
+
nil
|
|
40
43
|
end
|
|
41
44
|
end
|
|
@@ -124,18 +124,15 @@ module OllamaChat::Information
|
|
|
124
124
|
end
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
# The context_usage_colored method
|
|
128
|
-
# context window's token usage
|
|
129
|
-
#
|
|
130
|
-
# the percentage of the context that is currently filled.
|
|
127
|
+
# The context_usage_colored method returns a summary string of the current
|
|
128
|
+
# context window's token usage, with the used, maximum, and percentage
|
|
129
|
+
# values all ANSI-colored according to the compaction thresholds.
|
|
131
130
|
#
|
|
132
|
-
#
|
|
131
|
+
# Delegates the presentation (emoji + color) to {ContextUsage}.
|
|
132
|
+
#
|
|
133
|
+
# @return [ String ] the formatted, colored string representing context usage
|
|
133
134
|
def context_usage_colored
|
|
134
|
-
|
|
135
|
-
messages.compacted_estimate_tokens.tokens_formatted,
|
|
136
|
-
format_tokens(current_context_length),
|
|
137
|
-
context_gauge(context_percentage),
|
|
138
|
-
]
|
|
135
|
+
context_usage.colored
|
|
139
136
|
end
|
|
140
137
|
|
|
141
138
|
# Displays a detailed view of the current chat session state, including the
|
|
@@ -397,7 +394,7 @@ module OllamaChat::Information
|
|
|
397
394
|
tools_support: tools_support.on? ? 'enabled' : 'disabled',
|
|
398
395
|
voice: voice.on? ? 'enabled' : 'disabled',
|
|
399
396
|
weekday: now.strftime('%A'),
|
|
400
|
-
context_usage: ,
|
|
397
|
+
context_usage: context_usage_plain,
|
|
401
398
|
conversation_length: ,
|
|
402
399
|
}
|
|
403
400
|
end
|
|
@@ -455,66 +452,32 @@ module OllamaChat::Information
|
|
|
455
452
|
|
|
456
453
|
# Computes the fraction of the context window currently in use.
|
|
457
454
|
#
|
|
458
|
-
#
|
|
459
|
-
# effective context length, clamped to the range 0.0–1.0.
|
|
455
|
+
# Delegates to {ContextUsage#filled}; clamped to 0.0–1.0.
|
|
460
456
|
#
|
|
461
457
|
# @return [Float] the ratio of used context (e.g. `0.73` for 73%)
|
|
462
458
|
def context_filled
|
|
463
|
-
|
|
464
|
-
(es.tokens.to_f / current_context_length).clamp(0..1).to_f
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
# Formats the current context fill ratio as a percentage string.
|
|
468
|
-
#
|
|
469
|
-
# @return [String] the formatted percentage (e.g. `"64.0%"`)
|
|
470
|
-
def context_percentage
|
|
471
|
-
format('%.1f%%', 100 * context_filled)
|
|
459
|
+
context_usage.filled
|
|
472
460
|
end
|
|
473
461
|
|
|
474
462
|
# Formats the current context usage as a human-readable string.
|
|
475
463
|
#
|
|
476
464
|
# Returns a string like `"167.7 KT of 262.1 KT (64.0%)"` combining
|
|
477
465
|
# the estimated tokens in use, the effective context length, and
|
|
478
|
-
# the percentage
|
|
466
|
+
# the percentage. Delegates to {ContextUsage#plain}.
|
|
479
467
|
#
|
|
480
468
|
# @return [String, nil] the formatted usage string, or +nil+ if
|
|
481
469
|
# the context length cannot be determined.
|
|
482
|
-
def
|
|
483
|
-
|
|
484
|
-
'%s of %s (%s)' % [
|
|
485
|
-
messages.compacted_estimate_tokens.tokens_formatted,
|
|
486
|
-
format_tokens(current_context_length),
|
|
487
|
-
context_percentage,
|
|
488
|
-
]
|
|
489
|
-
end
|
|
470
|
+
def context_usage_plain
|
|
471
|
+
context_usage.plain
|
|
490
472
|
end
|
|
491
473
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
#
|
|
495
|
-
#
|
|
496
|
-
#
|
|
497
|
-
#
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
#
|
|
501
|
-
# @param percent_string [String] the formatted percentage to colorize
|
|
502
|
-
# @return [String] the ANSI-colored percentage string
|
|
503
|
-
def context_gauge(percent_string)
|
|
504
|
-
tokens = messages.compacted_estimate_tokens.tokens
|
|
505
|
-
ctx = current_context_length
|
|
506
|
-
return bold { percent_string } unless ctx
|
|
507
|
-
|
|
508
|
-
keep_recent = compact_ratio_tokens(:keep_recent, ctx)
|
|
509
|
-
reserve = compact_ratio_tokens(:reserve, ctx)
|
|
510
|
-
bold do
|
|
511
|
-
if tokens < keep_recent
|
|
512
|
-
'🟢 ' + green { percent_string }
|
|
513
|
-
elsif tokens <= reserve
|
|
514
|
-
'🟡 ' + yellow { percent_string }
|
|
515
|
-
else
|
|
516
|
-
'🔴 ' + red { percent_string }
|
|
517
|
-
end
|
|
518
|
-
end
|
|
474
|
+
private
|
|
475
|
+
|
|
476
|
+
# Lazily builds and caches the {ContextUsage} bound to this chat,
|
|
477
|
+
# which owns the ANSI/emoji presentation logic for context usage.
|
|
478
|
+
#
|
|
479
|
+
# @return [ContextUsage]
|
|
480
|
+
def context_usage
|
|
481
|
+
@context_usage ||= OllamaChat::ContextUsage.new(self)
|
|
519
482
|
end
|
|
520
483
|
end
|
|
@@ -164,7 +164,7 @@ class OllamaChat::MessageList
|
|
|
164
164
|
cand_es = OllamaChat::TokenEstimator::Crude.new(
|
|
165
165
|
candidates.sum { |m| m.content.to_s.bytesize }
|
|
166
166
|
).perform
|
|
167
|
-
context_before = @chat.
|
|
167
|
+
context_before = @chat.context_usage_colored
|
|
168
168
|
context_filled_before = @chat.context_filled
|
|
169
169
|
|
|
170
170
|
@chat.log(:info, 'Compaction: starting', data: {
|
|
@@ -211,7 +211,7 @@ class OllamaChat::MessageList
|
|
|
211
211
|
|
|
212
212
|
OllamaChat::Compaction::Result.new(
|
|
213
213
|
context_before:,
|
|
214
|
-
context_after: @chat.
|
|
214
|
+
context_after: @chat.context_usage_colored,
|
|
215
215
|
context_filled_before: ,
|
|
216
216
|
context_filled_after: @chat.context_filled,
|
|
217
217
|
candidates: candidates.size,
|
|
@@ -63,9 +63,9 @@ module OllamaChat::RAGHandling
|
|
|
63
63
|
|
|
64
64
|
# Returns the name of the currently active document collection.
|
|
65
65
|
#
|
|
66
|
-
# @return [String
|
|
66
|
+
# @return [String] the name of the current collection
|
|
67
67
|
def collection
|
|
68
|
-
@documents.collection
|
|
68
|
+
@documents.collection.to_s
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
# Sets the documents collection to collection.
|
|
@@ -137,10 +137,10 @@ module OllamaChat::RAGHandling
|
|
|
137
137
|
filename = Pathname.new(filename).expand_path
|
|
138
138
|
should_overwrite?(filename) or return
|
|
139
139
|
|
|
140
|
-
feedback("Dumping #{selected.size} collection(s): #{selected.
|
|
140
|
+
feedback("Dumping #{selected.size} collection(s): #{selected.sort.join(', ')}")
|
|
141
141
|
|
|
142
142
|
records = []
|
|
143
|
-
selected.
|
|
143
|
+
selected.sort.each do |col|
|
|
144
144
|
switch_collection(col) do
|
|
145
145
|
@documents.each_record do |r|
|
|
146
146
|
records << {
|
|
@@ -155,7 +155,7 @@ module OllamaChat::RAGHandling
|
|
|
155
155
|
|
|
156
156
|
OllamaChat::Utils::JSONJSONLIO.new(filename).write(collection: records)
|
|
157
157
|
log(:info, 'Memory dumped',
|
|
158
|
-
data: { collections: selected.
|
|
158
|
+
data: { collections: selected.sort, records: records.size, file: filename.to_s })
|
|
159
159
|
feedback(
|
|
160
160
|
"Dumped #{records.size} record(s) across #{selected.size} collection(s) to #{filename.to_s.inspect}.",
|
|
161
161
|
type: :success
|
|
@@ -164,8 +164,10 @@ module OllamaChat::RAGHandling
|
|
|
164
164
|
|
|
165
165
|
# Restores `memory-<persona>` collections from a JSONL dump file.
|
|
166
166
|
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
167
|
+
# Presents an accumulating chooser of all collections found in the file:
|
|
168
|
+
# pick individual collections (they drop out of the list once selected),
|
|
169
|
+
# `[ALL]` to grab everything remaining, or `[DONE]` to commit the restore.
|
|
170
|
+
# Records are added with their original tag and source so timestamps
|
|
169
171
|
# and file associations survive.
|
|
170
172
|
#
|
|
171
173
|
# @param filename [String, nil] the input path (must end in .json/.jsonl);
|
|
@@ -184,19 +186,55 @@ module OllamaChat::RAGHandling
|
|
|
184
186
|
entries = OllamaChat::Utils::JSONJSONLIO.new(filename).read.to_a
|
|
185
187
|
return feedback("No records found in #{filename.to_s.inspect}.", type: :warn) if entries.empty?
|
|
186
188
|
|
|
189
|
+
collections = entries.group_by { |e| e['collection'] }.reject { _1.nil? }
|
|
190
|
+
return feedback('No collection field found in entries.', type: :warn) if collections.empty?
|
|
191
|
+
|
|
192
|
+
selected = Set.new
|
|
193
|
+
choose_with_state do
|
|
194
|
+
loop do
|
|
195
|
+
remaining = collections.keys - selected.to_a
|
|
196
|
+
choices = (remaining.empty? ? [] : ['[ALL]'] + remaining) + ['[DONE]']
|
|
197
|
+
choice = choose_entry(choices, prompt: 'Which memory collections to restore? %s')
|
|
198
|
+
case choice
|
|
199
|
+
when nil, '[DONE]'
|
|
200
|
+
break
|
|
201
|
+
when '[ALL]'
|
|
202
|
+
selected.merge(remaining)
|
|
203
|
+
break
|
|
204
|
+
else
|
|
205
|
+
selected.add(choice)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
return feedback('Cancelled, no collections selected.', type: :cancel) if selected.empty?
|
|
211
|
+
|
|
212
|
+
selected = selected.sort
|
|
213
|
+
|
|
214
|
+
feedback("Restoring #{selected.size} collection(s): #{selected.join(', ')}")
|
|
215
|
+
|
|
187
216
|
total = 0
|
|
188
|
-
|
|
217
|
+
collections.slice(*selected).sort.each do |col, group|
|
|
189
218
|
create_memory_collection(col)
|
|
190
219
|
switch_collection(col) do
|
|
191
220
|
group.each do |entry|
|
|
192
|
-
@documents.add(
|
|
221
|
+
@documents.add(
|
|
222
|
+
[entry['text']],
|
|
223
|
+
tags: Array(entry['tags']),
|
|
224
|
+
batch_size: 1,
|
|
225
|
+
source: entry['source']
|
|
226
|
+
)
|
|
193
227
|
total += 1
|
|
194
228
|
end
|
|
195
229
|
end
|
|
196
230
|
end
|
|
197
231
|
|
|
198
|
-
log(:info, 'Memory restored',
|
|
199
|
-
|
|
232
|
+
log(:info, 'Memory restored',
|
|
233
|
+
data: { file: filename.to_s, collections: selected, records: total })
|
|
234
|
+
feedback(
|
|
235
|
+
"Restored #{total} record(s) across #{selected.size} collection(s) from #{filename.to_s.inspect}.",
|
|
236
|
+
type: :success
|
|
237
|
+
)
|
|
200
238
|
end
|
|
201
239
|
|
|
202
240
|
private
|
|
@@ -208,9 +246,15 @@ module OllamaChat::RAGHandling
|
|
|
208
246
|
# @return [ nil, OllamaChat::Chat ] when the user declines the confirmation
|
|
209
247
|
# prompt, self otherwise.
|
|
210
248
|
def clear_whole_collection
|
|
211
|
-
|
|
249
|
+
target = collection
|
|
250
|
+
prompt = "🔥 This will incinerate every record in #{target.inspect}. " \
|
|
251
|
+
"Type the name to confirm (C-c ⇒ cancel): "
|
|
252
|
+
typed = switch_history(:collection_name) do
|
|
253
|
+
ask?(prompt:, prefill: target).full?(:strip)
|
|
254
|
+
end
|
|
255
|
+
if typed == target
|
|
212
256
|
@documents.clear
|
|
213
|
-
log(:info, "Collection cleared", data: { collection: })
|
|
257
|
+
log(:info, "Collection #{target.inspect} cleared", data: { collection: })
|
|
214
258
|
feedback("Cleared collection #{bold{collection}}.", type: :info)
|
|
215
259
|
self
|
|
216
260
|
else
|
|
@@ -248,7 +292,7 @@ module OllamaChat::RAGHandling
|
|
|
248
292
|
label = source ? "#{source} #{snippet}" : snippet
|
|
249
293
|
feedback(label, type: :info)
|
|
250
294
|
view_tag_records(tag, [record])
|
|
251
|
-
confirm?(prompt: " [c]lear / other to go back: ") =~ /\Ac/i or next
|
|
295
|
+
confirm?(prompt: " 🧹[c]lear / 🔙other to go back: ") =~ /\Ac/i or next
|
|
252
296
|
clear_tag_records(tag, source)
|
|
253
297
|
else
|
|
254
298
|
group_lines = []
|
|
@@ -270,7 +314,7 @@ module OllamaChat::RAGHandling
|
|
|
270
314
|
)
|
|
271
315
|
next if chosen.nil? || chosen == '[back]'
|
|
272
316
|
src, recs = group_map[chosen]
|
|
273
|
-
action = confirm?(prompt: " [v]iew / [c]lear / other to go back: ")
|
|
317
|
+
action = confirm?(prompt: " 🔍[v]iew / 🧹[c]lear / 🔙other to go back: ")
|
|
274
318
|
case action
|
|
275
319
|
when /\Av/i
|
|
276
320
|
view_tag_records(tag, recs)
|
|
@@ -312,7 +356,8 @@ module OllamaChat::RAGHandling
|
|
|
312
356
|
data: { collection:, tag:, source: })
|
|
313
357
|
feedback(
|
|
314
358
|
"Cleared tag #{tag} from collection #{bold{collection}}.",
|
|
315
|
-
type:
|
|
359
|
+
type: :info,
|
|
360
|
+
timeout: 3,
|
|
316
361
|
)
|
|
317
362
|
end
|
|
318
363
|
|
|
@@ -350,7 +395,7 @@ module OllamaChat::RAGHandling
|
|
|
350
395
|
break
|
|
351
396
|
else
|
|
352
397
|
source = display_map[chosen]
|
|
353
|
-
action = confirm?(prompt: " [v]iew / [c]lear / other to go back: ")
|
|
398
|
+
action = confirm?(prompt: " 🔍[v]iew / 🧹[c]lear / 🔙other to go back: ")
|
|
354
399
|
case action
|
|
355
400
|
when /\Av/i
|
|
356
401
|
records = @documents.records(sources: [ source ])
|
|
@@ -373,7 +418,8 @@ module OllamaChat::RAGHandling
|
|
|
373
418
|
data: { collection:, source: })
|
|
374
419
|
feedback(
|
|
375
420
|
"Removed source #{source} from collection #{bold{collection}}.",
|
|
376
|
-
type:
|
|
421
|
+
type: :info,
|
|
422
|
+
timeout: 3,
|
|
377
423
|
)
|
|
378
424
|
end
|
|
379
425
|
end
|
data/lib/ollama_chat/version.rb
CHANGED
data/lib/ollama_chat.rb
CHANGED
|
@@ -128,6 +128,7 @@ require 'ollama_chat/source_fetching'
|
|
|
128
128
|
require 'ollama_chat/web_searching'
|
|
129
129
|
require 'ollama_chat/dialog'
|
|
130
130
|
require 'ollama_chat/think_control'
|
|
131
|
+
require 'ollama_chat/context_usage'
|
|
131
132
|
require 'ollama_chat/information'
|
|
132
133
|
require 'ollama_chat/message_output'
|
|
133
134
|
require 'ollama_chat/clipboard'
|