ollama_chat 0.0.77 → 0.0.79

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +73 -0
  3. data/README.md +1 -9
  4. data/Rakefile +2 -2
  5. data/lib/ollama_chat/chat.rb +9 -20
  6. data/lib/ollama_chat/clipboard.rb +0 -1
  7. data/lib/ollama_chat/dialog.rb +3 -1
  8. data/lib/ollama_chat/document_cache.rb +1 -1
  9. data/lib/ollama_chat/follow_chat.rb +40 -19
  10. data/lib/ollama_chat/history.rb +10 -23
  11. data/lib/ollama_chat/information.rb +44 -1
  12. data/lib/ollama_chat/input_content.rb +1 -1
  13. data/lib/ollama_chat/logging.rb +29 -0
  14. data/lib/ollama_chat/model_handling.rb +3 -7
  15. data/lib/ollama_chat/oc.rb +22 -4
  16. data/lib/ollama_chat/ollama_chat_config/default_config.yml +15 -6
  17. data/lib/ollama_chat/personae_management.rb +13 -2
  18. data/lib/ollama_chat/tools/directory_structure.rb +2 -2
  19. data/lib/ollama_chat/tools/execute_grep.rb +30 -4
  20. data/lib/ollama_chat/tools/paste_into_editor.rb +2 -2
  21. data/lib/ollama_chat/tools/patch_file.rb +119 -0
  22. data/lib/ollama_chat/tools/run_tests.rb +15 -9
  23. data/lib/ollama_chat/tools.rb +1 -0
  24. data/lib/ollama_chat/utils/chooser.rb +7 -3
  25. data/lib/ollama_chat/utils/tag_resolver.rb +1 -1
  26. data/lib/ollama_chat/version.rb +1 -1
  27. data/lib/ollama_chat/web_searching.rb +5 -7
  28. data/lib/ollama_chat.rb +1 -0
  29. data/ollama_chat.gemspec +7 -7
  30. data/spec/ollama_chat/chat_spec.rb +8 -13
  31. data/spec/ollama_chat/clipboard_spec.rb +0 -2
  32. data/spec/ollama_chat/follow_chat_spec.rb +0 -2
  33. data/spec/ollama_chat/information_spec.rb +0 -2
  34. data/spec/ollama_chat/input_content_spec.rb +0 -2
  35. data/spec/ollama_chat/kramdown_ansi_spec.rb +0 -2
  36. data/spec/ollama_chat/message_editing_spec.rb +0 -2
  37. data/spec/ollama_chat/message_list_spec.rb +0 -2
  38. data/spec/ollama_chat/message_output_spec.rb +0 -2
  39. data/spec/ollama_chat/model_handling_spec.rb +0 -2
  40. data/spec/ollama_chat/parsing_spec.rb +0 -3
  41. data/spec/ollama_chat/redis_cache_spec.rb +0 -2
  42. data/spec/ollama_chat/server_socket_spec.rb +0 -2
  43. data/spec/ollama_chat/source_fetching_spec.rb +0 -2
  44. data/spec/ollama_chat/state_selectors_spec.rb +0 -2
  45. data/spec/ollama_chat/switches_spec.rb +0 -2
  46. data/spec/ollama_chat/think_control_spec.rb +0 -2
  47. data/spec/ollama_chat/tools/browse_spec.rb +0 -2
  48. data/spec/ollama_chat/tools/copy_to_clipboard_spec.rb +0 -2
  49. data/spec/ollama_chat/tools/directory_structure_spec.rb +0 -2
  50. data/spec/ollama_chat/tools/execute_grep_spec.rb +28 -10
  51. data/spec/ollama_chat/tools/execute_ri_spec.rb +0 -2
  52. data/spec/ollama_chat/tools/file_context_spec.rb +0 -2
  53. data/spec/ollama_chat/tools/gem_path_lookup_spec.rb +0 -2
  54. data/spec/ollama_chat/tools/generate_password_spec.rb +0 -2
  55. data/spec/ollama_chat/tools/get_current_weather_spec.rb +0 -2
  56. data/spec/ollama_chat/tools/get_cve_spec.rb +0 -2
  57. data/spec/ollama_chat/tools/get_endoflife_spec.rb +0 -2
  58. data/spec/ollama_chat/tools/get_jira_issue_spec.rb +0 -2
  59. data/spec/ollama_chat/tools/get_location_spec.rb +0 -2
  60. data/spec/ollama_chat/tools/get_rfc_spec.rb +0 -2
  61. data/spec/ollama_chat/tools/get_time_spec.rb +0 -2
  62. data/spec/ollama_chat/tools/get_url_spec.rb +0 -2
  63. data/spec/ollama_chat/tools/open_file_in_editor_spec.rb +0 -2
  64. data/spec/ollama_chat/tools/paste_from_clipboard_spec.rb +0 -2
  65. data/spec/ollama_chat/tools/paste_into_editor_spec.rb +0 -2
  66. data/spec/ollama_chat/tools/patch_file_spec.rb +155 -0
  67. data/spec/ollama_chat/tools/read_file_spec.rb +0 -2
  68. data/spec/ollama_chat/tools/resolve_tag_spec.rb +0 -2
  69. data/spec/ollama_chat/tools/run_tests_spec.rb +24 -9
  70. data/spec/ollama_chat/tools/search_web_spec.rb +0 -2
  71. data/spec/ollama_chat/tools/write_file_spec.rb +0 -2
  72. data/spec/ollama_chat/utils/analyze_directory_spec.rb +0 -4
  73. data/spec/ollama_chat/utils/cache_fetcher_spec.rb +0 -2
  74. data/spec/ollama_chat/utils/fetcher_spec.rb +0 -2
  75. data/spec/ollama_chat/utils/file_argument_spec.rb +0 -2
  76. data/spec/ollama_chat/vim_spec.rb +0 -2
  77. data/spec/ollama_chat/web_searching_spec.rb +0 -2
  78. data/spec/spec_helper.rb +7 -0
  79. metadata +10 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 368f0f36682a4570b76fead6a43e797a8c450f983921dfab46ca7d6d4cb5759b
