ollama_chat 0.0.107 → 0.0.109
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 +118 -0
- data/Rakefile +1 -1
- data/lib/ollama_chat/chat.rb +7 -4
- data/lib/ollama_chat/clipboard.rb +11 -0
- data/lib/ollama_chat/commands.rb +32 -11
- data/lib/ollama_chat/database/migrations/008_drop_think_mode_constraint.rb +130 -0
- data/lib/ollama_chat/dialog.rb +24 -17
- data/lib/ollama_chat/file_editing.rb +15 -13
- data/lib/ollama_chat/follow_chat.rb +34 -15
- data/lib/ollama_chat/kramdown_ansi.rb +1 -1
- data/lib/ollama_chat/model_handling.rb +119 -1
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +11 -5
- data/lib/ollama_chat/personae_management.rb +22 -18
- data/lib/ollama_chat/prompt_handling.rb +9 -9
- data/lib/ollama_chat/prompt_management.rb +7 -5
- data/lib/ollama_chat/rag_handling.rb +27 -23
- data/lib/ollama_chat/session_management.rb +21 -5
- data/lib/ollama_chat/think_control.rb +4 -1
- data/lib/ollama_chat/tools/patch_file.rb +5 -1
- data/lib/ollama_chat/tools/search_knowledge.rb +3 -0
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat/web_searching.rb +6 -4
- data/lib/ollama_chat.rb +9 -0
- data/ollama_chat.gemspec +5 -5
- data/spec/ollama_chat/chat_spec.rb +24 -0
- data/spec/ollama_chat/commands_spec.rb +24 -0
- data/spec/ollama_chat/config_handling_spec.rb +150 -0
- data/spec/ollama_chat/conversation_spec.rb +107 -0
- data/spec/ollama_chat/favourites_management_spec.rb +143 -0
- data/spec/ollama_chat/follow_chat_spec.rb +1 -2
- data/spec/ollama_chat/information_spec.rb +36 -2
- data/spec/ollama_chat/model_handling_spec.rb +139 -0
- data/spec/ollama_chat/prompt_handling_spec.rb +183 -0
- data/spec/ollama_chat/prompt_management_spec.rb +464 -0
- data/spec/ollama_chat/rag_handling_spec.rb +498 -0
- data/spec/ollama_chat/session_management_spec.rb +5 -5
- data/spec/ollama_chat/system_prompt_management_spec.rb +200 -0
- data/spec/ollama_chat/think_control_spec.rb +2 -2
- data/spec/ollama_chat/tools/execute_ri_spec.rb +2 -2
- data/spec/ollama_chat/tools/generate_image_spec.rb +6 -6
- data/spec/ollama_chat/tools/get_url_spec.rb +3 -3
- data/spec/ollama_chat/tools/move_file_spec.rb +1 -1
- data/spec/ollama_chat/tools/patch_file_spec.rb +3 -3
- data/spec/ollama_chat/tools/run_tests_spec.rb +3 -3
- data/spec/ollama_chat/tools/search_knowledge_spec.rb +28 -5
- data/spec/ollama_chat/utils/path_completer_spec.rb +1 -1
- data/spec/ollama_chat/utils/png_metadata_extractor_spec.rb +3 -3
- data/spec/ollama_chat/web_searching_spec.rb +99 -21
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e6c85b95f4c5051b6b0f257dd8f63ee2a3997146c527fd8af251458fee641039
|
|
4
|
+
data.tar.gz: 45a66e25a1a92d8cbd86253a991ad28eeb48d1a8ca68c1f8bbb8df90bbbba37f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a401173a7deb626af01ad8c9adf358259a6ffd7ea292644bb1a5a4553df2f70e9c74bb4ff0807d04914a7aa47e8140e81e0bd46745e33900962d8559950ea914
|
|
7
|
+
data.tar.gz: 6b04fcce611684e73bbe54cdadb01859fc4219f57960604a64c3037b414e56a02c7389a5bfef2341d0a2aa2a44d8a723761469f9c677ec8784c2c9d9e8b6fae0
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,123 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-08-18 v0.0.109
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
* Support for exporting and importing model options via the `/model` command:
|
|
8
|
+
* New `export_model_options` method in `model_handling.rb` to export
|
|
9
|
+
stored model profiles to a JSON file.
|
|
10
|
+
* New `import_model_options` method in `model_handling.rb` to import
|
|
11
|
+
profiles from a JSON file, featuring selective model picking, diff
|
|
12
|
+
display, and override confirmation.
|
|
13
|
+
* Extended `/model` command with `options export` and `options import`
|
|
14
|
+
subcommands.
|
|
15
|
+
* `-p` pattern flag for `/model options import` to narrow file search, with a
|
|
16
|
+
fallback to `**/*.json`.
|
|
17
|
+
* `-i` flag for `/paste` command to read input from stdin:
|
|
18
|
+
* New `paste_from_stdin` method in `clipboard.rb`.
|
|
19
|
+
* Updated `/paste` command regex and parsing to support both `-e` and
|
|
20
|
+
`-i` flags.
|
|
21
|
+
* `options` metadata to command definitions for `/copy`, `/paste`, `/toggle`,
|
|
22
|
+
and `/model`.
|
|
23
|
+
* Comprehensive test coverage for previously untested or under-tested
|
|
24
|
+
modules:
|
|
25
|
+
* `spec/ollama_chat/conversation_spec.rb` (9 examples).
|
|
26
|
+
* `spec/ollama_chat/favourites_management_spec.rb` (15 examples).
|
|
27
|
+
* `spec/ollama_chat/rag_handling_spec.rb` covering
|
|
28
|
+
`OllamaChat::RAGHandling`.
|
|
29
|
+
* `spec/ollama_chat/prompt_handling_spec.rb` (19 examples).
|
|
30
|
+
* `spec/ollama_chat/prompt_management_spec.rb` (47 examples).
|
|
31
|
+
* `spec/ollama_chat/system_prompt_management_spec.rb` (20 examples).
|
|
32
|
+
* `spec/ollama_chat/config_handling_spec.rb` (15 examples).
|
|
33
|
+
* `spec/ollama_chat/web_searching_spec.rb` (8 examples).
|
|
34
|
+
* `spec/ollama_chat/information_spec.rb` (5 examples).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
* Refactored session management to extract and reuse
|
|
39
|
+
`set_previous_session_on_change` as a shared private method in
|
|
40
|
+
`lib/ollama_chat/session_management.rb`.
|
|
41
|
+
* `set_new_session`, `duplicate_session`, and `change_session` now
|
|
42
|
+
delegate to this method for consistent `@previous_session_id` handling.
|
|
43
|
+
* Migrated test stubs from `allow` to `expect` across multiple spec files to
|
|
44
|
+
eliminate false-green tests where stubs were never invoked.
|
|
45
|
+
* Normalized `context` and `name` arguments in `prompt_handling.rb` to handle
|
|
46
|
+
`Symbol` inputs safely in SQL queries.
|
|
47
|
+
* Updated `s.files` and `s.test_files` in `ollama_chat.gemspec` to include
|
|
48
|
+
new configuration, asset, and test files.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
* Infinite retry loop in `kramdown_ansi.rb` by using `retried ||= false` to
|
|
53
|
+
persist the guard across `retry` calls.
|
|
54
|
+
* Incorrect YARD `@return` documentation for `#info_prompt` in
|
|
55
|
+
`prompt_management.rb`.
|
|
56
|
+
|
|
57
|
+
## 2026-08-15 v0.0.108
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- Added `require 'io/console'` to support `IO#raw` for key reads.
|
|
62
|
+
- Added `max` to `THINK_MODE_STATES` in `think_control.rb` to support newer
|
|
63
|
+
Ollama releases (e.g., **0.32.13**).
|
|
64
|
+
- Added migration `008_drop_think_mode_constraint.rb` to drop the `think_mode`
|
|
65
|
+
`CHECK` constraint in SQLite.
|
|
66
|
+
- Added `.obsidian` to `.gitignore` and the `GemHadar` `ignore` list in
|
|
67
|
+
`Rakefile`.
|
|
68
|
+
- Added `require_confirmation: true` to `get_current_weather`, `get_cve`,
|
|
69
|
+
`get_endoflife`, `browse`, `get_jira_issue`, `get_rfc`, and `get_ghr`.
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
|
|
73
|
+
- Refactored `confirm?` key reads to use `STDIN.raw(min:, time:, intr: true)`
|
|
74
|
+
instead of `stty` commands.
|
|
75
|
+
- Updated `confirm?` to print prompts to `output` instead of `STDOUT`.
|
|
76
|
+
- Updated glyphs for confirmation: `\u2328\uFE0F` to `\u2328`, `☑️` to `\u2611`,
|
|
77
|
+
and `🚫` to `\u{1F6AB}`.
|
|
78
|
+
- Scoped `Reline` histories for various interactive prompts:
|
|
79
|
+
- `duplicate_session` name prompt now scoped to `:session_name`.
|
|
80
|
+
- `determine_valid_new_name_for_persona` now scoped to `:persona_name`.
|
|
81
|
+
- `add_persona` `[FILES]` patterns prompt now scoped to `:patterns`.
|
|
82
|
+
- `add_new_prompt` `[FILES]` patterns prompt now scoped to `:patterns`.
|
|
83
|
+
- `determine_valid_output_filename` loop now scoped to `:filename`.
|
|
84
|
+
- `/session summarize -f` filename prompt now scoped to `:filename`.
|
|
85
|
+
- `choose_profile_for_model` profile name prompt now scoped to
|
|
86
|
+
`:profile_name`.
|
|
87
|
+
- Scoped `Reline` histories for RAG prompts:
|
|
88
|
+
- `rename_collection` now scopes to `:collection_name`.
|
|
89
|
+
- `create_collection` scopes to `:collection_name`,
|
|
90
|
+
`:collection_description`, and `:patterns`.
|
|
91
|
+
- `edit_collection` description prompt now uses `:collection_description`.
|
|
92
|
+
- Refactored terminal truncation by moving `truncate_for_terminal` from
|
|
93
|
+
`prepare_last_message` to `last_message_with_user`.
|
|
94
|
+
- Added `height:` keyword argument to `last_message_with_user` and
|
|
95
|
+
`display_formatted_terminal_output`.
|
|
96
|
+
- Refactored `display_formatted_terminal_output` to use `move_home` and
|
|
97
|
+
`erase_in_display(nil)` instead of `clear_screen` to prevent `tmux` flicker.
|
|
98
|
+
- Updated `require_confirmation` to `false` for `open_file_in_editor`,
|
|
99
|
+
`paste_into_editor`, and `generate_image`.
|
|
100
|
+
- Removed `jq` parsing from `OLLAMA_CHAT_TOOLS_TEST_RUNNER` in `.envrc`.
|
|
101
|
+
- Introduced `OLLAMA_CHAT_COLLECTION_NAME_REGEXP` in `lib/ollama_chat.rb` to
|
|
102
|
+
enforce safe identifiers.
|
|
103
|
+
- Updated `OLLAMA_CHAT::Chat#initial_collection` to validate names against the
|
|
104
|
+
new regex.
|
|
105
|
+
- Wrapped web search link list output in `use_pager` within
|
|
106
|
+
`OLLAMA_CHAT::WebSearching`.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
- Added `rescue` for `Interrupt` and `IRB::Abort` during key reads to return
|
|
110
|
+
`nil` and print `"\u274C\uFE0F"`.
|
|
111
|
+
- Fixed `tmux` flicker in vertically split panes by avoiding full-pane redraws.
|
|
112
|
+
- Fixed `OLLAMA_CHAT::Tools::PatchFile` to explicitly warn against redundant
|
|
113
|
+
tool calls.
|
|
114
|
+
|
|
115
|
+
### Refactored
|
|
116
|
+
- Updated YARD `@param output` and `@return` documentation.
|
|
117
|
+
- Simplified `last_message_with_user` to return a single joined string.
|
|
118
|
+
- Simplified `OLLAMA_CHAT::Tools::SearchKnowledge` to raise
|
|
119
|
+
`OLLAMA_CHAT::ToolFunctionArgumentError` on invalid input.
|
|
120
|
+
|
|
3
121
|
## 2026-08-09 v0.0.107
|
|
4
122
|
|
|
5
123
|
### Added
|
data/Rakefile
CHANGED
|
@@ -20,7 +20,7 @@ GemHadar do
|
|
|
20
20
|
test_dir 'spec'
|
|
21
21
|
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
|
|
22
22
|
'.yardoc', 'doc', 'tags', 'corpus', 'coverage', '/config/searxng/*',
|
|
23
|
-
'.starscope.db', 'cscope.out', 'errors.lst', 'tmp/*'
|
|
23
|
+
'.starscope.db', 'cscope.out', 'errors.lst', 'tmp/*', '.obsidian'
|
|
24
24
|
package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
|
|
25
25
|
'.rspec', '.github', '.contexts', '.envrc', '.yardopts'
|
|
26
26
|
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -229,11 +229,14 @@ class OllamaChat::Chat
|
|
|
229
229
|
#
|
|
230
230
|
# @return [ Symbol ] the collection name symbol
|
|
231
231
|
def initial_collection
|
|
232
|
-
|
|
233
|
-
session&.current_collection.full? ||
|
|
232
|
+
c = session&.current_collection.full? ||
|
|
234
233
|
config.embedding.collection.full? ||
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
'default'
|
|
235
|
+
if c =~ /\A#{OllamaChat::COLLECTION_NAME_REGEXP.source}\z/
|
|
236
|
+
c
|
|
237
|
+
else
|
|
238
|
+
'default'
|
|
239
|
+
end.to_sym
|
|
237
240
|
end
|
|
238
241
|
|
|
239
242
|
# The initial_system_prompt method returns the system prompt for the initial
|
|
@@ -143,4 +143,15 @@ module OllamaChat::Clipboard
|
|
|
143
143
|
log(:error, e, data: { method: __method__ })
|
|
144
144
|
STDERR.puts e.message
|
|
145
145
|
end
|
|
146
|
+
|
|
147
|
+
# Read the full text from STDIN and return it.
|
|
148
|
+
#
|
|
149
|
+
# @param edit [Boolean] If true, the text is passed through
|
|
150
|
+
# {#edit_text} before being returned.
|
|
151
|
+
# @return [String] The raw (or edited) content read from STDIN.
|
|
152
|
+
def paste_from_stdin(edit: false)
|
|
153
|
+
text = STDIN.read
|
|
154
|
+
edit and text = edit_text(text)
|
|
155
|
+
text
|
|
156
|
+
end
|
|
146
157
|
end
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -27,6 +27,7 @@ module OllamaChat::Commands
|
|
|
27
27
|
command(
|
|
28
28
|
name: :copy,
|
|
29
29
|
regexp: %r(^/copy(\s+-e)?\s*$),
|
|
30
|
+
options: '[-e]',
|
|
30
31
|
help: <<~EOT
|
|
31
32
|
📋 Copy the last response to the clipboard.
|
|
32
33
|
Options: -e to edit before copying.
|
|
@@ -39,15 +40,22 @@ module OllamaChat::Commands
|
|
|
39
40
|
|
|
40
41
|
command(
|
|
41
42
|
name: :paste,
|
|
42
|
-
regexp: %r(^/paste(\s+-
|
|
43
|
+
regexp: %r(^/paste(\s+-[ie])*\s*$),
|
|
44
|
+
options: '[-e|-i]',
|
|
43
45
|
help: <<~EOT
|
|
44
|
-
📋 Paste content from the clipboard.
|
|
45
|
-
Options:
|
|
46
|
+
📋 Paste content from the clipboard or stdin.
|
|
47
|
+
Options:
|
|
48
|
+
-e Edit after pasting.
|
|
49
|
+
-i Read from stdin instead of clipboard.
|
|
46
50
|
EOT
|
|
47
51
|
) do |opts|
|
|
48
52
|
disable_content_parsing
|
|
49
|
-
opts = go_command('
|
|
50
|
-
|
|
53
|
+
opts = go_command('ie', opts)
|
|
54
|
+
if opts[?i]
|
|
55
|
+
paste_from_stdin(edit: opts[?e])
|
|
56
|
+
else
|
|
57
|
+
paste_from_clipboard(edit: opts[?e])
|
|
58
|
+
end
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
## Settings
|
|
@@ -88,6 +96,7 @@ module OllamaChat::Commands
|
|
|
88
96
|
name: :toggle,
|
|
89
97
|
regexp: %r(^/toggle(?:\s+(markdown|stream|location|runtime_info|voice|think_loud|think_strip|embedding)(?:\s+(-[yn]))?)?$),
|
|
90
98
|
complete: [ 'toggle', %w[ markdown stream location runtime_info voice think_loud think_strip embedding ] ],
|
|
99
|
+
options: '[-y|-n]',
|
|
91
100
|
help: <<~EOT
|
|
92
101
|
🎛️ Toggle feature switches
|
|
93
102
|
(markdown, stream, location, runtime_info,
|
|
@@ -139,17 +148,21 @@ module OllamaChat::Commands
|
|
|
139
148
|
|
|
140
149
|
command(
|
|
141
150
|
name: :model,
|
|
142
|
-
regexp: %r(^/model(?:\s+(change|options(?: copy| delete)?|options from session|options to session))?((?:\s+(?:-m))*)$),
|
|
143
|
-
complete: [ 'model', %w[ change options options\ copy options\ delete options\ from\ session options\ to\ session ] ],
|
|
151
|
+
regexp: %r(^/model(?:\s+(change|options(?: copy| delete| export| import)?|options from session|options to session))?((?:\s+(?:-m|-p\s+[\S]+))*)$),
|
|
152
|
+
complete: [ 'model', %w[ change options options\ copy options\ delete options\ export options\ import options\ from\ session options\ to\ session ] ],
|
|
153
|
+
options: '[-m|-p pattern]',
|
|
144
154
|
help: <<~EOT
|
|
145
155
|
🤖 Manage AI models & profiles:
|
|
146
156
|
- change: Switch active model
|
|
147
157
|
- options: Edit saved profile config
|
|
148
158
|
- options copy: Copy profile from another model
|
|
149
159
|
- options delete: Delete a saved profile
|
|
160
|
+
- options export: Export ALL model profiles to JSON
|
|
161
|
+
- options import: Selectively import profiles from JSON
|
|
150
162
|
- options from session: Save live → Saved
|
|
151
163
|
- options to session: Apply Saved → Live
|
|
152
164
|
-m interactively choose a model
|
|
165
|
+
-p PATTERN narrow file search for import
|
|
153
166
|
EOT
|
|
154
167
|
) do |subcommand, opts|
|
|
155
168
|
if subcommand == 'change'
|
|
@@ -163,7 +176,7 @@ module OllamaChat::Commands
|
|
|
163
176
|
end
|
|
164
177
|
next :next
|
|
165
178
|
end
|
|
166
|
-
opts = go_command('
|
|
179
|
+
opts = go_command('mp:', opts)
|
|
167
180
|
model = opts[?m] ? choose_model('', @model) : @model
|
|
168
181
|
case subcommand
|
|
169
182
|
when 'options'
|
|
@@ -179,6 +192,12 @@ module OllamaChat::Commands
|
|
|
179
192
|
when 'options to session'
|
|
180
193
|
profile = choose_profile_for_model(model) || 'default'
|
|
181
194
|
copy_model_options_to_session(model, profile:)
|
|
195
|
+
when 'options export'
|
|
196
|
+
export_model_options
|
|
197
|
+
when 'options import'
|
|
198
|
+
pattern = opts[?p] || '**/*.json'
|
|
199
|
+
filename = choose_filename(pattern) or next :next
|
|
200
|
+
import_model_options(filename)
|
|
182
201
|
end
|
|
183
202
|
:next
|
|
184
203
|
end
|
|
@@ -296,8 +315,10 @@ module OllamaChat::Commands
|
|
|
296
315
|
when 'summarize'
|
|
297
316
|
opts = go_command('fs', opts)
|
|
298
317
|
if opts[?f] and
|
|
299
|
-
|
|
300
|
-
|
|
318
|
+
filename = switch_history(:filename) {
|
|
319
|
+
ask?(prompt: "❓ Enter filename: ")
|
|
320
|
+
}.full? { Pathname.new(_1) }
|
|
321
|
+
then
|
|
301
322
|
if filename.exist? && !confirm?(
|
|
302
323
|
prompt: "🔔 File #{filename.to_s.inspect} already exists, overwrite? (y/n) ",
|
|
303
324
|
yes: /\Ay/i
|
|
@@ -807,7 +828,7 @@ module OllamaChat::Commands
|
|
|
807
828
|
|
|
808
829
|
command(
|
|
809
830
|
name: :input,
|
|
810
|
-
regexp: %r(^/input(?:\s+(path|context|embedding|summary)(?:\s*(?=\z))?)?((?:\s+-(?:[apre]|c\s
|
|
831
|
+
regexp: %r(^/input(?:\s+(path|context|embedding|summary)(?:\s*(?=\z))?)?((?:\s+-(?:[apre]|c\s*#{OllamaChat::COLLECTION_NAME_REGEXP.source}|w\s*\d+|t\s*[-\w\.]+(?:,[-\w\.]+)*))*)(?:\s+([^-].*))?$),
|
|
811
832
|
optional: true,
|
|
812
833
|
complete: [ 'input', %w[ path context embedding summary ] ],
|
|
813
834
|
options: <<~EOT,
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Removes the `think_mode` CHECK constraint from the `sessions` table.
|
|
2
|
+
#
|
|
3
|
+
# The set of valid think modes is model-dependent and evolving upstream
|
|
4
|
+
# (e.g., `max` was only added mid-2026, and numeric token budgets are
|
|
5
|
+
# under discussion), so the schema should not pin a fixed vocabulary.
|
|
6
|
+
# State validation is handled in Ruby via
|
|
7
|
+
# `OllamaChat::ThinkControl::THINK_MODE_STATES` and the state selectors.
|
|
8
|
+
#
|
|
9
|
+
# SQLite cannot alter CHECK constraints in place, so the table is rebuilt
|
|
10
|
+
# using the same shadow-table pattern as
|
|
11
|
+
# `004_add_profile_to_model_options.rb`.
|
|
12
|
+
Sequel.migration do
|
|
13
|
+
up do
|
|
14
|
+
create_table(:sessions_new) do
|
|
15
|
+
primary_key :id
|
|
16
|
+
String :name, null: false
|
|
17
|
+
String :current_model
|
|
18
|
+
String :current_collection
|
|
19
|
+
String :default_persona_name
|
|
20
|
+
String :current_system_prompt
|
|
21
|
+
Boolean :tools_enabled, null: false
|
|
22
|
+
Text :tools_default_enabled
|
|
23
|
+
String :think_mode, null: false
|
|
24
|
+
Bool :think_loud_enabled, null: false
|
|
25
|
+
Bool :embedding_enabled, null: false
|
|
26
|
+
String :document_policy, null: false
|
|
27
|
+
Bool :runtime_info_enabled, null: false
|
|
28
|
+
Bool :think_strip_enabled, null: false
|
|
29
|
+
Boolean :markdown_enabled, null: false
|
|
30
|
+
Boolean :stream_enabled, null: false
|
|
31
|
+
Boolean :location_enabled, null: false
|
|
32
|
+
Boolean :voice_enabled, null: false
|
|
33
|
+
String :current_voice, null: false
|
|
34
|
+
Text :working_directory
|
|
35
|
+
Integer :locked_by_pid
|
|
36
|
+
Text :model_options
|
|
37
|
+
Text :messages, null: false
|
|
38
|
+
Text :links, null: false, default: ''
|
|
39
|
+
Text :history, null: false, default: ''
|
|
40
|
+
String :context_format, null: false, default: 'JSON'
|
|
41
|
+
Time :created_at
|
|
42
|
+
Time :updated_at
|
|
43
|
+
unique [:name]
|
|
44
|
+
|
|
45
|
+
constraint(
|
|
46
|
+
:document_policy,
|
|
47
|
+
document_policy: %w[ ignoring embedding importing summarizing ]
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
source = from(:sessions).select(
|
|
52
|
+
:id, :name, :current_model, :current_collection,
|
|
53
|
+
:default_persona_name, :current_system_prompt,
|
|
54
|
+
:tools_enabled, :tools_default_enabled, :think_mode,
|
|
55
|
+
:think_loud_enabled, :embedding_enabled, :document_policy,
|
|
56
|
+
:runtime_info_enabled, :think_strip_enabled,
|
|
57
|
+
:markdown_enabled, :stream_enabled, :location_enabled,
|
|
58
|
+
:voice_enabled, :current_voice, :working_directory,
|
|
59
|
+
:locked_by_pid, :model_options, :messages, :links,
|
|
60
|
+
:history, :context_format, :created_at, :updated_at
|
|
61
|
+
)
|
|
62
|
+
from(:sessions_new).insert(source)
|
|
63
|
+
|
|
64
|
+
drop_table(:sessions)
|
|
65
|
+
rename_table(:sessions_new, :sessions)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
down do
|
|
69
|
+
# Restores the original `think_mode` constraint. All rows that
|
|
70
|
+
# predate the up-migration satisfy it; any newer value (e.g. `max`)
|
|
71
|
+
# would fail the insert, which is the desired loud failure on
|
|
72
|
+
# rollback.
|
|
73
|
+
create_table(:sessions_old) do
|
|
74
|
+
primary_key :id
|
|
75
|
+
String :name, null: false
|
|
76
|
+
String :current_model
|
|
77
|
+
String :current_collection
|
|
78
|
+
String :default_persona_name
|
|
79
|
+
String :current_system_prompt
|
|
80
|
+
Boolean :tools_enabled, null: false
|
|
81
|
+
Text :tools_default_enabled
|
|
82
|
+
String :think_mode, null: false
|
|
83
|
+
Bool :think_loud_enabled, null: false
|
|
84
|
+
Bool :embedding_enabled, null: false
|
|
85
|
+
String :document_policy, null: false
|
|
86
|
+
Bool :runtime_info_enabled, null: false
|
|
87
|
+
Bool :think_strip_enabled, null: false
|
|
88
|
+
Boolean :markdown_enabled, null: false
|
|
89
|
+
Boolean :stream_enabled, null: false
|
|
90
|
+
Boolean :location_enabled, null: false
|
|
91
|
+
Boolean :voice_enabled, null: false
|
|
92
|
+
String :current_voice, null: false
|
|
93
|
+
Text :working_directory
|
|
94
|
+
Integer :locked_by_pid
|
|
95
|
+
Text :model_options
|
|
96
|
+
Text :messages, null: false
|
|
97
|
+
Text :links, null: false, default: ''
|
|
98
|
+
Text :history, null: false, default: ''
|
|
99
|
+
String :context_format, null: false, default: 'JSON'
|
|
100
|
+
Time :created_at
|
|
101
|
+
Time :updated_at
|
|
102
|
+
unique [:name]
|
|
103
|
+
|
|
104
|
+
constraint(
|
|
105
|
+
:think_mode,
|
|
106
|
+
think_mode: %w[ disabled enabled low medium high ]
|
|
107
|
+
)
|
|
108
|
+
constraint(
|
|
109
|
+
:document_policy,
|
|
110
|
+
document_policy: %w[ ignoring embedding importing summarizing ]
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
source = from(:sessions).select(
|
|
115
|
+
:id, :name, :current_model, :current_collection,
|
|
116
|
+
:default_persona_name, :current_system_prompt,
|
|
117
|
+
:tools_enabled, :tools_default_enabled, :think_mode,
|
|
118
|
+
:think_loud_enabled, :embedding_enabled, :document_policy,
|
|
119
|
+
:runtime_info_enabled, :think_strip_enabled,
|
|
120
|
+
:markdown_enabled, :stream_enabled, :location_enabled,
|
|
121
|
+
:voice_enabled, :current_voice, :working_directory,
|
|
122
|
+
:locked_by_pid, :model_options, :messages, :links,
|
|
123
|
+
:history, :context_format, :created_at, :updated_at
|
|
124
|
+
)
|
|
125
|
+
from(:sessions_old).insert(source)
|
|
126
|
+
|
|
127
|
+
drop_table(:sessions)
|
|
128
|
+
rename_table(:sessions_old, :sessions)
|
|
129
|
+
end
|
|
130
|
+
end
|
data/lib/ollama_chat/dialog.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'io/console'
|
|
2
|
+
|
|
1
3
|
# A module that provides interactive selection and configuration functionality
|
|
2
4
|
# for OllamaChat.
|
|
3
5
|
#
|
|
@@ -35,27 +37,32 @@ module OllamaChat::Dialog
|
|
|
35
37
|
# @param default [Object, nil] value returned when the timeout expires
|
|
36
38
|
# (defaults to `nil`)
|
|
37
39
|
# @param yes [Object, nil] value that is considered a positive response
|
|
38
|
-
# @param output [IO] the IO object to write the prompt to
|
|
40
|
+
# @param output [IO] the IO object to write the prompt and the answer to
|
|
39
41
|
#
|
|
40
|
-
# @return [Object] the character entered by the user,
|
|
41
|
-
# if a timeout occurs
|
|
42
|
+
# @return [Object] the character entered by the user, the `default` value
|
|
43
|
+
# if a timeout occurs, or `nil` if the read is interrupted (e.g. Ctrl-C)
|
|
42
44
|
def confirm?(prompt:, timeout: nil, default: nil, yes: nil, output: STDOUT)
|
|
43
45
|
return default if timeout&.zero?
|
|
44
46
|
if prompt.include?('%s')
|
|
45
47
|
prompt = prompt % (timeout ? ('timeout in %us' % timeout) : 'no timeout')
|
|
46
48
|
end
|
|
47
|
-
print prompt
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
output.print prompt
|
|
50
|
+
min = 1
|
|
51
|
+
time = 0
|
|
52
|
+
if timeout
|
|
53
|
+
min = 0
|
|
54
|
+
time = timeout
|
|
55
|
+
end
|
|
56
|
+
exceptions = [ (IRB::Abort if defined? IRB), Interrupt ].compact
|
|
57
|
+
begin
|
|
58
|
+
keypress = STDIN.raw(min:, time:, intr: true) do |io|
|
|
59
|
+
io.getc
|
|
60
|
+
end
|
|
61
|
+
rescue *exceptions
|
|
62
|
+
output.puts "\u274C\uFE0F"
|
|
63
|
+
return
|
|
64
|
+
end
|
|
65
|
+
answer = keypress || default
|
|
59
66
|
case
|
|
60
67
|
when yes.nil?
|
|
61
68
|
if keypress
|
|
@@ -68,12 +75,12 @@ module OllamaChat::Dialog
|
|
|
68
75
|
if keypress
|
|
69
76
|
output.puts "\u2705\uFE0F #{answer}"
|
|
70
77
|
else
|
|
71
|
-
output.puts "
|
|
78
|
+
output.puts "\u2611\uFE0F #{answer}"
|
|
72
79
|
end
|
|
73
80
|
answer
|
|
74
81
|
else
|
|
75
82
|
if keypress
|
|
76
|
-
output.puts "
|
|
83
|
+
output.puts "\u{1F6AB} #{answer}"
|
|
77
84
|
else
|
|
78
85
|
output.puts "\u231B\uFE0F #{answer}"
|
|
79
86
|
end
|
|
@@ -111,20 +111,22 @@ module OllamaChat::FileEditing
|
|
|
111
111
|
# @return [Pathname, nil] the validated filename as a Pathname, or nil if the
|
|
112
112
|
# operation was cancelled
|
|
113
113
|
def determine_valid_output_filename(action)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
switch_history(:filename) do
|
|
115
|
+
loop do
|
|
116
|
+
filename_str = ask?(
|
|
117
|
+
prompt: "❓ Enter filename #{action}, C-c ⇒ cancel: "
|
|
118
|
+
)
|
|
119
|
+
if filename_str.nil?
|
|
120
|
+
STDOUT.puts "Cancelled."
|
|
121
|
+
return nil
|
|
122
|
+
end
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
filename = Pathname.new(filename_str)
|
|
125
|
+
if filename.exist?
|
|
126
|
+
STDERR.puts "File #{filename.to_path.inspect} already exists!"
|
|
127
|
+
else
|
|
128
|
+
return filename
|
|
129
|
+
end
|
|
128
130
|
end
|
|
129
131
|
end
|
|
130
132
|
end
|
|
@@ -39,6 +39,9 @@ class OllamaChat::FollowChat
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
# Returns the chat object representing the conversation context.
|
|
43
|
+
#
|
|
44
|
+
# @return [OllamaChat::Chat] The chat object.
|
|
42
45
|
attr_reader :chat
|
|
43
46
|
|
|
44
47
|
# Returns the conversation history (an array of message objects).
|
|
@@ -74,7 +77,7 @@ class OllamaChat::FollowChat
|
|
|
74
77
|
ensure_assistant_response_exists
|
|
75
78
|
update_last_message(response)
|
|
76
79
|
if chat.stream.on?
|
|
77
|
-
display_formatted_terminal_output
|
|
80
|
+
display_formatted_terminal_output(height: Tins::Terminal.lines - 1)
|
|
78
81
|
else
|
|
79
82
|
if display_output
|
|
80
83
|
display_formatted_terminal_output
|
|
@@ -293,9 +296,9 @@ class OllamaChat::FollowChat
|
|
|
293
296
|
def prepare_last_message
|
|
294
297
|
content, thinking = @messages.last.content, @messages.last.thinking
|
|
295
298
|
if chat.markdown.on?
|
|
296
|
-
content = talk_annotate {
|
|
299
|
+
content = talk_annotate { chat.kramdown_ansi_parse(content) }
|
|
297
300
|
if chat.think?
|
|
298
|
-
thinking = think_annotate {
|
|
301
|
+
thinking = think_annotate { chat.kramdown_ansi_parse(thinking) }
|
|
299
302
|
end
|
|
300
303
|
else
|
|
301
304
|
content = talk_annotate { content }
|
|
@@ -304,20 +307,28 @@ class OllamaChat::FollowChat
|
|
|
304
307
|
return content&.chomp, thinking&.chomp
|
|
305
308
|
end
|
|
306
309
|
|
|
307
|
-
# The last_message_with_user method constructs a formatted
|
|
310
|
+
# The last_message_with_user method constructs a formatted string by
|
|
308
311
|
# combining user information, newline characters, thinking annotations, and
|
|
309
312
|
# content for display in the terminal output.
|
|
310
313
|
#
|
|
311
|
-
# @
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
|
|
314
|
+
# @param height [Integer] the maximum number of lines to truncate the output
|
|
315
|
+
# to. Defaults to 0 (no truncation).
|
|
316
|
+
#
|
|
317
|
+
# @return [String] the formatted message string containing the user
|
|
318
|
+
# identifier, newline character, thinking annotation (if present), and
|
|
319
|
+
# content formatted for terminal display
|
|
320
|
+
def last_message_with_user(height: 0)
|
|
315
321
|
content, thinking = prepare_last_message
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
322
|
+
content ||= ''
|
|
323
|
+
result = if thinking.present?
|
|
324
|
+
[ @sender + ":\n", thinking, ?\n, content ]
|
|
325
|
+
else
|
|
326
|
+
[ @sender + ":\n", content ]
|
|
327
|
+
end * ''
|
|
328
|
+
if height > 0
|
|
329
|
+
result = truncate_for_terminal(result, max_lines: height)
|
|
320
330
|
end
|
|
331
|
+
result
|
|
321
332
|
end
|
|
322
333
|
|
|
323
334
|
# The display_formatted_terminal_output method formats and outputs the
|
|
@@ -327,9 +338,17 @@ class OllamaChat::FollowChat
|
|
|
327
338
|
# move home commands. The method takes into account whether markdown and
|
|
328
339
|
# thinking modes are enabled to determine how to process and display the
|
|
329
340
|
# content.
|
|
330
|
-
|
|
341
|
+
#
|
|
342
|
+
# @param output [IO, nil] the output stream to print to. Defaults to
|
|
343
|
+
# `@output`.
|
|
344
|
+
# @param height [Integer] the maximum number of lines to truncate the output
|
|
345
|
+
# to. Defaults to 0 (no truncation).
|
|
346
|
+
def display_formatted_terminal_output(output = nil, height: 0)
|
|
331
347
|
output ||= @output
|
|
332
|
-
output.print(
|
|
348
|
+
output.print(
|
|
349
|
+
move_home, erase_in_display(nil),
|
|
350
|
+
last_message_with_user(height:)
|
|
351
|
+
)
|
|
333
352
|
end
|
|
334
353
|
|
|
335
354
|
# The display_output method shows the last message in the conversation.
|
|
@@ -345,7 +364,7 @@ class OllamaChat::FollowChat
|
|
|
345
364
|
if chat.markdown.on?
|
|
346
365
|
display_formatted_terminal_output(output)
|
|
347
366
|
else
|
|
348
|
-
output.print(
|
|
367
|
+
output.print(last_message_with_user)
|
|
349
368
|
end
|
|
350
369
|
end
|
|
351
370
|
end
|
|
@@ -39,7 +39,7 @@ module OllamaChat::KramdownANSI
|
|
|
39
39
|
# @return [ String ] the content formatted with ANSI escape sequences
|
|
40
40
|
# according to the configured styles
|
|
41
41
|
def kramdown_ansi_parse(content)
|
|
42
|
-
retried
|
|
42
|
+
retried ||= false
|
|
43
43
|
content.nil? and return ''
|
|
44
44
|
Kramdown::ANSI.parse(content, ansi_styles: @kramdown_ansi_styles)
|
|
45
45
|
rescue Encoding::UndefinedConversionError
|