ollama_chat 0.0.85 → 0.0.86

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a9e61c3d789441bb11ee79fe2ec63f219cc8d938845a7dc6fe9c8f6d012d5bb
4
- data.tar.gz: f453e609568a6df073fbaf865860fa1c919419b728c309ae0e19e97dc09d6b52
3
+ metadata.gz: ff96f5853a0c293512e72157a823fb8237bfba6b1e36b1cf17c486cd3594597d
4
+ data.tar.gz: bd23354a354c89d2526a64071a76801304e2e9ebe67e9a978f1e50d0a624c021
5
5
  SHA512:
6
- metadata.gz: 24fadb41107daee4f625bb3d80743c8323624da545e6386b07ef25da5be3974afa2b0759a8db86d44eea04c9b156b92400e6a348d6bd9aae3dd71791939533bd
7
- data.tar.gz: 7c43765e2da1f09781b6a8b0af70ea562cdec22fbdb4c92ab7f4eca033fdd3b9f79a55cbe3d7c3e91684c771a29cca95c76f26c44b7871cf9e142c3d0ca12179
6
+ metadata.gz: cea92ab75e86033f88e08bedc272e75d7151ee62eebba70328a17b7eaad6aba9d84dfcfe5e69e9757317cbb4e881e6ae9c5464b6070f4540f6bfe9d09cb19049
7
+ data.tar.gz: af5ec5db535c6baa88749a387ff3c6b08e593bb4a578f45851fa1d695c0a7fed387a9698e9e379c30561b357d529b5f77a2b26bbdfe1073d1c6bcfcc0f522945
data/CHANGES.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-02 v0.0.86
4
+
5
+ - Updated `play_persona_prompt` in `lib/ollama_chat/personae_management.rb` to
6
+ include “(no need to read the file)” in the roleplay prompt template string.
7
+ - Added `optional: true` to the `/links` command in `lib/ollama_chat/chat.rb`.
8
+ - Made the `edit` subcommand of `/revise` optional by adding `optional: true`
9
+ to its command definition in `lib/ollama_chat/chat.rb`.
10
+ - Added a `backup` subcommand for persona management:
11
+ - Updated the `:persona` command regex and completion options in
12
+ `lib/ollama_chat/chat.rb`.
13
+ - Added a case handler to invoke the new `backup_persona` method.
14
+ - Implemented `backup_persona` in `lib/ollama_chat/personae_management.rb`
15
+ with YARD documentation.
16
+ - Removed the redundant assignment `persona = persona` in `edit_persona`.
17
+ - Fixed the rescue exception class name in the `use_model` block of
18
+ `lib/ollama_chat/chat.rb`, changing from `OllamaChatError::UnknownModelError`
19
+ to `OllamaChat::UnknownModelError`.
20
+ - Ensured float division for duration calculations in `FollowChat` by
21
+ converting operands to float in the `eval_stats` method of
22
+ `lib/ollama_chat/follow_chat.rb`.
23
+ - Used `Pathname.new(file).expand_path.directory?` for tilde expansion in
24
+ directory checks in `lib/ollama_chat/parsing.rb`.
25
+ - Refactored command registration formatting in `lib/ollama_chat/chat.rb`.
26
+ - Added YARD documentation to the `OllamaChat::CommandConcern::Command` class
27
+ in `lib/ollama_chat/command_concern.rb`.
28
+ - Removed the deprecated `-d` flag from the `/input` command in
29
+ `lib/ollama_chat/chat.rb`.
30
+ - Removed tag support from `parse_content`:
31
+ - Updated `OllamaChat::Chat` to call `parse_content` without expecting a
32
+ `tags` array.
33
+ - Simplified handling of `@parse_content`.
34
+ - Removed tag recognition logic from `OllamaChat::Parsing`.
35
+ - Changed `parse_content` to return a single `String`.
36
+ - Deleted tag‑specific example from the spec.
37
+ - Updated the `file_context` tool description for accuracy.
38
+ - Added an interactive loop to enable/disable tools:
39
+ - Wrapped `enable_tool` and `disable_tool` in a `loop do` in
40
+ `lib/ollama_chat/tool_calling.rb`.
41
+ - Modified `select_tools` to place `[EXIT]` at the start.
42
+ - Handled user choice with `OllamaChat::Utils::Chooser.choose(select_tools)`
43
+ and exited on `[EXIT]` or `nil`.
44
+
3
45
  ## 2026-03-29 v0.0.85