4
- data.tar.gz: aadd0d681c682ce97a670b48d706f0dfc71a3a65ed6cd4390c3e663892db1e8a
3
+ metadata.gz: 982588e8a14a4bb35aebd365a9dea99fb7c7b474f4d1293436fa97d1258eec79
4
+ data.tar.gz: 0a0410940246c4d9d260256e02373f002aeadba778a2097aefc97f190dc17e68
5
5
  SHA512:
6
- metadata.gz: e9b72a1b63e771e0574b7028a205936f2c3cf2213fb9f85c54f4d4c5d11a5dad99d0ae6461f16b656f8b36f13a42c7237b953a1be305176c0b12766881d087e4
7
- data.tar.gz: 1986df4ed7e098d6561674e7d8406bc1db73b55884b4eedbd411c33f5777009ae88864828905c55f4c057b44895fef4e8d5552e89ac2c83bc4a6c0a5ffdce255
6
+ metadata.gz: f15c28d9980519078af9b27d5706edfa91df2c4c13ac235377dd97623c62a40c9b8014c06373f093ef473e5c9553e20a949fa4488afb7be06b94ebd006c2eb1c
7
+ data.tar.gz: 8bc4b5bd4880ab46ea227379ff4786681a7f7bef67d81df35628f5aea238c250f0842de5408fdb94056828c792080ce0ee0793a3a74e13d8a78c6d504b005f9d
data/CHANGES.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-03-13 v0.0.79
4
+
5
+ - Added `tmp/*` to Rakefile ignore list for cleaner builds.
6
+ - Updated gemspec: changed `s.rubygems_version` to **3.6.9**.
7
+ - Added `logging.rb` to `extra_rdoc_files` and `files` in gemspec.
8
+ - Adjusted gemspec file list to reflect new structure.
9
+ - Removed `Runtime Directory` (`-d`) explanation from `README.md`.
10
+ - Updated URL in `README.md`.
11
+ - Added explicit check that `args.path.full?` is true before calling
12
+ `assert_valid_path`, raising `ArgumentError` with message `'require path to
13
+ file to be patched'`.
14
+ - Updated path assignment to first validate presence, then assert validity
15
+ against `config.tools.functions.patch_file.allowed?`.
16
+ - Updated `OllamaChat::Tools::ExecuteGrep` to accept new options `before`,
17
+ `after`, and `context`.
18
+ - Added helper method `normalize_number` for optional integer arguments.
19
+ - Adjusted command template in `default_config.yml` to include `-B`, `-A`, and
20
+ `-C` flags based on provided values.
21
+ - Refactored logging: replaced `logger.error` / `logger.warn` calls with
22
+ `log(:error, …)` or `log(:warn, …)` across multiple files.
23
+ - Added optional `warn: true` flag to new helper so that critical errors also
24
+ trigger a user‑visible warning output while still being written to the log
25
+ file.
26
+ - Implemented `OllamaChat::Logging#log(severity, msg, warn:)` in `logging.rb`;
27
+ it formats exceptions with backtraces and forwards messages to the underlying
28
+ Ruby `Logger`.
29
+ - Updated `spec_helper.rb` by adding a global `config.before` hook that sets
30
+ temporary paths for `OC::OLLAMA::CHAT::HISTORY` and `LOGFILE` so all specs
31
+ run against isolated files.
32
+ - Added `tmp/*` to `.gitignore`.
33
+ - Created new module `OllamaChat::Logging` that lazily builds a Logger writing
34
+ to the file defined by `OC::OLLAMA::CHAT::LOGFILE` in XDG STATE.
35
+ - Required this logging module in `lib/ollama_chat.rb` and included it in
36
+ `class OllamaChat::Chat` so every chat instance has access to `logger`.
37
+ - Logged connection messages via `@chat.logger.info` before printing the
38
+ “Connecting …” line in `OllamaChat::Dialog#connect_message`.
39
+ - Centralized tool‑call error handling: log unconfigured, unregistered or
40
+ disabled tools with `@chat.logger.error`, and record each executed function
41
+ payload using `JSON.pretty_generate`.
42
+ - Introduced an explicit vs implicit confirmation flow (`:explicit`,
43
+ `:implicite`, `:denied`) in `OllamaChat::FollowChat#follow_chat` and log the
44
+ outcome accordingly.
45
+ - Switched chat history storage from XDG CACHE to XDG STATE by updating
46
+ `OC::OLLAMA::CHAT::HISTORY` path, adjusting file operations in
47
+ `lib/ollama_chat/history.rb`, and adding a new config entry for `LOGFILE`
48
+ under state home in `oc.rb`.
49
+ - Enhanced PatchFile tool: updated documentation to specify `unified diff
50
+ format` and `JSON response`.
51
+ - Added private method `digest` that returns `MD5` of a file path.
52
+ - Modified `apply_patch` to compute old digest, run patch command, compare
53
+ digests, set `success` flag accordingly.
54
+ - Improved error handling: now includes `success`, clearer messages, empty
55
+ result on failure.
56
+
57
+ ## 2026-03-11 v0.0.78
58
+
59
+ - Added new `patch_file` tool for applying unified diff patches to files with
60
+ safety checks, including specs and integration into the tool system.
61
+ - Updated `DirectoryStructure` tool description to clarify that `max_depth`
62
+ limits the tree height for better LLM understanding.
63
+ - Bumped `search_ui` gem dependency from **0.0** to **0.1**, refactored model
64
+ handling using `SearchUI::Wrapper.new` and updated chooser logic for safer
65
+ method dispatch.
66
+ - Enhanced `run_tests` tool with a path validation whitelist in
67
+ `default_config.yml`, introducing `OllamaChat::Utils::PathValidator` and
68
+ updating `check_path` method to validate against the allowed list.
69
+ - Simplified runtime information handling by adding new helper methods:
70
+ `runtime_information_values`, `runtime_information`, and updated `chat.rb` to
71
+ use these for displaying structured runtime data.
72
+ - Added default persona name display using the `default_persona_name` helper,
73
+ updating information output and refactoring `reload_default_persona` guard
74
+ logic.
75
+
3
76
  ## 2026-03-09 v0.0.77
