ollama_chat 0.0.105 → 0.0.107
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 +85 -0
- data/README.md +16 -0
- data/bin/ollama_chat_send +12 -2
- data/lib/ollama_chat/chat.rb +17 -1
- data/lib/ollama_chat/commands.rb +18 -12
- data/lib/ollama_chat/database/models/prompt.rb +1 -1
- data/lib/ollama_chat/follow_chat.rb +5 -1
- data/lib/ollama_chat/input_content.rb +1 -1
- data/lib/ollama_chat/model_handling.rb +33 -5
- data/lib/ollama_chat/ollama_chat_config/default_config.yml +7 -1
- data/lib/ollama_chat/prompt_management.rb +87 -46
- data/lib/ollama_chat/rag_handling.rb +6 -5
- data/lib/ollama_chat/say.rb +30 -0
- data/lib/ollama_chat/state_selectors.rb +2 -1
- data/lib/ollama_chat/tools/write_file.rb +16 -0
- data/lib/ollama_chat/version.rb +1 -1
- data/lib/ollama_chat.rb +1 -0
- data/ollama_chat.gemspec +4 -4
- data/spec/ollama_chat/commands_spec.rb +7 -7
- data/spec/ollama_chat/tools/write_file_spec.rb +104 -2
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e2686defd34fe5cf4e0f61c980480578f6b2589bc429d7b724ed4f3cb478d7b8
|
|
4
|
+
data.tar.gz: 8bd9136e0e6f3e202c93f8c4aec0a4b482a447bfd1e29163b0dff1973e64f2fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a177889fb72f197a05895b60c7e73f1493a119fcc7832354772097f121d53b150ea500fdf50ae81bdeb05161f0a3121af204496d54a708a13c427096e126159
|
|
7
|
+
data.tar.gz: 55c0270902a86e39e1704d62a4478daf0d04526312d47eb35f560b3b95218045d6699dd428b874fa9059ce3af8585bed97a5c2bd662751ef05885baa452a9c6b
|
data/CHANGES.md
CHANGED
|
@@ -1,5 +1,90 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-08-09 v0.0.107
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- New `-e` option to `ollama_chat_send` to open input content in the configured
|
|
8
|
+
editor before sending.
|
|
9
|
+
- New `-F` option to `ollama_chat_send` to specify file extension for syntax
|
|
10
|
+
highlighting in the editor.
|
|
11
|
+
- Confirmation prompts to `write_file` when overwriting existing files in
|
|
12
|
+
`overwrite` mode or creating new files in `append` mode.
|
|
13
|
+
- Support for pluggable voice handler architecture via a new `handler` key in
|
|
14
|
+
the `voice` configuration.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Refactored voice handling to use a dynamic `voice_handler` method in
|
|
19
|
+
`OllamaChat::Chat` to resolve configured classes (e.g., `OllamaChat::Say`).
|
|
20
|
+
- Externalized the suggestion prompt template by adding
|
|
21
|
+
`context_template_suggest` to `default_config.yml` under `prompts`, replacing
|
|
22
|
+
hardcoded heredocs in `prompt_management.rb`.
|
|
23
|
+
- Updated `StateSelectors` to delegate voice list retrieval via
|
|
24
|
+
`voice_handler.ask_and_send(:voices)`.
|
|
25
|
+
- Updated `FollowChat` to instantiate the resolved voice handler dynamically.
|
|
26
|
+
- Refactored `OllamaChat::Say.voices` to extract logic from
|
|
27
|
+
`default_config.yml` ERB and remove RSpec-specific branching.
|
|
28
|
+
- Updated `spec/ollama_chat/commands_spec.rb` to use explicit `.jsonl`
|
|
29
|
+
extensions for `/conversation save` and `/conversation load` tests.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Reopened `STDIN` from `/dev/tty` during editing to prevent editor warnings.
|
|
34
|
+
- Ensured `save_conversation` and `load_conversation` expectations match the
|
|
35
|
+
new file naming convention.
|
|
36
|
+
|
|
37
|
+
### Security & Error Handling
|
|
38
|
+
|
|
39
|
+
- Raised `OllamaChat::ToolFunctionArgumentError` when a user declines a file
|
|
40
|
+
operation confirmation.
|
|
41
|
+
- Added `.to_s` call on `prompt` results to correctly handle `Sequel::Model`
|
|
42
|
+
return types.
|
|
43
|
+
|
|
44
|
+
## 2026-08-06 v0.0.106
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- New `/model options delete` subcommand to allow removing saved profiles.
|
|
49
|
+
- Implementation of `delete_model_options_profile` in `model_handling.rb`.
|
|
50
|
+
- New `/prompt rename` subcommand for prompt templates.
|
|
51
|
+
- Implementation of `rename_prompt` method in `prompt_management.rb`.
|
|
52
|
+
- Support for shell-style quoting for file pattern arguments using
|
|
53
|
+
`Shellwords.split`.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Tightened validation for the `/conversation` command to restrict filenames to
|
|
58
|
+
`.json` or `.jsonl` extensions.
|
|
59
|
+
- Updated `options` string documentation to include the optional `FILENAME`
|
|
60
|
+
argument and added format hints to `save` and `load` subcommands.
|
|
61
|
+
- Added a `suggest` parameter to `choose_profile_for_model` to allow specific
|
|
62
|
+
profiles to be inserted at the top of selection lists.
|
|
63
|
+
- Updated `copy_model_options_profile` to use the source profile as the
|
|
64
|
+
suggested destination.
|
|
65
|
+
- Refactored error logging in `OllamaChat::Chat` to use a standardized `log`
|
|
66
|
+
method with `:warn` level instead of direct `STDOUT.puts`.
|
|
67
|
+
- Centralized pattern parsing logic by replacing `arg.scan(/(\S+)/).flatten`
|
|
68
|
+
with `extract_patterns` in `commands.rb`.
|
|
69
|
+
- Updated context generation in `input_content.rb` to dynamically call
|
|
70
|
+
`to_json` or `to_toon` based on the selected format.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- Resolved a scope limitation in `Prompt#after_destroy` by replacing
|
|
75
|
+
`models::Favourite` with `OllamaChat::Database::Models::Favourite`.
|
|
76
|
+
- Ensured the `default` profile remains valid by resetting it to an empty
|
|
77
|
+
options `{}` instead of deleting it during model option removal.
|
|
78
|
+
|
|
79
|
+
### Refactored
|
|
80
|
+
|
|
81
|
+
- Improved readability in `model_handling.rb` by wrapping long `STDOUT.puts`
|
|
82
|
+
strings.
|
|
83
|
+
- Wrapped prompt operations in `switch_history(:prompt)` for improved
|
|
84
|
+
consistency.
|
|
85
|
+
- Updated YARD documentation for `extract_patterns` to reflect new shell
|
|
86
|
+
semantics.
|
|
87
|
+
|
|
3
88
|
## 2026-08-04 v0.0.105
|
|
4
89
|
|
|
5
90
|
### New Features
|
data/README.md
CHANGED
|
@@ -344,6 +344,22 @@ functionality:
|
|
|
344
344
|
$ echo "Hello world" | ollama_chat_send -d /tmp/my_working_dir -r
|
|
345
345
|
```
|
|
346
346
|
|
|
347
|
+
- **Edit Content (`-e`)**: Opens the input content in the configured editor
|
|
348
|
+
before sending. This is useful for refining the message or adding more
|
|
349
|
+
context.
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
$ echo "Draft message..." | ollama_chat_send -e
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
- **File Format (`-F`)**: When using edit mode, specify a file extension to
|
|
356
|
+
enable syntax highlighting in your editor (e.g., `rb` for Ruby, `md` for
|
|
357
|
+
Markdown).
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
$ echo "def hello; end" | ollama_chat_send -e -F rb
|
|
361
|
+
```
|
|
362
|
+
|
|
347
363
|
- **Help (`-h` or `--help`)**: Displays usage information and available options.
|
|
348
364
|
|
|
349
365
|
```bash
|
data/bin/ollama_chat_send
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
require 'ollama_chat'
|
|
4
|
+
include OllamaChat::FileEditing
|
|
4
5
|
require 'tins/go'
|
|
5
6
|
include Tins::GO
|
|
6
7
|
|
|
7
|
-
opts = go 'f:d:
|
|
8
|
+
opts = go 'f:d:F:rteph', ARGV
|
|
8
9
|
|
|
9
10
|
# Displays the usage information for the ollama_chat_send command.
|
|
10
11
|
#
|
|
@@ -23,6 +24,8 @@ def usage(rc = 0)
|
|
|
23
24
|
-p Send input with source parsing enabled (defaults to disabled)
|
|
24
25
|
-f CONFIG file to read
|
|
25
26
|
-d DIR the working directory to derive the socket file from
|
|
27
|
+
-e Edit content in editor before sending
|
|
28
|
+
-F FORMAT file extension for editor (e.g., rb, md)
|
|
26
29
|
-h Show this help message
|
|
27
30
|
|
|
28
31
|
Send data to a running Ollama Chat client via standard input.
|
|
@@ -38,8 +41,15 @@ begin
|
|
|
38
41
|
else
|
|
39
42
|
opts[?r] ? :socket_input_with_response : :socket_input
|
|
40
43
|
end
|
|
44
|
+
content = STDIN.read
|
|
45
|
+
if opts[?e]
|
|
46
|
+
basename = %w[ text ]
|
|
47
|
+
basename << opts[?F]&.sub(/\A(?=[^.])/, ?.) || '.md'
|
|
48
|
+
STDIN.reopen('/dev/tty')
|
|
49
|
+
content = edit_text(content, basename:)
|
|
50
|
+
end
|
|
41
51
|
response = OllamaChat::ServerSocket.send_to_server_socket(
|
|
42
|
-
|
|
52
|
+
content,
|
|
43
53
|
type:,
|
|
44
54
|
config:,
|
|
45
55
|
working_dir: opts[?d],
|
data/lib/ollama_chat/chat.rb
CHANGED
|
@@ -160,6 +160,21 @@ class OllamaChat::Chat
|
|
|
160
160
|
# @return [OllamaChat::RedisCache, nil] the cache instance
|
|
161
161
|
attr_reader :cache
|
|
162
162
|
|
|
163
|
+
|
|
164
|
+
# Returns the voice handler class based on the configuration.
|
|
165
|
+
#
|
|
166
|
+
# This method resolves the voice handler class specified in the config.
|
|
167
|
+
# If running within RSpec, it returns an empty array to avoid side effects.
|
|
168
|
+
#
|
|
169
|
+
# @return [Class, Array] the voice handler class or an empty array if in test mode
|
|
170
|
+
def voice_handler
|
|
171
|
+
defined?(RSpec) and return []
|
|
172
|
+
case config.voice.handler
|
|
173
|
+
when 'OllamaChat::Say'
|
|
174
|
+
OllamaChat::Say
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
163
178
|
# The start method initializes the chat session by displaying information,
|
|
164
179
|
# then prompts the user for input to begin interacting with the chat.
|
|
165
180
|
def start
|
|
@@ -535,7 +550,8 @@ class OllamaChat::Chat
|
|
|
535
550
|
store_messages_in_session
|
|
536
551
|
rescue Ollama::Errors::BadRequestError
|
|
537
552
|
if (think? || tools_support.on?) && !retried
|
|
538
|
-
|
|
553
|
+
msg = "Error in think mode/with tool support, switch both off and retry."
|
|
554
|
+
log(:warn, msg, warn: true)
|
|
539
555
|
sleep 1
|
|
540
556
|
think_mode.selected = 'disabled'
|
|
541
557
|
tools_support.set false
|
data/lib/ollama_chat/commands.rb
CHANGED
|
@@ -139,13 +139,14 @@ module OllamaChat::Commands
|
|
|
139
139
|
|
|
140
140
|
command(
|
|
141
141
|
name: :model,
|
|
142
|
-
regexp: %r(^/model(?:\s+(change|options(?: copy)?|options from session|options to session))?((?:\s+(?:-m))*)$),
|
|
143
|
-
complete: [ 'model', %w[ change options options\ copy options\ from\ session options\ to\ session ] ],
|
|
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 ] ],
|
|
144
144
|
help: <<~EOT
|
|
145
145
|
🤖 Manage AI models & profiles:
|
|
146
146
|
- change: Switch active model
|
|
147
147
|
- options: Edit saved profile config
|
|
148
148
|
- options copy: Copy profile from another model
|
|
149
|
+
- options delete: Delete a saved profile
|
|
149
150
|
- options from session: Save live → Saved
|
|
150
151
|
- options to session: Apply Saved → Live
|
|
151
152
|
-m interactively choose a model
|
|
@@ -170,6 +171,8 @@ module OllamaChat::Commands
|
|
|
170
171
|
edit_model_options(model, profile:)
|
|
171
172
|
when 'options copy'
|
|
172
173
|
copy_model_options_profile(model)
|
|
174
|
+
when 'options delete'
|
|
175
|
+
delete_model_options_profile(model)
|
|
173
176
|
when 'options from session'
|
|
174
177
|
profile = choose_profile_for_model(model) || 'default'
|
|
175
178
|
copy_model_options_from_session(model, profile:)
|
|
@@ -460,14 +463,14 @@ module OllamaChat::Commands
|
|
|
460
463
|
|
|
461
464
|
command(
|
|
462
465
|
name: :prompt,
|
|
463
|
-
regexp: %r(^/prompt(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|-e))?(\s+(?:-[ef]|-c\s+(?:\w+|\?)))?(?:\s+([^-].*))?$),
|
|
464
|
-
complete: [ 'prompt', %w[ edit info add delete list duplicate import export reset ] ],
|
|
466
|
+
regexp: %r(^/prompt(?:\s+(edit|info|add|delete|list|duplicate|import|export|reset|rename|-e))?(\s+(?:-[ef]|-c\s+(?:\w+|\?)))?(?:\s+([^-].*))?$),
|
|
467
|
+
complete: [ 'prompt', %w[ edit info add delete list duplicate import export reset rename ] ],
|
|
465
468
|
optional: true,
|
|
466
469
|
options: '[-c CONTEXT|-e|-f]',
|
|
467
470
|
help: <<~EOT,
|
|
468
471
|
📝 Manage prompt templates:
|
|
469
472
|
Subcommands: edit, info, add, delete, list,
|
|
470
|
-
duplicate, import, export, reset.
|
|
473
|
+
duplicate, import, export, reset, rename.
|
|
471
474
|
Options: -c [context]
|
|
472
475
|
(? for interactive in /prompt),
|
|
473
476
|
-e (edit next)
|
|
@@ -499,6 +502,8 @@ module OllamaChat::Commands
|
|
|
499
502
|
list_prompts(context:)
|
|
500
503
|
when 'duplicate'
|
|
501
504
|
duplicate_prompt(context:)
|
|
505
|
+
when 'rename'
|
|
506
|
+
rename_prompt(context:)
|
|
502
507
|
when 'import'
|
|
503
508
|
import_prompt(filename, context:)
|
|
504
509
|
when 'export'
|
|
@@ -565,12 +570,13 @@ module OllamaChat::Commands
|
|
|
565
570
|
|
|
566
571
|
command(
|
|
567
572
|
name: :conversation,
|
|
568
|
-
regexp: %r(^/conversation\s+(clean|save|load)(\s+-c)?(?:\s+([^-]
|
|
573
|
+
regexp: %r(^/conversation\s+(clean|save|load)(\s+-c)?(?:\s+([^-].*\.jsonl?))?$),
|
|
569
574
|
complete: [ 'conversation', %w[ save load clean ] ],
|
|
570
|
-
options: '[-c]',
|
|
575
|
+
options: '[-c] [FILENAME]',
|
|
571
576
|
help: <<~EOT
|
|
572
577
|
💾 Save/Load conversation state
|
|
573
578
|
(-c to clean before saving)
|
|
579
|
+
FILENAME ends with .json or .jsonl
|
|
574
580
|
Or clean inplace (removes tool content, images, and thinking)
|
|
575
581
|
EOT
|
|
576
582
|
) do |subcommand,opts,path|
|
|
@@ -826,7 +832,7 @@ module OllamaChat::Commands
|
|
|
826
832
|
if opts[?p]
|
|
827
833
|
words = opts.fetch(?w, 100)
|
|
828
834
|
all = opts.fetch(?a, false)
|
|
829
|
-
|
|
835
|
+
patterns = extract_patterns(arg)
|
|
830
836
|
next provide_file_set_content(patterns, all:, skip_blank: true) { summarize(_1, words:) } || :next
|
|
831
837
|
elsif arg
|
|
832
838
|
words = opts.fetch(?w, 100)
|
|
@@ -840,7 +846,7 @@ module OllamaChat::Commands
|
|
|
840
846
|
opts = go_command('pa', opts)
|
|
841
847
|
if opts[?p]
|
|
842
848
|
all = opts.fetch(?a, false)
|
|
843
|
-
patterns = arg
|
|
849
|
+
patterns = extract_patterns(arg).full? || [ '**/*' ]
|
|
844
850
|
next context_spook(patterns, all:) || :next
|
|
845
851
|
elsif arg
|
|
846
852
|
next context_spook(Array(arg.to_s), all: true) || :next
|
|
@@ -862,7 +868,7 @@ module OllamaChat::Commands
|
|
|
862
868
|
tags = opts[?t].full?(:split, ?,)
|
|
863
869
|
if opts[?p]
|
|
864
870
|
all = opts.fetch(?a, false)
|
|
865
|
-
|
|
871
|
+
patterns = extract_patterns(arg)
|
|
866
872
|
next provide_file_set_content(patterns, all:, skip_blank: true) { embed(_1, tags:) } || :next
|
|
867
873
|
elsif arg
|
|
868
874
|
next embed(arg, tags:) || :next
|
|
@@ -875,7 +881,7 @@ module OllamaChat::Commands
|
|
|
875
881
|
opts = go_command('pae', opts)
|
|
876
882
|
if opts[?p]
|
|
877
883
|
all = opts.fetch(?a, false)
|
|
878
|
-
|
|
884
|
+
patterns = extract_patterns(arg)
|
|
879
885
|
read = -> pathname {
|
|
880
886
|
STDOUT.puts "Reading #{pathname.to_s.inspect}."
|
|
881
887
|
pathname.read
|
|
@@ -895,7 +901,7 @@ module OllamaChat::Commands
|
|
|
895
901
|
opts = go_command('pae', opts)
|
|
896
902
|
if opts[?p]
|
|
897
903
|
all = opts.fetch(?a, false)
|
|
898
|
-
|
|
904
|
+
patterns = extract_patterns(arg)
|
|
899
905
|
next provide_file_set_content(patterns, all:, skip_blank: true) { import(_1) } || :next
|
|
900
906
|
elsif arg
|
|
901
907
|
source = arg
|
|
@@ -52,7 +52,7 @@ class OllamaChat::Database::Models::Prompt < Sequel::Model(OllamaChat::DB)
|
|
|
52
52
|
# database when the underlying prompt is removed.
|
|
53
53
|
def after_destroy
|
|
54
54
|
super
|
|
55
|
-
|
|
55
|
+
OllamaChat::Database::Models::Favourite.where(context:, name:).destroy
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# Seeds the prompt table from the provided chat configuration.
|
|
@@ -29,10 +29,14 @@ class OllamaChat::FollowChat
|
|
|
29
29
|
super(output:)
|
|
30
30
|
@chat = chat
|
|
31
31
|
@output.sync = true
|
|
32
|
-
@say = voice ? Handlers::Say.new(voice:) : NOP
|
|
33
32
|
@messages = messages
|
|
34
33
|
@group_uuid = group_uuid
|
|
35
34
|
@sender = nil
|
|
35
|
+
@say = if voice && @chat.voice_handler.respond_to?(:new)
|
|
36
|
+
@chat.voice_handler.new(chat:, voice:)
|
|
37
|
+
else
|
|
38
|
+
NOP
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
attr_reader :chat
|
|
@@ -102,7 +102,7 @@ module OllamaChat::InputContent
|
|
|
102
102
|
file filename.to_path
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
|
-
end.
|
|
105
|
+
end.send("to_#{format.downcase}")
|
|
106
106
|
else
|
|
107
107
|
if context_filename = choose_filename('.contexts/*.rb')
|
|
108
108
|
ContextSpook.generate_context(context_filename, verbose: true, format:).
|
|
@@ -156,7 +156,8 @@ module OllamaChat::ModelHandling
|
|
|
156
156
|
model_name ||= @model
|
|
157
157
|
model_options = get_session_model_options
|
|
158
158
|
store_model_options(model_name, model_options, profile:)
|
|
159
|
-
STDOUT.puts "Model options #{italic{profile}} for #{bold{model_name}}
|
|
159
|
+
STDOUT.puts "Model options #{italic{profile}} for #{bold{model_name}} "\
|
|
160
|
+
"were copied from session model options."
|
|
160
161
|
end
|
|
161
162
|
|
|
162
163
|
# Resets the session's model options to match the stored defaults for the
|
|
@@ -169,7 +170,8 @@ module OllamaChat::ModelHandling
|
|
|
169
170
|
model_name ||= @model
|
|
170
171
|
stored_model_options = get_stored_model_options(model_name, profile:)
|
|
171
172
|
session.update(model_options: stored_model_options)
|
|
172
|
-
STDOUT.puts "Model options #{italic{profile}} of #{bold{model_name}}
|
|
173
|
+
STDOUT.puts "Model options #{italic{profile}} of #{bold{model_name}} "\
|
|
174
|
+
"were copied to session model options."
|
|
173
175
|
end
|
|
174
176
|
|
|
175
177
|
# Interactively copies model options from a source model/profile to the
|
|
@@ -181,7 +183,7 @@ module OllamaChat::ModelHandling
|
|
|
181
183
|
src_model = choose_model('', model)
|
|
182
184
|
src_profile = choose_profile_for_model(src_model) || 'default'
|
|
183
185
|
dst_model = model
|
|
184
|
-
dst_profile = choose_profile_for_model(dst_model, allow_new: true
|
|
186
|
+
dst_profile = choose_profile_for_model(dst_model, allow_new: true, suggest: src_profile)
|
|
185
187
|
|
|
186
188
|
src_opts = get_stored_model_options(src_model, profile: src_profile).full? or return
|
|
187
189
|
|
|
@@ -200,7 +202,31 @@ module OllamaChat::ModelHandling
|
|
|
200
202
|
end
|
|
201
203
|
|
|
202
204
|
store_model_options(dst_model, src_opts, profile: dst_profile)
|
|
203
|
-
STDOUT.puts "✅ Copied options from #{italic{src_model}}/#{italic{src_profile}}
|
|
205
|
+
STDOUT.puts "✅ Copied options from #{italic{src_model}}/#{italic{src_profile}} "\
|
|
206
|
+
"to #{bold{dst_model}}/#{italic{dst_profile}}."
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Interactively deletes a stored model options profile.
|
|
210
|
+
#
|
|
211
|
+
# If the deleted profile is the default one, it is replaced with an empty
|
|
212
|
+
# options hash `{}` to ensure the model always has a valid default profile.
|
|
213
|
+
#
|
|
214
|
+
# @param model [String] the model whose profile should be deleted
|
|
215
|
+
def delete_model_options_profile(model)
|
|
216
|
+
profile = choose_profile_for_model(model) or return
|
|
217
|
+
|
|
218
|
+
if confirm?(prompt: "🔔 Really delete profile #{bold{profile}} for #{bold{model}}? (y/n) ", yes: /\Ay/i)
|
|
219
|
+
if profile == 'default'
|
|
220
|
+
store_model_options(model, {}, profile:)
|
|
221
|
+
STDOUT.puts "Default profile #{italic{profile}} for #{bold{model}} has been reset to empty options."
|
|
222
|
+
else
|
|
223
|
+
models::ModelOptions.where(model_name: model, profile:).destroy
|
|
224
|
+
STDOUT.puts "Profile #{italic{profile}} for #{bold{model}} deleted."
|
|
225
|
+
end
|
|
226
|
+
log(:info, "Model options profile deleted", data: { model:, profile: })
|
|
227
|
+
else
|
|
228
|
+
STDOUT.puts "Cancelled."
|
|
229
|
+
end
|
|
204
230
|
end
|
|
205
231
|
|
|
206
232
|
# Presents an interactive list of stored configuration profiles for the
|
|
@@ -212,12 +238,14 @@ module OllamaChat::ModelHandling
|
|
|
212
238
|
#
|
|
213
239
|
# @param model_name [String] the name of the model whose profiles are to be listed
|
|
214
240
|
# @return [String, nil] the selected profile name, or `nil` if none was chosen
|
|
215
|
-
def choose_profile_for_model(model_name, allow_new: false)
|
|
241
|
+
def choose_profile_for_model(model_name, allow_new: false, suggest: nil)
|
|
216
242
|
profiles = models::ModelOptions.where(model_name:).order(:profile).map(&:profile)
|
|
217
243
|
|
|
218
244
|
if allow_new
|
|
245
|
+
profiles.unshift(suggest) if suggest && !profiles.member?(suggest)
|
|
219
246
|
profiles = [ '[EXIT]', '[NEW]' ] + profiles
|
|
220
247
|
else
|
|
248
|
+
profiles.unshift(suggest) if suggest && !profiles.member?(suggest)
|
|
221
249
|
profiles.size < 2 and return profiles.first
|
|
222
250
|
profiles = [ '[EXIT]' ] + profiles
|
|
223
251
|
end
|
|
@@ -173,6 +173,12 @@ prompts:
|
|
|
173
173
|
conversation. Output only the title and nothing else:
|
|
174
174
|
|
|
175
175
|
%{content}
|
|
176
|
+
context_template_suggest: |
|
|
177
|
+
Conversation History:
|
|
178
|
+
%{history}
|
|
179
|
+
|
|
180
|
+
Create and output text following this instruction:
|
|
181
|
+
%{instruction}
|
|
176
182
|
suggest:
|
|
177
183
|
coding: |
|
|
178
184
|
## Context
|
|
@@ -343,9 +349,9 @@ prompts:
|
|
|
343
349
|
%{runtime_info}
|
|
344
350
|
assistant: You are a helpful assistant.
|
|
345
351
|
voice:
|
|
352
|
+
handler: OllamaChat::Say
|
|
346
353
|
enabled: false
|
|
347
354
|
default: Samantha
|
|
348
|
-
list: <%= defined?(RSpec) ? '[]' : `say -v '?' 2>/dev/null`.lines.map { |l| l.force_encoding('ASCII-8BIT'); l[/^(.+?)\s+[a-z]{2}_[a-zA-Z0-9]{2,}/, 1] }.uniq.sort.to_s %>
|
|
349
355
|
roles:
|
|
350
356
|
user: 👨 %{sender_name}
|
|
351
357
|
assistant: 🤖 %{sender_name}
|
|
@@ -88,11 +88,11 @@ module OllamaChat::PromptManagement
|
|
|
88
88
|
# Interactively prompts the user for a name and content (optionally loading
|
|
89
89
|
# from a file) to create a new prompt template.
|
|
90
90
|
#
|
|
91
|
-
# @return [
|
|
91
|
+
# @return [self, nil] self if the prompt was added, nil if the process was
|
|
92
92
|
# cancelled
|
|
93
93
|
def add_new_prompt(context: nil)
|
|
94
94
|
context ||= 'prompt'
|
|
95
|
-
switch_history(:
|
|
95
|
+
switch_history(:prompt) do
|
|
96
96
|
name = determine_valid_new_name_for_prompt('to add', context:) or return
|
|
97
97
|
|
|
98
98
|
sources = %w[ [CLIPBOARD] [FILES] [EMPTY/MANUAL] ]
|
|
@@ -115,7 +115,7 @@ module OllamaChat::PromptManagement
|
|
|
115
115
|
prompt_content = edit_text(content)
|
|
116
116
|
store_prompt(name, prompt_content, context:)
|
|
117
117
|
log(:info, "Prompt added", data: { name:, context: })
|
|
118
|
-
|
|
118
|
+
self
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
121
|
|
|
@@ -165,31 +165,75 @@ module OllamaChat::PromptManagement
|
|
|
165
165
|
# cancelled the operation or no prompt was selected.
|
|
166
166
|
def duplicate_prompt(context: nil)
|
|
167
167
|
context ||= 'prompt'
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
name = nil
|
|
173
|
-
loop do
|
|
174
|
-
name = ask?(
|
|
175
|
-
prompt: "❓ Enter new prompt name to duplicate as, C-c ⇒ cancel: "
|
|
168
|
+
switch_history(:prompt) do
|
|
169
|
+
selected_prompt = choose_prompt(context:, prompt: 'Which prompt shall be the basis for a new one? %s') or return
|
|
170
|
+
STDOUT.puts kramdown_ansi_parse(
|
|
171
|
+
selected_prompt.to_s + "\n---"
|
|
176
172
|
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
173
|
+
name = nil
|
|
174
|
+
loop do
|
|
175
|
+
name = ask?(
|
|
176
|
+
prompt: "❓ Enter new prompt name to duplicate as, C-c ⇒ cancel: "
|
|
177
|
+
)
|
|
178
|
+
if name.nil?
|
|
179
|
+
STDOUT.puts "Cancelled."
|
|
180
|
+
return nil
|
|
181
|
+
end
|
|
182
|
+
if prompt(name, context:)
|
|
183
|
+
STDOUT.puts "Prompt named #{bold{name}} already exists."
|
|
184
|
+
else
|
|
185
|
+
break
|
|
186
|
+
end
|
|
180
187
|
end
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
duplicated_prompt = selected_prompt.duplicate
|
|
189
|
+
duplicated_prompt.name = name
|
|
190
|
+
duplicated_prompt.metadata['default'] = false
|
|
191
|
+
duplicated_prompt.save
|
|
192
|
+
log(:info, "Prompt duplicated", data: { name:, old_name: selected_prompt.name, context: })
|
|
193
|
+
self
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Interactively selects an existing prompt and renames it.
|
|
198
|
+
#
|
|
199
|
+
# @return [self, nil] the current context on success, or nil if the user
|
|
200
|
+
# cancelled the operation or no prompt was selected.
|
|
201
|
+
def rename_prompt(context: nil)
|
|
202
|
+
context ||= 'prompt'
|
|
203
|
+
switch_history(:prompt) do
|
|
204
|
+
selected_prompt = choose_prompt(
|
|
205
|
+
prompt: 'Which prompt would you like to rename? %s',
|
|
206
|
+
context:
|
|
207
|
+
) or return
|
|
208
|
+
|
|
209
|
+
STDOUT.puts kramdown_ansi_parse(
|
|
210
|
+
selected_prompt.to_s + "\n---"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
name = nil
|
|
214
|
+
loop do
|
|
215
|
+
name = ask?(
|
|
216
|
+
prompt: "❓ Enter new prompt name, C-c ⇒ cancel: "
|
|
217
|
+
)
|
|
218
|
+
if name.nil?
|
|
219
|
+
STDOUT.puts "Cancelled."
|
|
220
|
+
return nil
|
|
221
|
+
end
|
|
222
|
+
if name == selected_prompt.name
|
|
223
|
+
STDOUT.puts "That is the current name."
|
|
224
|
+
elsif prompt(name, context:)
|
|
225
|
+
STDOUT.puts "Prompt named #{bold{name}} already exists."
|
|
226
|
+
else
|
|
227
|
+
break
|
|
228
|
+
end
|
|
185
229
|
end
|
|
230
|
+
|
|
231
|
+
old_name = selected_prompt.name
|
|
232
|
+
selected_prompt.name = name
|
|
233
|
+
selected_prompt.save
|
|
234
|
+
log(:info, "Prompt renamed", data: { old_name:, new_name: name, context: })
|
|
235
|
+
self
|
|
186
236
|
end
|
|
187
|
-
duplicated_prompt = selected_prompt.duplicate
|
|
188
|
-
duplicated_prompt.name = name
|
|
189
|
-
duplicated_prompt.metadata['default'] = false
|
|
190
|
-
duplicated_prompt.save
|
|
191
|
-
log(:info, "Prompt duplicated", data: { name:, old_name: selected_prompt.name, context: })
|
|
192
|
-
self
|
|
193
237
|
end
|
|
194
238
|
|
|
195
239
|
# Interactively imports a prompt from a file.
|
|
@@ -294,16 +338,11 @@ module OllamaChat::PromptManagement
|
|
|
294
338
|
|
|
295
339
|
# Build the context by gathering all current conversation messages
|
|
296
340
|
history = prepare_conversation_history
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
#{history}
|
|
300
|
-
|
|
301
|
-
Instruction:
|
|
302
|
-
#{instruction}
|
|
303
|
-
EOT
|
|
341
|
+
template = prompt('context_template_suggest', context: 'prompt').to_s
|
|
342
|
+
full_prompt = template % { history:, instruction: }
|
|
304
343
|
|
|
305
344
|
# Execute a silent chat oneshot call (doesn't add to history)
|
|
306
|
-
suggestions
|
|
345
|
+
suggestions = generate(prompt: full_prompt).full? or return
|
|
307
346
|
|
|
308
347
|
# Pass the AI's suggestions through the editor for final refinement
|
|
309
348
|
edit_text(suggestions)
|
|
@@ -366,21 +405,23 @@ module OllamaChat::PromptManagement
|
|
|
366
405
|
# the operation was cancelled.
|
|
367
406
|
def determine_valid_new_name_for_prompt(action, context: nil)
|
|
368
407
|
context ||= 'prompt'
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
408
|
+
switch_history(:prompt) do
|
|
409
|
+
prompt_name = nil
|
|
410
|
+
loop do
|
|
411
|
+
prompt_name = ask?(
|
|
412
|
+
prompt: "❓ Enter new prompt name #{action}, C-c ⇒ cancel: "
|
|
413
|
+
)
|
|
414
|
+
if prompt_name.nil?
|
|
415
|
+
STDOUT.puts "Cancelled."
|
|
416
|
+
return nil
|
|
417
|
+
end
|
|
418
|
+
if prompt(prompt_name, context:)
|
|
419
|
+
STDOUT.puts "Prompt named #{bold{prompt_name}} already exists."
|
|
420
|
+
else
|
|
421
|
+
break
|
|
422
|
+
end
|
|
382
423
|
end
|
|
424
|
+
prompt_name
|
|
383
425
|
end
|
|
384
|
-
prompt_name
|
|
385
426
|
end
|
|
386
427
|
end
|
|
@@ -219,15 +219,16 @@ module OllamaChat::RAGHandling
|
|
|
219
219
|
end
|
|
220
220
|
end
|
|
221
221
|
|
|
222
|
-
# Extracts and normalizes file patterns from a
|
|
222
|
+
# Extracts and normalizes file patterns from a shell-style string.
|
|
223
223
|
#
|
|
224
|
-
# Splits the input string
|
|
225
|
-
#
|
|
224
|
+
# Splits the input string using shell semantics, correctly handling
|
|
225
|
+
# spaces enclosed in single/double quotes or escaped with backslashes.
|
|
226
|
+
# Each resulting pattern is expanded to an absolute path.
|
|
226
227
|
#
|
|
227
|
-
# @param patterns_str [String, nil] the
|
|
228
|
+
# @param patterns_str [String, nil] the shell-style glob patterns
|
|
228
229
|
# @return [Array<String>] an array of expanded absolute path patterns
|
|
229
230
|
def extract_patterns(patterns_str)
|
|
230
|
-
patterns =
|
|
231
|
+
patterns = Shellwords.split(patterns_str.to_s)
|
|
231
232
|
patterns.map { File.expand_path(_1) }
|
|
232
233
|
end
|
|
233
234
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# A handler that uses the system's say command to speak response content.
|
|
2
|
+
#
|
|
3
|
+
# This class extends Ollama::Handlers::Say to provide voice validation
|
|
4
|
+
# against the system's available voices. It ensures that only valid voices
|
|
5
|
+
# are used, falling back to nil if an invalid voice is specified.
|
|
6
|
+
#
|
|
7
|
+
# @example Using the Say handler
|
|
8
|
+
# OllamaChat::Say.new(chat: chat, voice: 'Samantha')
|
|
9
|
+
class OllamaChat::Say < Ollama::Handlers::Say
|
|
10
|
+
# Returns a list of available system voices.
|
|
11
|
+
#
|
|
12
|
+
# This method queries the system's `say` command to retrieve the list of
|
|
13
|
+
# available voices. If running within RSpec, it returns an empty array to
|
|
14
|
+
# avoid side effects during testing.
|
|
15
|
+
#
|
|
16
|
+
# @return [Array<String>] a sorted list of unique voice identifiers
|
|
17
|
+
def self.voices
|
|
18
|
+
`say -v '?' 2>/dev/null`.lines.map { |l| l[/^(.+?)\s+[a-z]{2}_[a-zA-Z0-9]{2,}/, 1] }.uniq.sort
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Initializes a new Say handler.
|
|
22
|
+
#
|
|
23
|
+
# @param chat [OllamaChat::Chat] the chat instance
|
|
24
|
+
# @param voice [String, nil] the voice to use (must be in the list of available voices)
|
|
25
|
+
def initialize(chat:, voice: nil)
|
|
26
|
+
voice && self.class.voices.member?(voice) or voice = nil
|
|
27
|
+
@chat = chat
|
|
28
|
+
super(voice:)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -269,11 +269,12 @@ module OllamaChat::StateSelectors
|
|
|
269
269
|
states: OllamaChat::ThinkControl::THINK_MODE_STATES,
|
|
270
270
|
off: OllamaChat::ThinkControl::THINK_MODE_STATES[0, 1],
|
|
271
271
|
)
|
|
272
|
+
list = voice_handler.ask_and_send(:voices) || []
|
|
272
273
|
@voices = DatabaseStateSelector.new(
|
|
273
274
|
chat: self,
|
|
274
275
|
attribute: :current_voice,
|
|
275
276
|
name: 'Voice',
|
|
276
|
-
states:
|
|
277
|
+
states: list,
|
|
277
278
|
allow_empty: true
|
|
278
279
|
)
|
|
279
280
|
@context_format = DatabaseStateSelector.new(
|
|
@@ -76,6 +76,22 @@ class OllamaChat::Tools::WriteFile
|
|
|
76
76
|
|
|
77
77
|
es = OllamaChat::TokenEstimator.estimate(args.content)
|
|
78
78
|
|
|
79
|
+
# Confirm overwrite if file already exists
|
|
80
|
+
if path.exist? && (args.mode == 'overwrite' || args.mode.nil?)
|
|
81
|
+
unless chat.confirm?(prompt: "File #{path.to_s.inspect} already exists. Overwrite? (y/N): ", yes: /\Ay/i)
|
|
82
|
+
raise OllamaChat::ToolFunctionArgumentError,
|
|
83
|
+
"Write rejected: File #{path.to_s.inspect} already exists and was not overwritten."
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Confirm creation if file doesn't exist in append mode
|
|
88
|
+
if !path.exist? && args.mode == 'append'
|
|
89
|
+
unless chat.confirm?(prompt: "File #{path.to_s.inspect} does not exist. Create it? (y/N): ", yes: /\Ay/i)
|
|
90
|
+
raise OllamaChat::ToolFunctionArgumentError,
|
|
91
|
+
"Write rejected: File #{path.to_s.inspect} does not exist and was not created."
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
79
95
|
backup_path = nil
|
|
80
96
|
|
|
81
97
|
content = args.content
|
data/lib/ollama_chat/version.rb
CHANGED
data/lib/ollama_chat.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.107 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.107".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]
|
|
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.description = "The app provides a command-line interface (CLI) to an Ollama AI model,\nallowing users to engage in text-based conversations and generate\nhuman-like responses. Users can import data from local files or web pages,\nwhich are then processed through three different modes: fully importing the\ncontent into the conversation context, summarizing the information for\nconcise reference, or storing it in an embedding vector database for later\nretrieval based on the conversation.\n".freeze
|
|
13
13
|
s.email = "flori@ping.de".freeze
|
|
14
14
|
s.executables = ["ollama_chat".freeze, "ollama_chat_send".freeze, "ollama_chat_log".freeze]
|
|
15
|
-
s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/session_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/directory_structure.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/file_context.rb".freeze, "lib/ollama_chat/tools/gem_path_lookup.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
|
|
16
|
-
s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_log".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "config/sherlock.md".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/session_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/directory_structure.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/file_context.rb".freeze, "lib/ollama_chat/tools/gem_path_lookup.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/conversation.jsonl".freeze, "spec/assets/deep/deeper/empty.txt".freeze, "spec/assets/deep/deeper/not-empty.txt".freeze, "spec/assets/deep/empty.txt".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.epub".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/example_with_quote.html".freeze, "spec/assets/fluffy.png".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/miyu.png".freeze, "spec/assets/pirateweather.json".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/commands_spec.rb".freeze, "spec/ollama_chat/database/models/favourite_spec.rb".freeze, "spec/ollama_chat/file_editing_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/history_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/input_content_spec.rb".freeze, "spec/ollama_chat/kramdown_ansi_spec.rb".freeze, "spec/ollama_chat/message_editing_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/redis_cache_spec.rb".freeze, "spec/ollama_chat/server_socket_spec.rb".freeze, "spec/ollama_chat/session_management_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/state_selectors_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/think_control_spec.rb".freeze, "spec/ollama_chat/token_estimator_spec.rb".freeze, "spec/ollama_chat/tool_calling_spec.rb".freeze, "spec/ollama_chat/tools/browse_spec.rb".freeze, "spec/ollama_chat/tools/compute_bmi_spec.rb".freeze, "spec/ollama_chat/tools/copy_to_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/delete_file_spec.rb".freeze, "spec/ollama_chat/tools/directory_structure_spec.rb".freeze, "spec/ollama_chat/tools/execute_grep_spec.rb".freeze, "spec/ollama_chat/tools/execute_ri_spec.rb".freeze, "spec/ollama_chat/tools/file_context_spec.rb".freeze, "spec/ollama_chat/tools/gem_path_lookup_spec.rb".freeze, "spec/ollama_chat/tools/generate_image_spec.rb".freeze, "spec/ollama_chat/tools/generate_password_spec.rb".freeze, "spec/ollama_chat/tools/get_current_weather_spec.rb".freeze, "spec/ollama_chat/tools/get_cve_spec.rb".freeze, "spec/ollama_chat/tools/get_endoflife_spec.rb".freeze, "spec/ollama_chat/tools/get_ghr_spec.rb".freeze, "spec/ollama_chat/tools/get_jira_issue_spec.rb".freeze, "spec/ollama_chat/tools/get_location_spec.rb".freeze, "spec/ollama_chat/tools/get_rfc_spec.rb".freeze, "spec/ollama_chat/tools/get_time_spec.rb".freeze, "spec/ollama_chat/tools/get_url_spec.rb".freeze, "spec/ollama_chat/tools/move_file_spec.rb".freeze, "spec/ollama_chat/tools/open_file_in_editor_spec.rb".freeze, "spec/ollama_chat/tools/paste_from_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/paste_into_editor_spec.rb".freeze, "spec/ollama_chat/tools/patch_file_spec.rb".freeze, "spec/ollama_chat/tools/read_file_spec.rb".freeze, "spec/ollama_chat/tools/resolve_tag_spec.rb".freeze, "spec/ollama_chat/tools/roll_dice_spec.rb".freeze, "spec/ollama_chat/tools/run_tests_spec.rb".freeze, "spec/ollama_chat/tools/search_knowledge_spec.rb".freeze, "spec/ollama_chat/tools/search_web_spec.rb".freeze, "spec/ollama_chat/tools/write_file_spec.rb".freeze, "spec/ollama_chat/utils/analyze_directory_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/log_viewer_spec.rb".freeze, "spec/ollama_chat/utils/path_completer_spec.rb".freeze, "spec/ollama_chat/utils/png_metadata_extractor_spec.rb".freeze, "spec/ollama_chat/vim_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
|
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/session_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/directory_structure.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/file_context.rb".freeze, "lib/ollama_chat/tools/gem_path_lookup.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze]
|
|
16
|
+
s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/ollama_chat".freeze, "bin/ollama_chat_log".freeze, "bin/ollama_chat_send".freeze, "config/searxng/settings.yml".freeze, "config/sherlock.md".freeze, "docker-compose.yml".freeze, "lib/ollama_chat.rb".freeze, "lib/ollama_chat/chat.rb".freeze, "lib/ollama_chat/clipboard.rb".freeze, "lib/ollama_chat/command_concern.rb".freeze, "lib/ollama_chat/commands.rb".freeze, "lib/ollama_chat/config_handling.rb".freeze, "lib/ollama_chat/conversation.rb".freeze, "lib/ollama_chat/database.rb".freeze, "lib/ollama_chat/database/duplicatable.rb".freeze, "lib/ollama_chat/database/migrations.rb".freeze, "lib/ollama_chat/database/migrations/001_initial_schema.rb".freeze, "lib/ollama_chat/database/migrations/002_add_links_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/003_add_history_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/004_add_profile_to_model_options.rb".freeze, "lib/ollama_chat/database/migrations/005_add_context_format_to_sessions.rb".freeze, "lib/ollama_chat/database/migrations/006_rename_system_prompt_context_to_system.rb".freeze, "lib/ollama_chat/database/migrations/007_add_collections_table.rb".freeze, "lib/ollama_chat/database/models/collection.rb".freeze, "lib/ollama_chat/database/models/favourite.rb".freeze, "lib/ollama_chat/database/models/model_options.rb".freeze, "lib/ollama_chat/database/models/prompt.rb".freeze, "lib/ollama_chat/database/models/session.rb".freeze, "lib/ollama_chat/database/session_locking.rb".freeze, "lib/ollama_chat/dialog.rb".freeze, "lib/ollama_chat/document_cache.rb".freeze, "lib/ollama_chat/favourites_management.rb".freeze, "lib/ollama_chat/file_editing.rb".freeze, "lib/ollama_chat/follow_chat.rb".freeze, "lib/ollama_chat/history.rb".freeze, "lib/ollama_chat/http_handling.rb".freeze, "lib/ollama_chat/information.rb".freeze, "lib/ollama_chat/input_content.rb".freeze, "lib/ollama_chat/kramdown_ansi.rb".freeze, "lib/ollama_chat/links_set.rb".freeze, "lib/ollama_chat/location_handling.rb".freeze, "lib/ollama_chat/logging.rb".freeze, "lib/ollama_chat/message.rb".freeze, "lib/ollama_chat/message_editing.rb".freeze, "lib/ollama_chat/message_format.rb".freeze, "lib/ollama_chat/message_list.rb".freeze, "lib/ollama_chat/message_output.rb".freeze, "lib/ollama_chat/model_handling.rb".freeze, "lib/ollama_chat/oc.rb".freeze, "lib/ollama_chat/ollama_chat_config.rb".freeze, "lib/ollama_chat/ollama_chat_config/default_config.yml".freeze, "lib/ollama_chat/pager.rb".freeze, "lib/ollama_chat/parsing.rb".freeze, "lib/ollama_chat/personae_management.rb".freeze, "lib/ollama_chat/prompt_handling.rb".freeze, "lib/ollama_chat/prompt_management.rb".freeze, "lib/ollama_chat/rag_handling.rb".freeze, "lib/ollama_chat/redis_cache.rb".freeze, "lib/ollama_chat/say.rb".freeze, "lib/ollama_chat/server_socket.rb".freeze, "lib/ollama_chat/session_management.rb".freeze, "lib/ollama_chat/source_fetching.rb".freeze, "lib/ollama_chat/state_selectors.rb".freeze, "lib/ollama_chat/switches.rb".freeze, "lib/ollama_chat/system_prompt_management.rb".freeze, "lib/ollama_chat/think_control.rb".freeze, "lib/ollama_chat/token_estimator.rb".freeze, "lib/ollama_chat/token_estimator/crude.rb".freeze, "lib/ollama_chat/tool_calling.rb".freeze, "lib/ollama_chat/tools.rb".freeze, "lib/ollama_chat/tools/browse.rb".freeze, "lib/ollama_chat/tools/compute_bmi.rb".freeze, "lib/ollama_chat/tools/concern.rb".freeze, "lib/ollama_chat/tools/copy_to_clipboard.rb".freeze, "lib/ollama_chat/tools/delete_file.rb".freeze, "lib/ollama_chat/tools/directory_structure.rb".freeze, "lib/ollama_chat/tools/eval_ruby.rb".freeze, "lib/ollama_chat/tools/execute_grep.rb".freeze, "lib/ollama_chat/tools/execute_ri.rb".freeze, "lib/ollama_chat/tools/file_context.rb".freeze, "lib/ollama_chat/tools/gem_path_lookup.rb".freeze, "lib/ollama_chat/tools/generate_image.rb".freeze, "lib/ollama_chat/tools/generate_password.rb".freeze, "lib/ollama_chat/tools/get_current_weather.rb".freeze, "lib/ollama_chat/tools/get_cve.rb".freeze, "lib/ollama_chat/tools/get_endoflife.rb".freeze, "lib/ollama_chat/tools/get_ghr.rb".freeze, "lib/ollama_chat/tools/get_jira_issue.rb".freeze, "lib/ollama_chat/tools/get_location.rb".freeze, "lib/ollama_chat/tools/get_rfc.rb".freeze, "lib/ollama_chat/tools/get_time.rb".freeze, "lib/ollama_chat/tools/get_url.rb".freeze, "lib/ollama_chat/tools/move_file.rb".freeze, "lib/ollama_chat/tools/open_file_in_editor.rb".freeze, "lib/ollama_chat/tools/paste_from_clipboard.rb".freeze, "lib/ollama_chat/tools/paste_into_editor.rb".freeze, "lib/ollama_chat/tools/patch_file.rb".freeze, "lib/ollama_chat/tools/read_file.rb".freeze, "lib/ollama_chat/tools/resolve_tag.rb".freeze, "lib/ollama_chat/tools/roll_dice.rb".freeze, "lib/ollama_chat/tools/run_tests.rb".freeze, "lib/ollama_chat/tools/search_knowledge.rb".freeze, "lib/ollama_chat/tools/search_web.rb".freeze, "lib/ollama_chat/tools/write_file.rb".freeze, "lib/ollama_chat/utils.rb".freeze, "lib/ollama_chat/utils/analyze_directory.rb".freeze, "lib/ollama_chat/utils/backup.rb".freeze, "lib/ollama_chat/utils/cache_fetcher.rb".freeze, "lib/ollama_chat/utils/chooser.rb".freeze, "lib/ollama_chat/utils/fetcher.rb".freeze, "lib/ollama_chat/utils/json_jsonl_io.rb".freeze, "lib/ollama_chat/utils/log_viewer.rb".freeze, "lib/ollama_chat/utils/path_completer.rb".freeze, "lib/ollama_chat/utils/path_validator.rb".freeze, "lib/ollama_chat/utils/png_metadata_extractor.rb".freeze, "lib/ollama_chat/utils/tag_resolver.rb".freeze, "lib/ollama_chat/utils/utf8_converter.rb".freeze, "lib/ollama_chat/utils/value_formatter.rb".freeze, "lib/ollama_chat/uuid_v7.rb".freeze, "lib/ollama_chat/version.rb".freeze, "lib/ollama_chat/vim.rb".freeze, "lib/ollama_chat/web_searching.rb".freeze, "ollama_chat.gemspec".freeze, "redis/redis.conf".freeze, "spec/assets/api_show.json".freeze, "spec/assets/api_tags.json".freeze, "spec/assets/api_version.json".freeze, "spec/assets/conversation.json".freeze, "spec/assets/conversation.jsonl".freeze, "spec/assets/deep/deeper/empty.txt".freeze, "spec/assets/deep/deeper/not-empty.txt".freeze, "spec/assets/deep/empty.txt".freeze, "spec/assets/duckduckgo.html".freeze, "spec/assets/example.atom".freeze, "spec/assets/example.csv".freeze, "spec/assets/example.epub".freeze, "spec/assets/example.html".freeze, "spec/assets/example.pdf".freeze, "spec/assets/example.ps".freeze, "spec/assets/example.rb".freeze, "spec/assets/example.rss".freeze, "spec/assets/example.xml".freeze, "spec/assets/example_with_quote.html".freeze, "spec/assets/fluffy.png".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/miyu.png".freeze, "spec/assets/pirateweather.json".freeze, "spec/assets/prompt.txt".freeze, "spec/assets/searxng.json".freeze, "spec/ollama_chat/chat_spec.rb".freeze, "spec/ollama_chat/clipboard_spec.rb".freeze, "spec/ollama_chat/commands_spec.rb".freeze, "spec/ollama_chat/database/models/favourite_spec.rb".freeze, "spec/ollama_chat/file_editing_spec.rb".freeze, "spec/ollama_chat/follow_chat_spec.rb".freeze, "spec/ollama_chat/history_spec.rb".freeze, "spec/ollama_chat/information_spec.rb".freeze, "spec/ollama_chat/input_content_spec.rb".freeze, "spec/ollama_chat/kramdown_ansi_spec.rb".freeze, "spec/ollama_chat/message_editing_spec.rb".freeze, "spec/ollama_chat/message_list_spec.rb".freeze, "spec/ollama_chat/message_output_spec.rb".freeze, "spec/ollama_chat/model_handling_spec.rb".freeze, "spec/ollama_chat/parsing_spec.rb".freeze, "spec/ollama_chat/redis_cache_spec.rb".freeze, "spec/ollama_chat/server_socket_spec.rb".freeze, "spec/ollama_chat/session_management_spec.rb".freeze, "spec/ollama_chat/source_fetching_spec.rb".freeze, "spec/ollama_chat/state_selectors_spec.rb".freeze, "spec/ollama_chat/switches_spec.rb".freeze, "spec/ollama_chat/think_control_spec.rb".freeze, "spec/ollama_chat/token_estimator_spec.rb".freeze, "spec/ollama_chat/tool_calling_spec.rb".freeze, "spec/ollama_chat/tools/browse_spec.rb".freeze, "spec/ollama_chat/tools/compute_bmi_spec.rb".freeze, "spec/ollama_chat/tools/copy_to_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/delete_file_spec.rb".freeze, "spec/ollama_chat/tools/directory_structure_spec.rb".freeze, "spec/ollama_chat/tools/execute_grep_spec.rb".freeze, "spec/ollama_chat/tools/execute_ri_spec.rb".freeze, "spec/ollama_chat/tools/file_context_spec.rb".freeze, "spec/ollama_chat/tools/gem_path_lookup_spec.rb".freeze, "spec/ollama_chat/tools/generate_image_spec.rb".freeze, "spec/ollama_chat/tools/generate_password_spec.rb".freeze, "spec/ollama_chat/tools/get_current_weather_spec.rb".freeze, "spec/ollama_chat/tools/get_cve_spec.rb".freeze, "spec/ollama_chat/tools/get_endoflife_spec.rb".freeze, "spec/ollama_chat/tools/get_ghr_spec.rb".freeze, "spec/ollama_chat/tools/get_jira_issue_spec.rb".freeze, "spec/ollama_chat/tools/get_location_spec.rb".freeze, "spec/ollama_chat/tools/get_rfc_spec.rb".freeze, "spec/ollama_chat/tools/get_time_spec.rb".freeze, "spec/ollama_chat/tools/get_url_spec.rb".freeze, "spec/ollama_chat/tools/move_file_spec.rb".freeze, "spec/ollama_chat/tools/open_file_in_editor_spec.rb".freeze, "spec/ollama_chat/tools/paste_from_clipboard_spec.rb".freeze, "spec/ollama_chat/tools/paste_into_editor_spec.rb".freeze, "spec/ollama_chat/tools/patch_file_spec.rb".freeze, "spec/ollama_chat/tools/read_file_spec.rb".freeze, "spec/ollama_chat/tools/resolve_tag_spec.rb".freeze, "spec/ollama_chat/tools/roll_dice_spec.rb".freeze, "spec/ollama_chat/tools/run_tests_spec.rb".freeze, "spec/ollama_chat/tools/search_knowledge_spec.rb".freeze, "spec/ollama_chat/tools/search_web_spec.rb".freeze, "spec/ollama_chat/tools/write_file_spec.rb".freeze, "spec/ollama_chat/utils/analyze_directory_spec.rb".freeze, "spec/ollama_chat/utils/cache_fetcher_spec.rb".freeze, "spec/ollama_chat/utils/fetcher_spec.rb".freeze, "spec/ollama_chat/utils/log_viewer_spec.rb".freeze, "spec/ollama_chat/utils/path_completer_spec.rb".freeze, "spec/ollama_chat/utils/png_metadata_extractor_spec.rb".freeze, "spec/ollama_chat/vim_spec.rb".freeze, "spec/ollama_chat/web_searching_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tmp/.keep".freeze]
|
|
17
17
|
s.homepage = "https://github.com/flori/ollama_chat".freeze
|
|
18
18
|
s.licenses = ["MIT".freeze]
|
|
19
19
|
s.rdoc_options = ["--title".freeze, "OllamaChat - A command-line interface (CLI) for interacting with an Ollama AI model.".freeze, "--main".freeze, "README.md".freeze]
|
|
@@ -475,13 +475,13 @@ describe OllamaChat::Commands, protect_env: true do
|
|
|
475
475
|
|
|
476
476
|
describe 'conversation' do
|
|
477
477
|
it 'returns :next when input is "/conversation save\\s+(.+)$"' do
|
|
478
|
-
expect(chat).to receive(:save_conversation).with('./some_file', clean: false)
|
|
479
|
-
expect(chat.handle_input("/conversation save ./some_file")).to eq :next
|
|
478
|
+
expect(chat).to receive(:save_conversation).with('./some_file.jsonl', clean: false)
|
|
479
|
+
expect(chat.handle_input("/conversation save ./some_file.jsonl")).to eq :next
|
|
480
480
|
end
|
|
481
481
|
|
|
482
|
-
it 'returns :next when input is "/conversation save -c ./some_file"' do
|
|
483
|
-
expect(chat).to receive(:save_conversation).with('./some_file', clean: 1)
|
|
484
|
-
expect(chat.handle_input("/conversation save -c ./some_file")).to eq :next
|
|
482
|
+
it 'returns :next when input is "/conversation save -c ./some_file.jsonl"' do
|
|
483
|
+
expect(chat).to receive(:save_conversation).with('./some_file.jsonl', clean: 1)
|
|
484
|
+
expect(chat.handle_input("/conversation save -c ./some_file.jsonl")).to eq :next
|
|
485
485
|
end
|
|
486
486
|
|
|
487
487
|
it 'returns :next when input is "/conversation save" without path' do
|
|
@@ -490,8 +490,8 @@ describe OllamaChat::Commands, protect_env: true do
|
|
|
490
490
|
end
|
|
491
491
|
|
|
492
492
|
it 'returns :next when input is "/conversation load\\s+(.+)$"' do
|
|
493
|
-
expect(chat).to receive(:load_conversation).with('./some_file')
|
|
494
|
-
expect(chat.handle_input("/conversation load ./some_file")).to eq :next
|
|
493
|
+
expect(chat).to receive(:load_conversation).with('./some_file.jsonl')
|
|
494
|
+
expect(chat.handle_input("/conversation load ./some_file.jsonl")).to eq :next
|
|
495
495
|
end
|
|
496
496
|
|
|
497
497
|
it 'returns :next when input is "/conversation load" without path' do
|
|
@@ -21,7 +21,7 @@ describe OllamaChat::Tools::WriteFile do
|
|
|
21
21
|
"./tmp/test_write_file_#{Tins::Token.new(bits: 128)}.txt"
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
it 'can be executed successfully with overwrite mode' do
|
|
24
|
+
it 'can be executed successfully with overwrite mode on new file' do
|
|
25
25
|
tool_call = double(
|
|
26
26
|
'ToolCall',
|
|
27
27
|
function: double(
|
|
@@ -51,7 +51,62 @@ describe OllamaChat::Tools::WriteFile do
|
|
|
51
51
|
File.delete(test_write_file) if File.exist?(test_write_file)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
it 'can be executed successfully with
|
|
54
|
+
it 'can be executed successfully with overwrite mode on existing file with confirmation' do
|
|
55
|
+
# Pre-create the file
|
|
56
|
+
File.write(test_write_file, 'Old content')
|
|
57
|
+
|
|
58
|
+
expect(chat).to receive(:confirm?).and_return(true)
|
|
59
|
+
|
|
60
|
+
tool_call = double(
|
|
61
|
+
'ToolCall',
|
|
62
|
+
function: double(
|
|
63
|
+
name: 'write_file',
|
|
64
|
+
arguments: double(
|
|
65
|
+
path: test_write_file,
|
|
66
|
+
content: 'New content',
|
|
67
|
+
mode: 'overwrite'
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
result = described_class.new.execute(tool_call, chat:)
|
|
73
|
+
|
|
74
|
+
json = json_object(result)
|
|
75
|
+
expect(json.success).to eq true
|
|
76
|
+
expect(File.read(test_write_file)).to eq 'New content'
|
|
77
|
+
ensure
|
|
78
|
+
File.delete(test_write_file) if File.exist?(test_write_file)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'rejects overwrite when user declines confirmation' do
|
|
82
|
+
# Pre-create the file
|
|
83
|
+
File.write(test_write_file, 'Old content')
|
|
84
|
+
|
|
85
|
+
expect(chat).to receive(:confirm?).and_return(false)
|
|
86
|
+
|
|
87
|
+
tool_call = double(
|
|
88
|
+
'ToolCall',
|
|
89
|
+
function: double(
|
|
90
|
+
name: 'write_file',
|
|
91
|
+
arguments: double(
|
|
92
|
+
path: test_write_file,
|
|
93
|
+
content: 'New content',
|
|
94
|
+
mode: 'overwrite'
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
result = described_class.new.execute(tool_call, chat:)
|
|
100
|
+
|
|
101
|
+
json = json_object(result)
|
|
102
|
+
expect(json.error).to eq 'OllamaChat::ToolFunctionArgumentError'
|
|
103
|
+
expect(json.message).to include('Write rejected')
|
|
104
|
+
expect(File.read(test_write_file)).to eq 'Old content'
|
|
105
|
+
ensure
|
|
106
|
+
File.delete(test_write_file) if File.exist?(test_write_file)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'can be executed successfully with append mode on existing file' do
|
|
55
110
|
# First write some initial content
|
|
56
111
|
initial_content = 'Initial content\n'
|
|
57
112
|
File.secure_write(test_write_file, initial_content)
|
|
@@ -87,6 +142,53 @@ describe OllamaChat::Tools::WriteFile do
|
|
|
87
142
|
File.delete(test_write_file) if File.exist?(test_write_file)
|
|
88
143
|
end
|
|
89
144
|
|
|
145
|
+
it 'can be executed successfully with append mode on new file with confirmation' do
|
|
146
|
+
expect(chat).to receive(:confirm?).and_return(true)
|
|
147
|
+
|
|
148
|
+
tool_call = double(
|
|
149
|
+
'ToolCall',
|
|
150
|
+
function: double(
|
|
151
|
+
name: 'write_file',
|
|
152
|
+
arguments: double(
|
|
153
|
+
path: test_write_file,
|
|
154
|
+
content: 'First content\n',
|
|
155
|
+
mode: 'append'
|
|
156
|
+
)
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
result = described_class.new.execute(tool_call, chat:)
|
|
161
|
+
|
|
162
|
+
json = json_object(result)
|
|
163
|
+
expect(json.success).to eq true
|
|
164
|
+
expect(File.read(test_write_file)).to eq 'First content\n'
|
|
165
|
+
ensure
|
|
166
|
+
File.delete(test_write_file) if File.exist?(test_write_file)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'rejects append when user declines confirmation for new file' do
|
|
170
|
+
expect(chat).to receive(:confirm?).and_return(false)
|
|
171
|
+
|
|
172
|
+
tool_call = double(
|
|
173
|
+
'ToolCall',
|
|
174
|
+
function: double(
|
|
175
|
+
name: 'write_file',
|
|
176
|
+
arguments: double(
|
|
177
|
+
path: test_write_file,
|
|
178
|
+
content: 'First content\n',
|
|
179
|
+
mode: 'append'
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
result = described_class.new.execute(tool_call, chat:)
|
|
185
|
+
|
|
186
|
+
json = json_object(result)
|
|
187
|
+
expect(json.error).to eq 'OllamaChat::ToolFunctionArgumentError'
|
|
188
|
+
expect(json.message).to include('Write rejected')
|
|
189
|
+
expect(File.exist?(test_write_file)).to be false
|
|
190
|
+
end
|
|
191
|
+
|
|
90
192
|
it 'can handle execution errors gracefully when path is not allowed' do
|
|
91
193
|
tool_call = double(
|
|
92
194
|
'ToolCall',
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ollama_chat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.107
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
@@ -530,6 +530,7 @@ extra_rdoc_files:
|
|
|
530
530
|
- lib/ollama_chat/prompt_management.rb
|
|
531
531
|
- lib/ollama_chat/rag_handling.rb
|
|
532
532
|
- lib/ollama_chat/redis_cache.rb
|
|
533
|
+
- lib/ollama_chat/say.rb
|
|
533
534
|
- lib/ollama_chat/server_socket.rb
|
|
534
535
|
- lib/ollama_chat/session_management.rb
|
|
535
536
|
- lib/ollama_chat/source_fetching.rb
|
|
@@ -658,6 +659,7 @@ files:
|
|
|
658
659
|
- lib/ollama_chat/prompt_management.rb
|
|
659
660
|
- lib/ollama_chat/rag_handling.rb
|
|
660
661
|
- lib/ollama_chat/redis_cache.rb
|
|
662
|
+
- lib/ollama_chat/say.rb
|
|
661
663
|
- lib/ollama_chat/server_socket.rb
|
|
662
664
|
- lib/ollama_chat/session_management.rb
|
|
663
665
|
- lib/ollama_chat/source_fetching.rb
|