4
46
 
5
47
  - Added `list` and `rename` subcommands to the `/collection` command, allowing
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ GemHadar do
42
42
 
43
43
  dependency 'excon', '~> 1.0'
44
44
  dependency 'ollama-ruby', '~> 1.21'
45
- dependency 'documentrix', '>= 0.1.0'
45
+ dependency 'documentrix', '>= 0.1.1'
46
46
  dependency 'unix_socks', '~> 0.3'
47
47
  dependency 'rss', '~> 0.3'
48
48
  dependency 'term-ansicolor', '~> 1.11'
@@ -296,7 +296,7 @@ class OllamaChat::Chat
296
296
  ) do
297
297
  begin
298
298
  use_model
299
- rescue OllamaChatError::UnknownModelError => e
299
+ rescue OllamaChat::UnknownModelError => e
300
300
  msg = "Caught #{e.class}: #{e}"
301
301
  log(:error, msg, warn: true)
302
302
  end
@@ -410,6 +410,7 @@ class OllamaChat::Chat
410
410
  name: :links,
411
411
  regexp: %r(^/links(?:\s+(clear))?$),
412
412
  complete: [ 'links', %w[ clear ] ],
413
+ optional: true,
413
414
  help: 'display (or clear) links used in the chat',
414
415
  ) do |subcommand|
415
416
  manage_links(subcommand)
@@ -420,6 +421,7 @@ class OllamaChat::Chat
420
421
  name: :revise,
421
422
  regexp: %r(^/revise(?:\s+(edit))?$),
422
423
  complete: [ 'revise', %w[ edit ] ],
424
+ optional: true,
423
425
  help: 'revise the last message (and/or edit the query)'
424
426
  ) do |subcommand|
425
427
  if content = messages.second_last&.content
@@ -526,8 +528,8 @@ class OllamaChat::Chat
526
528
 
527
529
  command(
528
530
  name: :persona,
529
- regexp: %r(^/persona(?:\s+(add|delete|edit|file|info|list|load|play))?$),
530
- complete: [ 'persona', %w[ add delete edit file info list load play ] ],
531
+ regexp: %r(^/persona(?:\s+(add|delete|edit|backup|file|info|list|load|play))?$),
532
+ complete: [ 'persona', %w[ add delete edit backup file info list load play ] ],
531
533
  optional: true,
532
534
  help: 'manage and load/play personae for roleplay',
533
535
  ) do |subcommand|
@@ -553,6 +555,9 @@ class OllamaChat::Chat
553
555
  else
554
556
  :next
555
557
  end
558
+ when 'backup'
559
+ backup_persona
560
+ :next
556
561
  when 'file'
557
562
  if pathname = choose_filename('**/*.md')
558
563
  pathname.read
@@ -608,7 +613,7 @@ class OllamaChat::Chat
608
613
 