4
77
 
5
78
  - Add runtime Git and time placeholders: added `git_current_branch` and
data/README.md CHANGED
@@ -252,14 +252,6 @@ The `ollama_chat_send` command now supports additional parameters to enhance fun
252
252
  $ echo "Hello world" | ollama_chat_send -d /tmp/my_working_dir -r
253
253
  ```
254
254
 
255
- - **Runtime Directory (`-d`)**: Specifies the directory where the Unix socket
256
- file of `ollama_chat` was created, if you want to send to a specific
257
- `ollama_chat`.
258
-
259
- ```bash
260
- $ echo "Hello world" | ollama_chat_send -d /tmp/my_runtime_dir -r
261
- ```
262
-
263
255
  - **Help (`-h` or `--help`)**: Displays usage information and available options.
264
256
 
265
257
  ```bash
@@ -273,7 +265,7 @@ These parameters provide greater flexibility in how you interact with
273
265
 
274
266
  The homepage of this app is located at
275
267
 
276
- * https://github.com/flori/ollama\_chat
268
+ * https://github.com/flori/ollama_chat
277
269
 
278
270
  ## Author
279
271
 
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ GemHadar do
22
22
  test_dir 'spec'
23
23
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
24
24
  '.yardoc', 'doc', 'tags', 'corpus', 'coverage', '/config/searxng/*',
25
- '.starscope.db', 'cscope.out', 'errors.lst'
25
+ '.starscope.db', 'cscope.out', 'errors.lst', 'tmp/*'
26
26
  package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
27
27
  '.rspec', '.github', '.contexts', '.envrc', '.yardopts'
28
28
 
@@ -52,7 +52,7 @@ GemHadar do
52
52
  dependency 'kramdown-ansi', '~> 0.3'
53
53
  dependency 'complex_config', '~> 0.22', '>= 0.22.2'
54
54
  dependency 'tins', '~> 1.52'
55
- dependency 'search_ui', '~> 0.0'
55
+ dependency 'search_ui', '~> 0.1'
56
56
  dependency 'amatch', '~> 0.4'
57
57
  dependency 'pdf-reader', '~> 2.0'
58
58
  dependency 'bigdecimal', '~> 3.1'
@@ -33,6 +33,7 @@ require 'context_spook'
33
33
  class OllamaChat::Chat
34
34
  include Tins::GO
35
35
  include Term::ANSIColor
36
+ include OllamaChat::Logging
36
37
  include OllamaChat::DocumentCache
37
38
  include OllamaChat::Switches
38
39
  include OllamaChat::StateSelectors
@@ -193,7 +194,7 @@ class OllamaChat::Chat
193
194
  end
194
195
 
195
196
  # The disable_content_parsing method turns off content parsing by setting
196
- # @parse_content to false.
197
+ # `@parse_content` to false.
197
198
  #
198
199
  # This prevents automatic parsing of user input content during chat
199
200
  # processing.
@@ -264,7 +265,8 @@ class OllamaChat::Chat
264
265
  begin
265
266
  use_model
266
267
  rescue OllamaChatError::UnknownModelError => e
267
- STDERR.puts "Caught #{e.class}: #{e}"
268
+ msg = "Caught #{e.class}: #{e}"
269
+ log(:error, msg, warn: true)
268
270
  end
269
271
  :next
270
272
  when %r(^/system(?:\s+(show))?$)
@@ -707,23 +709,7 @@ class OllamaChat::Chat
707
709
  end
708
710
  end
709
711
 
710
- if runtime_info.on? && content
711
- runtime_info_values = {
712
- languages: config.languages * ', ',
713
- location: location.on? ? location_description.inspect : 'n/a',
714
- git_current_branch: `git rev-parse --abbrev-ref HEAD 2>/dev/null`.chomp.full? || 'n/a',
715
- git_remote_origin: `git remote get-url origin 2>/dev/null`.chomp.full? || 'n/a',
716
- client: ,
717
- current_directory: Pathname.pwd.expand_path.to_path.inspect,
718
- terminal_rows: Tins::Terminal.rows,
719
- terminal_cols: Tins::Terminal.cols,
720
- time: Time.now.iso8601,
721
- voice: voice.on? ? 'enabled' : 'disabled',
722
- markdown: markdown.on? ? 'enabled' : 'disabled',
723
- tool_paths_allowed: JSON(tool_paths_allowed),
724
- }
725
- content << config.prompts.runtime_info % runtime_info_values
726
- end
712
+ content << runtime_information if runtime_info.on? && content
727
713
 
728
714
  messages << Ollama::Message.new(role: 'user', content:, images: @images.dup)
729
715
  @images.clear
@@ -777,7 +763,8 @@ class OllamaChat::Chat
777
763
  server_socket_message&.disconnect
778
764
  end
779
765
  rescue Ollama::Errors::TimeoutError
780
- STDOUT.puts "#{bold('Error')}: Currently lost connection to ollama server and cannot send command."
766
+ msg = "Currently lost connection to ollama server and cannot send command."
767
+ log(:warn, msg, warn: true)
781
768
  rescue Interrupt
782
769
  STDOUT.puts "Type /quit to quit."
783
770
  ensure
@@ -785,6 +772,7 @@ class OllamaChat::Chat
785
772
  end
786
773
  0
787
774
  rescue ComplexConfig::AttributeMissing, ComplexConfig::ConfigurationSyntaxError => e
775
+ log(:error, e)
788
776
  fix_config(e)
789
777
  ensure
790
778
  save_history
@@ -821,6 +809,7 @@ class OllamaChat::Chat
821
809
  if server_version.version < '0.9.0'.version
822
810
  raise 'require ollama API version 0.9.0 or higher'
823
811
  end
812
+ log(:info, "Connection to #{base_url} established.")
824
813
  @ollama
825
814
  end
826
815
 
@@ -98,7 +98,6 @@ module OllamaChat::Clipboard
98
98
  # handles any OllamaChat::OllamaChatError exceptions by printing the error
99
99
  # message to standard error and does not re-raise the exception.
100
100
  def copy_to_clipboard
101
-
102
101
  perform_copy_to_clipboard
103
102
  STDOUT.puts "The last response has been successfully copied to the system clipboard."
104
103
  true
@@ -30,7 +30,9 @@ module OllamaChat::Dialog
30
30
  # @param model [String] the model name to connect to
31
31
  # @param base_url [String] the base URL of the connection
32
32
  def connect_message(model, base_url)
33
- STDOUT.puts green { "Connecting to #{model}@#{base_url} now…" }
33
+ msg = "Connecting to #{model}@#{base_url} now…"
34
+ log(:info, msg)
35
+ STDOUT.puts green { msg }
34
36
  end
35
37
 
36
38
  # The choose_collection method presents a menu to select or create a document
@@ -43,7 +43,7 @@ module OllamaChat::DocumentCache
43
43
  document_cache_class
44
44
  end
45
45
  rescue => e