609
614
  command(
610
615
  name: :input,
611
- regexp: %r(^/input(?:\s+(path|summary|context|embedding)(?:\s*(?=\z))?)?((?:\s+-(?:[ad]|w\s*\d+))*)(?:\s+(pattern))?(?:\s+(.+))?$),
616
+ regexp: %r(^/input(?:\s+(path|summary|context|embedding)(?:\s*(?=\z))?)?((?:\s+-(?:[a]|w\s*\d+))*)(?:\s+(pattern))?(?:\s+(.+))?$),
612
617
  optional: true,
613
618
  complete: [ 'input', [ 'path', 'summary', 'context', 'embedding', '', ], [ 'pattern', '' ] ],
614
619
  options: '[-w|-a] [arg…]',
@@ -1004,11 +1009,7 @@ class OllamaChat::Chat
1004
1009
 
1005
1010
  content = content.encode(invalid: :replace)
1006
1011
 
1007
- content, tags = if @parse_content
1008
- parse_content(content, @images)
1009
- else
1010
- [ content, Documentrix::Utils::Tags.new(valid_tag: /\A#*([\w\]\[]+)/) ]
1011
- end
1012
+ @parse_content and content = parse_content(content, @images)
1012
1013
 
1013
1014
  runtime_info.on? && content and
1014
1015
  content << ?\n << {
@@ -31,8 +31,11 @@ module OllamaChat::CommandConcern
31
31
  # exists or if no block is given.
32
32
  def command(name:, regexp:, complete: nil, optional: false, options: nil, help: nil, &block)
33
33
  name = name.to_sym
34
- commands.key?(name) and raise ArgumentError, "command #{name} already registered!"
35
- commands[name] = Command.new(name:, regexp:, complete:, optional:, options:, help:, &block)
34
+ commands.key?(name) and
35
+ raise ArgumentError, "command #{name} already registered!"
36
+ commands[name] =Command.new(
37
+ name:, regexp:, complete:, optional:, options:, help:, &block
38
+ )
36
39
  end
37
40
 
38
41
  # Return an array of all available command completions.
@@ -83,6 +86,21 @@ module OllamaChat::CommandConcern
83
86
  delegate :help_message, to: self
84
87
  end
85
88
 
89
+ # Represents a registered command in the OllamaChat command DSL.
90
+ #
91
+ # A `Command` instance stores
92
+ # * the command name(s) (`@complete.first`),
93
+ # * the matching regular expression (`@regexp`),
94
+ # * optional completion hints (`@complete[1..]`),
95
+ # * help text (`@help`), and
96
+ # * the block that is executed when the command matches.
97
+ #
98
+ # It also exposes helpers for optionality (`optional?`),
99
+ # command names (`command_names`), arguments (`arguments`),
100
+ # and completions (`completions`).
101
+ #
102
+ # The `execute_if_match?` method performs a regexp match and, if
103
+ # successful, yields the execution context to the stored block.
86
104
  class Command
87
105
  # Create a new Command instance.
88
106
  #
@@ -348,8 +348,8 @@ class OllamaChat::FollowChat
348
348
  # the evaluation process including durations, counts, and rates, styled
349
349
  # with colors and formatting
350
350
  def eval_stats(response)
351
- eval_duration = response.eval_duration / 1e9
352
- prompt_eval_duration = response.prompt_eval_duration / 1e9
351
+ eval_duration = response.eval_duration.to_f / 1e9
352
+ prompt_eval_duration = response.prompt_eval_duration.to_f / 1e9
353
353
  stats_text = {
354
354
  eval_duration: Tins::Duration.new(eval_duration),
355
355
  eval_count: response.eval_count.to_i,
@@ -194,10 +194,6 @@ module OllamaChat::Parsing
194
194
  CONTENT_REGEXP = %r{
195
195
  (https?://\S+) # Match HTTP/HTTPS URLs
196
196
  | # OR
197
- (?<![a-zA-Z\d]) # Negative lookbehind: not part of a larger word
198
- \# # Literal # character (starts a tag)
199
- ([\w\]\[]+) # Tag content: alphanumeric, brackets, underscores
200
- | # OR
201
197
  (file://(?:[^\s#]+)) # Match file:// URLs
202
198
  | # OR
203
199
  "((?:\.\.|[~.]?)/(?:\\"|\\|[^"\\]+)+)" # Quoted file path with escaped " quotes
@@ -206,31 +202,27 @@ module OllamaChat::Parsing
206
202
  }x
207
203
  private_constant :CONTENT_REGEXP
208
204
 
209
- # Parses content and processes embedded resources based on document policy
205
+ # Parses a string for URLs, file refs, and image links, then returns
206
+ # the transformed content. Detects `http(s)` URLs, `file://` paths,
207
+ # quoted file paths, and collects any image URLs into the supplied
208
+ # `images` array.
210
209
  #
211
- # This method analyzes input content for URLs, tags, and file references,
212
- # fetches referenced resources, and processes them according to the current
213
- # document policy. It supports different processing modes for various content
214
- # types.
210
+ # @param content [String] the raw text to parse
211
+ # @param images [Array] mutable array that will be cleared
212
+ # then filled with discovered image URLs
215
213
  #
216
- # @param content [String] The input content string to parse
217
- # @param images [Array] An array to collect image references (will be cleared)
218
- # @return [Array<String, Documentrix::Utils::Tags>] Returns an array containing
219
- # the processed content string and tags object if any tags were found
214
+ # @return [String] the content after all supported transformations
215
+ # (URLs resolved, file refs expanded, image URLs collected)
220
216
  def parse_content(content, images)
221
217
  images.clear
222
- tags = Documentrix::Utils::Tags.new valid_tag: /\A#*([\w\]\[]+)/
223
218
  contents = [ content ]
224
- content.scan(CONTENT_REGEXP).each { |url, tag, file_url, quoted_file, file|
225
- if file && File.directory?(file)
219
+ content.scan(CONTENT_REGEXP).each { |url, file_url, quoted_file, file|
220
+ if file && Pathname.new(file).expand_path.directory?
226
221
  contents << generate_structure(file).to_json
227
222
  next
228
223
  end
229
224
  check_exist = false
230
225
  case
231
- when tag
232
- tags.add(tag)
233
- next
234
226
  when url
235
227
  links.add(url.to_s)
236
228
  source = url
@@ -271,7 +263,6 @@ module OllamaChat::Parsing
271
263
  end
272
264
  end
273
265
  }
274
- new_content = contents.select { _1.present? rescue nil }.compact * "\n\n"
275
- return new_content, (tags unless tags.empty?)
266
+ contents.select { _1.present? rescue nil }.compact * "\n\n"
276
267
  end
277
268
  end
@@ -198,7 +198,6 @@ module OllamaChat::PersonaeManagement
198
198
  # old content, and returns the result after editing.
199
199
  def edit_persona
200
200
  if persona = choose_persona
201
- persona = persona
202
201
  pathname = personae_directory + persona
203
202
  old_content = File.read(pathname)
204
203
  if edit_file(pathname)
@@ -211,6 +210,21 @@ module OllamaChat::PersonaeManagement
211
210
  end
212
211
  end
213
212
 
213
+ # Backs up the content of a selected persona file.
214
+ #
215
+ # Prompts the user to select a persona from the available list. If a persona
216
+ # is selected, its current content is read and saved to a designated backup
217
+ # location using `File.write`. This ensures a safe copy is preserved before
218
+ # any modifications are made to the original file.
219
+ def backup_persona
220
+ if persona = choose_persona
221
+ pathname = personae_directory + persona
222
+ old_content = File.read(pathname)
223
+ File.write(persona_backup_pathname(persona), old_content)
224
+ STDOUT.puts "Wrote backup of #{persona.to_s} to #{pathname.to_s.inspect}."
225
+ end
226
+ end
227
+
214
228
  # Displays detailed information about a selected persona.
215
229
  #
216
230
  # Shows the persona's profile using kramdown formatting with ansi parsing.
@@ -325,7 +339,7 @@ module OllamaChat::PersonaeManagement
325
339
  # @return [String] Formatted roleplay prompt
326
340
  def play_persona_prompt(persona:, persona_profile:)
327
341
  persona_name = persona.basename.sub_ext('')
328
- "Roleplay as persona %{persona_name} loaded from %{persona}\n\n%{persona_profile}" % {
342
+ "Roleplay as persona %{persona_name} (no nead to read the file) loaded from %{persona}\n\n%{persona_profile}" % {
329
343
  persona_name:, persona:, persona_profile:
330
344
  }
331
345
  end
@@ -119,16 +119,18 @@ module OllamaChat::ToolCalling
119
119
  # tools and handles the user's selection by adding the chosen tool to the
120
120
  # list of enabled tools and sorting the list.
121
121
  def enable_tool
122
- select_tools = configured_tools - enabled_tools
123
- select_tools += [ '[EXIT]' ]
124
- case chosen = OllamaChat::Utils::Chooser.choose(select_tools)
125
- when '[EXIT]', nil
126
- STDOUT.puts "Exiting chooser."
127
- return
128
- when *select_tools
129
- enabled_tools << chosen
130
- enabled_tools.sort!
131
- puts "Enabled tool %s" % bold { chosen }
122
+ loop do
123
+ select_tools = configured_tools - enabled_tools
124
+ select_tools = [ '[EXIT]' ] + select_tools
125
+ case chosen = OllamaChat::Utils::Chooser.choose(select_tools)
126
+ when '[EXIT]', nil
127
+ STDOUT.puts "Exiting chooser."
128
+ return
129
+ when *select_tools
130
+ enabled_tools << chosen
131
+ enabled_tools.sort!
132
+ puts "Enabled tool %s" % bold { chosen }
133
+ end
132
134
  end
133
135
  end
134
136
 
@@ -141,15 +143,17 @@ module OllamaChat::ToolCalling
141
143
  # the chosen tool from the list of enabled tools and sorting the list
142
144
  # afterwards.
143
145
  def disable_tool
144
- select_tools = enabled_tools
145
- select_tools += [ '[EXIT]' ]
146
- case chosen = OllamaChat::Utils::Chooser.choose(select_tools)
147
- when '[EXIT]', nil
148
- STDOUT.puts "Exiting chooser."
149
- return
150
- when *select_tools
151
- enabled_tools.delete chosen
152
- puts "Disabled tool %s" % bold { chosen }
146
+ loop do
147
+ select_tools = enabled_tools
148
+ select_tools = [ '[EXIT]' ] + select_tools
149
+ case chosen = OllamaChat::Utils::Chooser.choose(select_tools)
150
+ when '[EXIT]', nil
151
+ STDOUT.puts "Exiting chooser."
152
+ return
153
+ when *select_tools
154
+ enabled_tools.delete chosen
155
+ puts "Disabled tool %s" % bold { chosen }
156
+ end
153
157
  end
154
158
  end
155
159
 
@@ -27,9 +27,10 @@ class OllamaChat::Tools::FileContext
27
27
  function: Tool::Function.new(
28
28
  name:,
29
29
  description: <<~EOT,
30
- Semantic file snapshot Gathers AST‑style info (e.g., classes,
31
- methods) from all matching files (pattern) in directory. Useful for
32
- LLMs to reason about code structure
30
+ Reads all files matching a glob pattern like `lib/**/*.rb` and
31
+ returns their contents plus metadata. Provides file size, line count,
32
+ and tags. Useful for building codebase context to send to language
33
+ models or documenting project structure.
33
34
  EOT
34
35
  parameters: Tool::Function::Parameters.new(
35
36
  type: 'object',
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.85'
3
+ VERSION = '0.0.86'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/ollama_chat.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama_chat 0.0.85 ruby lib
2
+ # stub: ollama_chat 0.0.86 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama_chat".freeze
6
- s.version = "0.0.85".freeze
6
+ s.version = "0.0.86".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]
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
35
35
  s.add_development_dependency(%q<utils>.freeze, [">= 0".freeze])
36
36
  s.add_runtime_dependency(%q<excon>.freeze, ["~> 1.0".freeze])
37
37
  s.add_runtime_dependency(%q<ollama-ruby>.freeze, ["~> 1.21".freeze])
38
- s.add_runtime_dependency(%q<documentrix>.freeze, [">= 0.1.0".freeze])
38
+ s.add_runtime_dependency(%q<documentrix>.freeze, [">= 0.1.1".freeze])
39
39
  s.add_runtime_dependency(%q<unix_socks>.freeze, ["~> 0.3".freeze])
40
40
  s.add_runtime_dependency(%q<rss>.freeze, ["~> 0.3".freeze])
41
41
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
@@ -128,12 +128,6 @@ describe OllamaChat::Parsing do
128
128
  end
129
129
 
130
130
  describe '#parse_content' do
131
- it 'can parse tags' do
132
- content, tags = chat.parse_content("see #foobar …", [])
133
- expect(content).to eq 'see #foobar …'
134
- expect(tags).to include('foobar')
135
- end
136
-
137
131
  it 'can parse https URLs' do
138
132
  stub_request(:get, "https://www.example.com/foo.html").
139
133
  with(headers: { 'Host' => 'www.example.com' }).
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.85
4
+ version: 0.0.86
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -169,14 +169,14 @@ dependencies:
169
169
  requirements:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
- version: 0.1.0
172
+ version: 0.1.1
173
173
  type: :runtime
174
174
  prerelease: false
175
175
  version_requirements: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - ">="
178
178
  - !ruby/object:Gem::Version
179
- version: 0.1.0
179
+ version: 0.1.1
180
180
  - !ruby/object:Gem::Dependency
181
181
  name: unix_socks
182
182
  requirement: !ruby/object:Gem::Requirement