46
- STDERR.puts "Caught #{e.class}: #{e} => Falling back to MemoryCache."
46
+ log(:error, "Caught #{e.class}: #{e} => Falling back to MemoryCache.")
47
47
  Documentrix::Documents::MemoryCache
48
48
  end
49
49
  end
@@ -99,43 +99,46 @@ class OllamaChat::FollowChat
99
99
  response.message.tool_calls.each do |tool_call|
100
100
  name = tool_call.function.name
101
101
  unless @chat.tool_configured?(name)
102
- @chat.tool_call_results[name] =
103
- "Error: Unconfigured tool named %s ignored => Skip.\n" % name
102
+ msg = "Error: Unconfigured tool named %s ignored => Skip.\n" % name
103
+ @chat.tool_call_results[name] = msg
104
+ @chat.log(:error, msg)
104
105
  next
105
106
  end
106
107
  unless @chat.tool_registered?(name)
107
- @chat.tool_call_results[name] =
108
- "Error: Unregistered tool named %s ignored => Skip.\n" % name
108
+ msg = "Error: Unregistered tool named %s ignored => Skip.\n" % name
109
+ @chat.tool_call_results[name] = msg
110
+ @chat.log(:error, msg)
109
111
  next
110
112
  end
111
113
  unless @chat.tool_enabled?(name)
112
- @chat.tool_call_results[name] =
113
- "Error: Disabled tool named %s ignored => Skip.\n" % name
114
+ msg = "Error: Disabled tool named %s ignored => Skip.\n" % name
115
+ @chat.tool_call_results[name] = msg
116
+ @chat.log(:error, msg)
114
117
  next
115
118
  end
116
119
  STDOUT.puts
117
- confirmed = true
118
- args = JSON.pretty_generate(tool_call.function.arguments)
120
+ confirmed = :implicit
121
+ function = JSON.pretty_generate(tool_call.function)
122
+ @chat.log(:info, function)
119
123
  if @chat.tool_function(name).require_confirmation?
120
124
  prompt = "I want to execute tool %s\n%s\nConfirm? (y/n) " % [
121
125
  bold { name },
122
- italic { args },
126
+ italic { function },
123
127
  ]
124
- confirmed = @chat.ask?(prompt:) =~ /\Ay/i
128
+ if @chat.ask?(prompt:) =~ /\Ay/i
129
+ confirmed = :explicit
130
+ else
131
+ confirmed = :denied
132
+ end
125
133
  else
126
134
  STDOUT.puts "Executing tool %s\n%s" % [
127
135
  bold { name },
128
- italic { args },
136
+ italic { function },
129
137
  ]
130
138
  end
131
139
  result = nil
132
- if confirmed
133
- STDOUT.printf(
134
- "\n%s Execution of tool %s confirmed.\n\n", ?✅, bold { name }
135
- )
136
- result = OllamaChat::Tools.registered[name].
137
- execute(tool_call, chat: @chat, config: @chat.config)
138
- else
140
+ case confirmed
141
+ when :denied
139
142
  result = JSON(
140
143
  message: 'User denied confirmation!',
141
144
  resolve: 'You **MUST** ask the user for instructions on how to proceed!!!',
@@ -143,7 +146,25 @@ class OllamaChat::FollowChat
143
146
  STDOUT.printf(
144
147
  "\n%s Execution of tool %s denied by user.\n", ?🚫, bold { name }
145
148
  )
146
- sleep 1
149
+ @chat.log(:warn,"Execution of tool %s was denied by user!" % name)
150
+ else
151
+ symbol = confirmed == :implicit ? '☑️ ' : '✅'
152
+ STDOUT.printf(
153
+ "\n%s Execution of tool %s confirmed.\n\n", symbol, bold { name }
154
+ )
155
+ result = OllamaChat::Tools.registered[name].
156
+ execute(tool_call, chat: @chat, config: @chat.config)
157
+ if confirmed == :explicit
158
+ @chat.log(:info, "Execution of tool %s was explicitly confirmed." % name)
159
+ else
160
+ @chat.log(:info, "Execution of tool %s was implicitly confirmed." % name)
161
+ end
162
+ end
163
+ begin
164
+ data = JSON.parse(result)
165
+ @chat.log(:info, JSON.pretty_generate(data))
166
+ rescue
167
+ @chat.log(:info, result)
147
168
  end
148
169
  @chat.tool_call_results[name] = result
149
170
  end
@@ -17,20 +17,6 @@
17
17
  module OllamaChat::History
18
18
  private
19
19
 
20
- # The chat_history_filename method constructs and returns the full file path
21
- # for the chat history file.
22
- #
23
- # This method takes the configured chat history filename from the
24
- # configuration and expands it to an absolute path using File.expand_path.
25
- # This ensures that the returned path is fully qualified and can be used
26
- # reliably for reading from or writing to the chat history file.
27
- #
28
- # @return [String] the absolute file path to the chat history file as
29
- # specified in the configuration
30
- def chat_history_filename
31
- File.expand_path(OC::OLLAMA::CHAT::HISTORY)
32
- end
33
-
34
20
  # The init_chat_history method initializes the chat session by loading
35
21
  # previously saved command history from a file.
36
22
  #
@@ -40,15 +26,15 @@ module OllamaChat::History
40
26
  # loading process are caught and logged as warnings, but do not interrupt the
41
27
  # execution flow.
42
28
  def init_chat_history
43
- if File.exist?(chat_history_filename)
44
- File.open(chat_history_filename, ?r) do |history|
45
- history_data = JSON.load(history)
46
- Readline::HISTORY.clear
47
- Readline::HISTORY.push(*history_data)
48
- end
29
+ if OC::OLLAMA::CHAT::HISTORY.exist?
30
+ history = OC::OLLAMA::CHAT::HISTORY.read
31
+ history_data = JSON.load(history)
32
+ Readline::HISTORY.clear
33
+ Readline::HISTORY.push(*history_data)
49
34
  end
50
35
  rescue => e
51
- warn "Caught #{e.class} while loading #{chat_history_filename.inspect}: #{e}"
36
+ msg = "Caught #{e.class} while loading #{OC::OLLAMA::CHAT::HISTORY.inspect}: #{e}"
37
+ log(:error, msg, warn: true)
52
38
  end
53
39
 
54
40
  # The save_history method persists the current command history to a file.
@@ -57,9 +43,10 @@ module OllamaChat::History
57
43
  # writes it to the chat history filename. It handles potential errors during
58
44
  # the write operation by catching exceptions and issuing a warning message.
59
45
  def save_history
60
- File.secure_write(chat_history_filename, JSON.dump(Readline::HISTORY))
46
+ File.secure_write(OC::OLLAMA::CHAT::HISTORY, JSON.dump(Readline::HISTORY))
61
47
  rescue => e
62
- warn "Caught #{e.class} while saving #{chat_history_filename.inspect}: #{e}"
48
+ msg = "Caught #{e.class} while saving #{OC::OLLAMA::CHAT::HISTORY.inspect}: #{e}"
49
+ log(:error, msg, warn: true)
63
50
  end
64
51
 
65
52
  # The clear_history method clears the Readline history array and ensures that
@@ -112,13 +112,20 @@ module OllamaChat::Information
112
112
  think_mode.show
113
113
  think_loud.show
114
114
  location.show
115
- runtime_info.show
116
115
  voice.show
117
116
  @voice.on? and @voices.show
117
+ if runtime_info.on?
118
+ STDOUT.puts "Runtime Information:"
119
+ STDOUT.puts runtime_information_values.transform_keys(&:to_s).to_yaml.
120
+ sub(/\A---\s*\n/, '').gsub(/^/, ' ')
121
+ else
122
+ runtime_info.show
123
+ end
118
124
  tools_support.show
119
125
  STDOUT.puts "Documents database cache is #{@documents.nil? ? 'n/a' : bold{@documents.cache.class}}"
120
126
  STDOUT.puts "Document policy for references in user text: #{bold{document_policy}}"
121
127
  STDOUT.puts "Currently selected search engine is #{bold(search_engine)}."
128
+ name = default_persona_name and STDOUT.puts "Default persona: #{bold{name}}"
122
129
  STDOUT.puts "Conversation length: #{bold(@messages.size.to_s)} message(s)."
123
130
  nil
124
131
  end
@@ -231,4 +238,40 @@ module OllamaChat::Information
231
238
  def server_url
232
239
  @server_url ||= ollama.base_url
233
240
  end
241
+
242
+ # The runtime_information_values method compiles a set of key runtime details
243
+ # such as languages, location description, default persona name, current git
244
+ # branch and remote origin, client agent string, current directory, terminal
245
+ # dimensions, timestamp, voice and markdown status, and allowed tool paths.
246
+ #
247
+ # @return [Hash] a hash containing runtime information values.
248
+ def runtime_information_values
249
+ {
250
+ languages: config.languages * ', ',
251
+ time: Time.now.iso8601,
252
+ location: location.on?.full? { location_description } || 'n/a',
253
+ default_persona: default_persona_name.full? || 'n/a',
254
+ git_current_branch: `git rev-parse --abbrev-ref HEAD 2>/dev/null`.chomp.full? || 'n/a',
255
+ git_remote_origin: `git remote get-url origin 2>/dev/null`.chomp.full? || 'n/a',
256
+ client: ,
257
+ current_directory: Pathname.pwd.expand_path.to_path,
258
+ terminal_rows: Tins::Terminal.rows,
259
+ terminal_cols: Tins::Terminal.cols,
260
+ voice: voice.on? ? 'enabled' : 'disabled',
261
+ markdown: markdown.on? ? 'enabled' : 'disabled',
262
+ tool_paths_allowed: JSON.pretty_generate(tool_paths_allowed),
263
+ }
264
+ end
265
+
266
+ # The runtime_information method generates a formatted string containing
267
+ # various runtime values such as languages, location description, git branch
268
+ # and origin, client agent, current directory, terminal size, time, voice and
269
+ # markdown status, and allowed tool paths.
270
+ # It returns the result of interpolating these values into the configured
271
+ # runtime_info prompt template.
272
+ #
273
+ # @return [String] the formatted runtime information string.
274
+ def runtime_information
275
+ config.prompts.runtime_info % runtime_information_values
276
+ end
234
277
  end
@@ -37,7 +37,7 @@ module OllamaChat::InputContent
37
37
  # searches for files matching the given pattern, excludes already chosen
38
38
  # files, and presents them in an interactive chooser menu.
39
39
  #
40
- # @param pattern [ Array<String> ] the glob pattern to search for files
40
+ # @param patterns [ Array<String> ] the glob patterns to search for files
41
41
  # @param chosen [ Set ] a set of already chosen filenames to exclude from
42
42
  # selection
43
43
  #
@@ -0,0 +1,29 @@
1
+ # Provides a simple logging facility for the OllamaChat application. It offers
2
+ # methods to access a logger, determine the current log level, and write
3
+ # messages at various severity levels, including debug.
4
+ module OllamaChat::Logging
5
+ # The logger method returns the current Logger instance used by OllamaChat.
6
+ # If no Logger exists, it creates one pointing to the configured log file.
7
+ #
8
+ # @return [Logger] the active Logger instance
9
+ def logger
10
+ @logger and return @logger
11
+ OC::OLLAMA::CHAT::LOGFILE.dirname.mkpath
12
+ @logger = Logger.new(OC::OLLAMA::CHAT::LOGFILE)
13
+ end
14
+
15
+ # The log method records a message or exception at the specified severity
16
+ # level using the logger and optionally triggers a warning output
17
+ #
18
+ # @param severity [ Symbol ] the logging level to use
19
+ # @param msg [ String, Exception ] the message or exception to be logged
20
+ # @param warn [ TrueClass, FalseClass ] whether to also trigger a warning output
21
+ def log(severity, msg, warn: false)
22
+ if msg.is_a?(Exception)
23
+ msg = "Caught #{msg.class}: #{msg}\n#{Array(msg&.backtrace).join(?\n)}"
24
+ end
25
+ logger.send(severity, msg)
26
+ warn and self.warn(msg)
27
+ nil
28
+ end
29
+ end
@@ -94,14 +94,10 @@ module OllamaChat::ModelHandling
94
94
  # @return [ Object ] a result object with an overridden to_s method
95
95
  # that combines the model name and formatted size
96
96
  private def model_with_size(model)
97
- result = model.name
98
97
  formatted_size = Term::ANSIColor.bold {
99
98
  Tins::Unit.format(model.size, unit: ?B, prefix: 1024, format: '%.1f %U')
100
99
  }
101
- result.singleton_class.class_eval do
102
- define_method(:to_s) { "%s %s" % [ model.name, formatted_size ] }
103
- end
104
- result
100
+ SearchUI::Wrapper.new(model.name, display: "#{model.name} #{formatted_size}")
105
101
  end
106
102
 
107
103
  # The use_model method selects and sets the model to be used for the chat
@@ -151,12 +147,12 @@ module OllamaChat::ModelHandling
151
147
  Regexp.new($1)
152
148
  end
153
149
  models = ollama.tags.models.sort_by(&:name).map { |m| model_with_size(m) }
154
- selector and models = models.grep(selector)
150
+ selector and models = models.select { _1.value =~ selector }
155
151
  model =
156
152
  if models.size == 1
157
153
  models.first
158
154
  elsif cli_model == ''
159
- OllamaChat::Utils::Chooser.choose(models) || current_model
155
+ OllamaChat::Utils::Chooser.choose(models)&.value || current_model
160
156
  else
161
157
  cli_model || current_model
162
158
  end
@@ -17,17 +17,23 @@ module OC
17
17
  prefix ''
18
18
 
19
19
  XDG_CONFIG_HOME = set do
20
- description 'XDG Configuration directory path'
20
+ description 'XDG Configuration home directory path'
21
21
  default { '~/.config' }
22
22
  decode { Pathname.new(_1).join('ollama_chat').expand_path }
23
23
  end
24
24
 
25
25
  XDG_CACHE_HOME = set do
26
- description 'XDG Cache directory path'
26
+ description 'XDG Cache home directory path'
27
27
  default { '~/.cache' }
28
28
  decode { Pathname.new(_1).join('ollama_chat').expand_path }
29
29
  end
30
30
 
31
+ XDG_STATE_HOME = set do
32
+ description 'XDG State home directory path'
33
+ default { '~/.local' }
34
+ decode { Pathname.new(_1).join('state', 'ollama_chat').expand_path }
35
+ end
36
+
31
37
  PAGER = set do
32
38
  description 'Pager command to use in case terminal lines are exceeded by output'
33
39
 
@@ -133,14 +139,19 @@ module OC
133
139
 
134
140
  HISTORY = set do
135
141
  description 'File to save the chat history in'
136
- default XDG_CACHE_HOME + 'history.json'
142
+ default XDG_STATE_HOME + 'history.json'
143
+ end
144
+
145
+ LOGFILE = set do
146
+ description 'File to output log messages to'
147
+ default XDG_STATE_HOME + 'chat.log'
137
148
  end
138
149
 
139
150
  module TOOLS
140
151
  description 'Tool specific configuration settings'
141
152
 
142
153
  # Run Tests tool configuration
143
- RUN_TESTS_TEST_RUNNER = set do
154
+ TEST_RUNNER = set do
144
155
  description 'Configured test runner for run_tests tool function'
145
156
  default 'rspec'
146
157
  required true
@@ -162,6 +173,13 @@ module OC
162
173
  decode { Pathname.new(_1).expand_path }
163
174
  end
164
175
 
176
+ PATCH_TOOL = set do
177
+ description 'Patch tool to use'
178
+
179
+ default { `which patch`.full?(:chomp) }
180
+ check { value.blank? || File.exist?(value) }
181
+ end
182
+
165
183
  module JIRA
166
184
  description 'Jira tool configuration'
167
185
 
@@ -11,7 +11,7 @@ timeouts:
11
11
  languages:
12
12
  - en-US
13
13
  location:
14
- enabled: false
14
+ enabled: true
15
15
  name: Berlin
16
16
  decimal_degrees: [ 52.514127, 13.475211 ]
17
17
  units: SI (International System of Units) # or USCS (United States Customary System)
@@ -44,10 +44,10 @@ prompts:
44
44
  There is usually no reason to mention this information to the user unless
45
45
  asked about it.
46
46
 
47
- - Languages the user prefers: %{languages}.
48
- - Current time is %{time}.
49
- - Location is %{location}.
50
- - Current directory is %{current_directory}.
47
+ - Languages the user prefers: %{languages}
48
+ - Current time is %{time}
49
+ - Location: %{location}
50
+ - Current directory is "%{current_directory}"
51
51
  - **Git**:
52
52
  - Current branch is %{git_current_branch}
53
53
  - Current remote origin is %{git_remote_origin}
@@ -185,7 +185,7 @@ tools:
185
185
  execute_grep:
186
186
  default: true
187
187
  cmd: |
188
- grep #{'-i' if ignore_case} -m #{max_results} -r #{pattern} #{path}
188
+ grep #{'-i' if ignore_case} -m #{max_results} -r #{before.full? { "-B %u " % it }}#{after.full? { "-A %u " % it }}#{context.full? { "-C %u " % it }}#{pattern} #{path}
189
189
  browse:
190
190
  default: true
191
191
  write_file:
@@ -218,6 +218,10 @@ tools:
218
218
  run_tests:
219
219
  require_confirmation: true
220
220
  default: true
221
+ allowed:
222
+ - "./spec"
223
+ - "./test"
224
+ - "./tests"
221
225
  get_jira_issue:
222
226
  default: false
223
227
  get_rfc:
@@ -236,3 +240,8 @@ tools:
236
240
  default: true
237
241
  resolve_tag:
238
242
  default: true
243
+ patch_file:
244
+ default: true
245
+ require_confirmation: true
246
+ allowed:
247
+ - './tmp'
@@ -55,11 +55,22 @@ module OllamaChat::PersonaeManagement
55
55
  @default_persona ||= :none
56
56
  end
57
57
 
58
+ # The default_persona_name method returns the name of the currently set
59
+ # default persona by extracting its basename and removing the file extension,
60
+ # unless no persona is set.
61
+ #
62
+ # @return [ String ] the default persona name or nil if none.
63
+ def default_persona_name
64
+ if @default_persona.present? && @default_persona != :none
65
+ @default_persona.basename.sub_ext('').to_s
66
+ end
67
+ end
68
+
58
69
  # Reloads the default persona file if one is set and not :none, prompting the
59
70
  # user for confirmation before playing the persona file.
60
71
  def reload_default_persona
61
- !@default_persona || @default_persona == :none and return
62
- prompt = "Reload default persona #{@default_persona.basename.sub_ext('')}? (y/n) "
72
+ name = default_persona_name or return
73
+ prompt = "Reload default persona #{name}? (y/n) "
63
74
  if ask?(prompt:) =~ /\Ay/i
64
75
  play_persona_file @default_persona
65
76
  end