ollama_chat 0.0.55 → 0.0.57

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: b2e00c933dc3118c04db47cbe4361fadcc500004a4f5ddd5aded07cea3bf6119
4
- data.tar.gz: 5b959cdf55031620153e8176f69aaa1bb815872a03d8e1ae172fcc0e4b3d2977
3
+ metadata.gz: '0812722ef6dcc9b968a058ad3e4d96a8944ba61aaf347e39b064881e67704c3c'
4
+ data.tar.gz: 03ceba63e04403a982eac23c0a1d5bbf9ff50512f83a721a2def8c5ed8ebec46
5
5
  SHA512:
6
- metadata.gz: ba54894c682fec7e4c3756d6875eb0644b0104a8affcb95b6b55d15416998ffdf667e8e308c21fb04a5191a67a646d7c4d11a2a0516fa20d122e25d825f00d62
7
- data.tar.gz: e0590805be446b6512ff0fbe3e44e960360be18681e9cd557de20bda2f2c8b44cd59e96059a62bdca4db311a6dcdcf3cb7c0e710e3e56570ba980e3e20dc7948
6
+ metadata.gz: 14949a812f2040b5f4ec0fb767abcb8e41e8ff2f64af2502cc9278d8245f9794e1d7f9bcab0b1b99214c80aa135b1c9b68551a5d208356fa521f3fb36bb8e7f3
7
+ data.tar.gz: 44a2dfcccaa933286b5c0a0a93d6916e4bfd8e2af516d16d3524b4c26ffb76a59fd50557aef8262416fd00e7cb88e12d73fab653a6fda3c470f23f9be937d767
data/CHANGES.md CHANGED
@@ -1,5 +1,65 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-01-21 v0.0.57
4
+
5
+ - Introduce `OllamaChat::StateSelectors` module with `StateSelector` class for
6
+ managing configurable states
7
+ - Replace simple string-based document policy and think mode with
8
+ `StateSelector` objects
9
+ - Add `allow_empty` parameter to `StateSelector#initialize` method to allow
10
+ empty states in voice output
11
+ - Update `StateSelector#selected=` to conditionally validate states based on
12
+ `allow_empty?`
13
+ - Refactor voice handling to use `StateSelector` by replacing `@current_voice`
14
+ with `@voices` `StateSelector`
15
+ - Update `FollowChat` to use `@voices.selected` instead of `@current_voice` for
16
+ voice selection
17
+ - Simplify `change_voice` method in `dialog.rb` to delegate to `@voices.choose`
18
+ - Update voice display in `information.rb` to use `@voices.show` instead of raw
19
+ voice name
20
+ - Update configuration format to support nested `think` settings with `mode`
21
+ and `loud` sub-properties
22
+ - Modify command handlers to use `document_policy.choose` and
23
+ `think_mode.choose` instead of legacy methods
24
+ - Update `OllamaChat::Chat` initialization to use `setup_state_selectors`
25
+ method
26
+ - Refactor `OllamaChat::ThinkControl` to use new state selector system
27
+ - Update `OllamaChat::Parsing` to reference `@document_policy.selected` instead
28
+ of `@document_policy`
29
+ - Update default configuration file to use format with nested think settings
30
+ - Add proper `attr_reader` for `document_policy` and `think_mode` state
31
+ selectors
32
+ - Update help text to reference new state selector system
33
+ - Update `OllamaChat::Switches` to handle nested think configuration
34
+ - Add `OllamaChat::StateSelectors` to required files in `lib/ollama_chat.rb`
35
+
36
+ ## 2026-01-17 v0.0.56
37
+
38
+ - Updated `context_spook` dependency from version **1.4** to **1.5**
39
+ - Expanded context file inclusion to support YAML files
40
+ - Updated `context_spook` method to pass `format` parameter to
41
+ `ContextSpook::generate_context` calls
42
+ - Added `context` section to default configuration with `format: JSON` setting
43
+ - Added `/reconnect` command to reset Ollama connection
44
+ - Introduced `connect_ollama` method to create new Ollama client instances with
45
+ current configuration
46
+ - Added `base_url` method to resolve connection URL from command-line or
47
+ environment config
48
+ - Updated `handle_input` to process `/reconnect` command and trigger
49
+ reconnection
50
+ - Enhanced `OllamaChat::InputContent#input` method to select and read multiple
51
+ files matching a glob pattern
52
+ - Updated `OllamaChat::InputContent#choose_filename` to accept a `chosen`
53
+ parameter for tracking selections
54
+ - Modified test cases in `spec/ollama_chat/input_content_spec.rb` to verify
55
+ multiple file selection behavior
56
+ - Files are now concatenated with filename headers in the output
57
+ - Maintains backward compatibility with single file selection
58
+ - Uses `Set` for efficient duplicate prevention during selection
59
+ - Removed specialized CSV parsing functionality from `OllamaChat::Parsing`
60
+ module
61
+ - Handle nil from `STDIN.gets` to prevent `NoMethodError`
62
+
3
63
  ## 2026-01-08 v0.0.55
4
64
 
5
65
  - Added `OllamaChat::Vim` class for inserting text into Vim buffers using the
data/README.md CHANGED
@@ -151,6 +151,7 @@ subject - the young, blue-eyed cat.
151
151
  The following commands can be given inside the chat, if prefixed by a `/`:
152
152
 
153
153
  ```
154
+ /reconnect reconnect to current ollama server
154
155
  /copy to copy last response to clipboard
155
156
  /paste to paste content
156
157
  /markdown toggle markdown output
data/Rakefile CHANGED
@@ -58,7 +58,7 @@ GemHadar do
58
58
  dependency 'bigdecimal', '~> 3.1'
59
59
  dependency 'csv', '~> 3.0'
60
60
  dependency 'const_conf', '~> 0.3'
61
- dependency 'context_spook', '~> 1.1'
61
+ dependency 'context_spook', '~> 1.5'
62
62
  development_dependency 'all_images', '~> 0.6'
63
63
  development_dependency 'rspec', '~> 3.2'
64
64
  development_dependency 'kramdown', '~> 2.0'
@@ -36,6 +36,7 @@ class OllamaChat::Chat
36
36
  include Term::ANSIColor
37
37
  include OllamaChat::DocumentCache
38
38
  include OllamaChat::Switches
39
+ include OllamaChat::StateSelectors
39
40
  include OllamaChat::ModelHandling
40
41
  include OllamaChat::Parsing
41
42
  include OllamaChat::SourceFetching
@@ -88,22 +89,13 @@ class OllamaChat::Chat
88
89
  @ollama_chat_config = OllamaChat::OllamaChatConfig.new(@opts[?f])
89
90
  self.config = @ollama_chat_config.config
90
91
  setup_switches(config)
91
- base_url = @opts[?u] || OllamaChat::EnvConfig::OLLAMA::URL
92
- @ollama = Ollama::Client.new(
93
- connect_timeout: config.timeouts.connect_timeout?,
94
- read_timeout: config.timeouts.read_timeout?,
95
- write_timeout: config.timeouts.write_timeout?,
96
- base_url: base_url,
97
- debug: ,
98
- user_agent:
99
- )
92
+ setup_state_selectors(config)
93
+ @ollama = connect_ollama
100
94
  if server_version.version < '0.9.0'.version
101
95
  raise ArgumentError, 'require ollama API version 0.9.0 or higher'
102
96
  end
103
- @document_policy = config.document_policy
104
97
  @model = choose_model(@opts[?m], config.model.name)
105
98
  @model_options = Ollama::Options[config.model.options]
106
- @think = config.think
107
99
  model_system = pull_model_unless_present(@model, @model_options)
108
100
  embedding_enabled.set(config.embedding.enabled && !@opts[?E])
109
101
  if @opts[?c]
@@ -119,7 +111,6 @@ class OllamaChat::Chat
119
111
  end
120
112
  @documents = setup_documents
121
113
  @cache = setup_cache
122
- @current_voice = config.voice.default
123
114
  @images = []
124
115
  @kramdown_ansi_styles = configure_kramdown_ansi_styles
125
116
  init_chat_history
@@ -128,6 +119,18 @@ class OllamaChat::Chat
128
119
  fix_config(e)
129
120
  end
130
121
 
122
+ # The document_policy reader returns the document policy selector for the chat session.
123
+ #
124
+ # @return [ OllamaChat::StateSelector ] the document policy selector object
125
+ # that manages the policy for handling document references in user text
126
+ attr_reader :document_policy
127
+
128
+ # The think_mode reader returns the think mode selector for the chat session.
129
+ #
130
+ # @return [ OllamaChat::StateSelector ] the think mode selector object
131
+ # that manages the thinking mode setting for the Ollama model interactions
132
+ attr_reader :think_mode
133
+
131
134
  # The debug method accesses the debug configuration setting.
132
135
  #
133
136
  # @return [TrueClass, FalseClass] the current debug mode status
@@ -213,6 +216,11 @@ class OllamaChat::Chat
213
216
  # the content to be processed, or nil for no action needed
214
217
  def handle_input(content)
215
218
  case content
219
+ when %r(^/reconnect)
220
+ STDERR.print green { "Reconnecting to ollama #{base_url.to_s.inspect}…" }
221
+ @ollama = connect_ollama
222
+ STDERR.puts green { " Done." }
223
+ :next
216
224
  when %r(^/copy$)
217
225
  copy_to_clipboard
218
226
  :next
@@ -307,10 +315,10 @@ class OllamaChat::Chat
307
315
  info
308
316
  :next
309
317
  when %r(^/document_policy$)
310
- choose_document_policy
318
+ document_policy.choose
311
319
  :next
312
320
  when %r(^/think$)
313
- choose_think_mode
321
+ think_mode.choose
314
322
  :next
315
323
  when %r(^/think_loud$)
316
324
  think_loud.toggle
@@ -388,9 +396,9 @@ class OllamaChat::Chat
388
396
  # the specified number of URLs. The processing approach varies based on the current
389
397
  # document policy and embedding status:
390
398
  #
391
- # - **Embedding mode**: When `@document_policy == 'embedding'` AND `@embedding.on?` is true,
399
+ # - **Embedding mode**: When `document_policy.selected == 'embedding'` AND `@embedding.on?` is true,
392
400
  # each result is embedded and the query is interpolated into the `web_embed` prompt.
393
- # - **Summarizing mode**: When `@document_policy == 'summarizing'`,
401
+ # - **Summarizing mode**: When `document_policy.selected == 'summarizing'`,
394
402
  # each result is summarized and both query and results are interpolated into the
395
403
  # `web_summarize` prompt.
396
404
  # - **Importing mode**: For all other cases, each result is imported and both query and
@@ -406,11 +414,11 @@ class OllamaChat::Chat
406
414
  # web('3', 'ruby programming tutorials')
407
415
  #
408
416
  # @example Web search with embedding policy
409
- # # With @document_policy == 'embedding' and @embedding.on?
417
+ # # With document_policy.selected == 'embedding' and @embedding.on?
410
418
  # # Processes results through embedding pipeline
411
419
  #
412
420
  # @example Web search with summarizing policy
413
- # # With @document_policy == 'summarizing'
421
+ # # With document_policy.selected == 'summarizing'
414
422
  # # Processes results through summarization pipeline
415
423
  #
416
424
  # @see #search_web
@@ -420,13 +428,13 @@ class OllamaChat::Chat
420
428
  # @see #summarize
421
429
  def web(count, query)
422
430
  urls = search_web(query, count.to_i) or return :next
423
- if @document_policy == 'embedding' && @embedding.on?
431
+ if document_policy.selected == 'embedding' && @embedding.on?
424
432
  prompt = config.prompts.web_embed
425
433
  urls.each do |url|
426
434
  fetch_source(url) { |url_io| embed_source(url_io, url) }
427
435
  end
428
436
  prompt.named_placeholders_interpolate({query:})
429
- elsif @document_policy == 'summarizing'
437
+ elsif document_policy.selected == 'summarizing'
430
438
  prompt = config.prompts.web_import
431
439
  results = urls.each_with_object('') do |url, content|
432
440
  summarize(url).full? do |c|
@@ -620,7 +628,7 @@ class OllamaChat::Chat
620
628
  handler = OllamaChat::FollowChat.new(
621
629
  chat: self,
622
630
  messages:,
623
- voice: (@current_voice if voice.on?)
631
+ voice: (@voices.selected if voice.on?)
624
632
  )
625
633
  begin
626
634
  retried = false
@@ -636,7 +644,7 @@ class OllamaChat::Chat
636
644
  if think? && !retried
637
645
  STDOUT.puts "#{bold('Error')}: in think mode, switch thinking off and retry."
638
646
  sleep 1
639
- @think = false
647
+ think_mode.selected = 'disabled'
640
648
  retried = true
641
649
  retry
642
650
  else
@@ -680,6 +688,21 @@ class OllamaChat::Chat
680
688
 
681
689
  private
682
690
 
691
+ def base_url
692
+ @opts[?u] || OllamaChat::EnvConfig::OLLAMA::URL
693
+ end
694
+
695
+ def connect_ollama
696
+ Ollama::Client.new(
697
+ connect_timeout: config.timeouts.connect_timeout?,
698
+ read_timeout: config.timeouts.read_timeout?,
699
+ write_timeout: config.timeouts.write_timeout?,
700
+ base_url: base_url,
701
+ debug: ,
702
+ user_agent:
703
+ )
704
+ end
705
+
683
706
  # The setup_documents method initializes the document processing pipeline by
684
707
  # configuring the embedding model and database connection.
685
708
  # It then loads specified documents into the system and returns the
@@ -12,9 +12,6 @@
12
12
  #
13
13
  # @example Changing the system prompt
14
14
  # chat.change_system_prompt('default_prompt', system: '?sherlock')
15
- #
16
- # @example Choosing a document policy
17
- # chat.choose_document_policy
18
15
  module OllamaChat::Dialog
19
16
  # The model_with_size method formats a model's size for display
20
17
  # by creating a formatted string that includes the model name and its size
@@ -76,7 +73,7 @@ module OllamaChat::Dialog
76
73
  # @return [ String ] the user's response with trailing newline removed
77
74
  def ask?(prompt:)
78
75
  print prompt
79
- STDIN.gets.chomp
76
+ STDIN.gets.to_s.chomp
80
77
  end
81
78
 
82
79
  # The choose_collection method presents a menu to select or create a document
@@ -104,41 +101,6 @@ module OllamaChat::Dialog
104
101
  info
105
102
  end
106
103
 
107
- # The document_policy method sets the policy for handling document imports.
108
- #
109
- # @param value [ String ] the document policy to be set
110
- attr_writer :document_policy
111
-
112
- # The choose_document_policy method presents a menu to select a document policy.
113
- # It allows the user to choose from importing, embedding, summarizing, or
114
- # ignoring documents.
115
- # The method displays available policies and sets the selected policy as the
116
- # current document policy.
117
- # If no valid policy is found, it defaults to the first option.
118
- # After selection, it outputs the chosen policy and displays the current
119
- # configuration information.
120
- def choose_document_policy
121
- policies = %w[ importing embedding summarizing ignoring ].sort
122
- current = if policies.index(@document_policy)
123
- @document_policy
124
- elsif policies.index(config.document_policy)
125
- config.document_policy
126
- else
127
- policies.first
128
- end
129
- policies.unshift('[EXIT]')
130
- policy = OllamaChat::Utils::Chooser.choose(policies)
131
- case policy
132
- when nil, '[EXIT]'
133
- STDOUT.puts "Exiting chooser."
134
- policy = current
135
- end
136
- self.document_policy = policy
137
- ensure
138
- STDOUT.puts "Using document policy #{bold{@document_policy}}."
139
- info
140
- end
141
-
142
104
  # The change_system_prompt method allows the user to select or enter a new
143
105
  # system prompt for the chat session.
144
106
  # It provides an interactive chooser when multiple prompts match the given
@@ -204,8 +166,7 @@ module OllamaChat::Dialog
204
166
  #
205
167
  # @return [ String ] the full name of the chosen voice
206
168
  def change_voice
207
- chosen = OllamaChat::Utils::Chooser.choose(config.voice.list)
208
- @current_voice = chosen.full? || config.voice.default
169
+ @voices.choose
209
170
  end
210
171
 
211
172
  # The message_list method creates and returns a new MessageList instance
@@ -2,6 +2,15 @@ require 'const_conf'
2
2
  require 'pathname'
3
3
 
4
4
  module OllamaChat
5
+ # Environment configuration module for OllamaChat
6
+ #
7
+ # This module provides a structured way to manage environment variables and
8
+ # configuration settings for the OllamaChat application. It uses the
9
+ # ConstConf library to define and manage configuration parameters with
10
+ # default values, descriptions, and decoding logic.
11
+ #
12
+ # The module organizes configuration into logical sections including general
13
+ # settings, Ollama-specific configurations, and chat-specific options.
5
14
  module EnvConfig
6
15
  include ConstConf
7
16
 
@@ -99,15 +99,13 @@ module OllamaChat::Information
99
99
  end
100
100
  markdown.show
101
101
  stream.show
102
- think_show
102
+ think_mode.show
103
103
  think_loud.show
104
104
  location.show
105
105
  voice.show
106
- if @voice.on?
107
- STDOUT.puts " Using voice #{bold{@current_voice}} to speak."
108
- end
106
+ @voice.on? and @voices.show
109
107
  STDOUT.puts "Documents database cache is #{@documents.nil? ? 'n/a' : bold{@documents.cache.class}}"
110
- STDOUT.puts "Document policy for references in user text: #{bold{@document_policy}}"
108
+ STDOUT.puts "Document policy for references in user text: #{bold{document_policy}}"
111
109
  STDOUT.puts "Currently selected search engine is #{bold(search_engine)}."
112
110
  STDOUT.puts "Conversation length: #{bold(@messages.size.to_s)} message(s)."
113
111
  nil
@@ -118,6 +116,7 @@ module OllamaChat::Information
118
116
  # interface.
119
117
  private def display_chat_help_message
120
118
  <<~EOT
119
+ /reconnect reconnect to current ollama server
121
120
  /copy to copy last response to clipboard
122
121
  /paste to paste content
123
122
  /markdown toggle markdown output
@@ -143,7 +142,7 @@ module OllamaChat::Information
143
142
  /summarize [n] source summarize the source's content in n words
144
143
  /embedding toggle embedding paused or not
145
144
  /embed source embed the source's content
146
- /web [n] query query web & for n(=1) results (policy: #@document_policy)
145
+ /web [n] query query web & for n(=1) results (policy: #{document_policy})
147
146
  /links [clear] display (or clear) links used in the chat
148
147
  /save filename store conversation messages
149
148
  /load filename load conversation messages
@@ -8,35 +8,40 @@ require 'tempfile'
8
8
  # interactive file selection and context collection for enhancing chat
9
9
  # interactions with local or remote content.
10
10
  module OllamaChat::InputContent
11
- # The input method reads and returns the content of a selected file.
11
+ # The input method selects and reads content from files matching a pattern.
12
12
  #
13
- # This method searches for files matching the given pattern and presents them
14
- # in an interactive chooser menu. If a file is selected, its content is read
15
- # and returned. If the user chooses to exit or no file is selected, the
16
- # method returns nil.
13
+ # This method prompts the user to select files matching the given glob
14
+ # pattern, reads their content, and returns a concatenated string with each
15
+ # file's content preceded by its filename.
17
16
  #
18
- # @param pattern [ String ] the glob pattern to search for files (defaults to '**/*')
17
+ # @param pattern [String] the glob pattern to search for files (defaults to '**/*')
19
18
  #
20
- # @return [ String, nil ] the content of the selected file or nil if no file
21
- # was chosen
19
+ # @return [String] a concatenated string of file contents with filenames as headers
22
20
  def input(pattern)
23
21
  pattern ||= '**/*'
24
- if filename = choose_filename(pattern)
25
- File.read(filename)
22
+ files = Set[]
23
+ while filename = choose_filename(pattern, chosen: files)
24
+ files << filename
26
25
  end
26
+ result = ''
27
+ files.each do |filename|
28
+ result << ("%s:\n\n%s\n\n" % [ filename, File.read(filename) ])
29
+ end
30
+ result.full?
27
31
  end
28
32
 
29
- # The choose_filename method selects a file from a list of matching files.
30
- #
31
- # This method searches for files matching the given glob pattern, presents
32
- # them in an interactive chooser menu, and returns the selected filename. If
33
- # the user chooses to exit or no file is selected, the method returns nil.
33
+ # The choose_filename method selects a file from a list of matching files. It
34
+ # searches for files matching the given pattern, excludes already chosen
35
+ # files, and presents them in an interactive chooser menu.
34
36
  #
35
- # @param pattern [ String ] the glob pattern to search for files (defaults to '**/*')
37
+ # @param pattern [ String ] the glob pattern to search for files
38
+ # @param chosen [ Set ] a set of already chosen filenames to exclude from
39
+ # selection
36
40
  #
37
- # @return [ String, nil ] the path to the selected file or nil if no file was chosen
38
- def choose_filename(pattern)
39
- files = Dir.glob(pattern).select { File.file?(_1) }
41
+ # @return [ String, nil ] the selected filename or nil if no file was chosen or user exited
42
+ def choose_filename(pattern, chosen: nil)
43
+ files = Dir.glob(pattern).reject { chosen&.member?(_1) }.
44
+ select { File.file?(_1) }
40
45
  files.unshift('[EXIT]')
41
46
  case chosen = OllamaChat::Utils::Chooser.choose(files)
42
47
  when '[EXIT]', nil
@@ -75,8 +80,9 @@ module OllamaChat::InputContent
75
80
  # @example Load default context
76
81
  # context_spook(nil)
77
82
  def context_spook(patterns)
83
+ format = config.context.format
78
84
  if patterns
79
- ContextSpook::generate_context(verbose: true) do |context|
85
+ ContextSpook::generate_context(verbose: true, format:) do |context|
80
86
  context do
81
87
  Dir.glob(patterns).each do |filename|
82
88
  File.file?(filename) or next
@@ -86,7 +92,7 @@ module OllamaChat::InputContent
86
92
  end.to_json
87
93
  else
88
94
  if context_filename = choose_filename('.contexts/*.rb')
89
- ContextSpook.generate_context(context_filename, verbose: true).to_json
95
+ ContextSpook.generate_context(context_filename, verbose: true, format:).to_json
90
96
  end
91
97
  end
92
98
  end
@@ -41,8 +41,11 @@ voice:
41
41
  markdown: true
42
42
  stream: true
43
43
  document_policy: importing
44
- think: false
45
- think_loud: true
44
+ think:
45
+ mode: disabled
46
+ loud: true
47
+ context:
48
+ format: JSON
46
49
  embedding:
47
50
  enabled: true
48
51
  paused: false
@@ -30,8 +30,6 @@ module OllamaChat::Parsing
30
30
  end
31
31
  source_io.rewind
32
32
  source_io.read
33
- when 'text/csv'
34
- parse_csv(source_io)
35
33
  when 'application/rss+xml'
36
34
  parse_rss(source_io)
37
35
  when 'application/atom+xml'
@@ -247,7 +245,7 @@ module OllamaChat::Parsing
247
245
  when 'image'
248
246
  add_image(images, source_io, source)
249
247
  when 'text', 'application', nil
250
- case @document_policy
248
+ case document_policy.selected
251
249
  when 'ignoring'
252
250
  nil
253
251
  when 'importing'
@@ -0,0 +1,146 @@
1
+ # A module that provides state selection functionality for OllamaChat.
2
+ #
3
+ # The StateSelectors module encapsulates the StateSelector class, which manages
4
+ # configurable states with selection and display capabilities. It is used to
5
+ # handle various settings in the chat application such as document policies and
6
+ # think modes, allowing users to dynamically configure
7
+ # different aspects of the chat session behavior.
8
+ module OllamaChat::StateSelectors
9
+ # A state selector that manages configurable states with selection and
10
+ # display capabilities.
11
+ class StateSelector
12
+ include Term::ANSIColor
13
+
14
+ # Initializes a new StateSelector with the given configuration.
15
+ #
16
+ # @param name [String] The name of the state selector for display purposes
17
+ # @param states [Array<String>] The list of valid states this selector can have
18
+ # @param default [String, nil] The default state to select (must be one of +states+)
19
+ # @param off [Array<String>, nil] The list of states that should be considered "off"
20
+ # @raise [ArgumentError] If +states+ is empty or +default+ is not in +states+
21
+ def initialize(name:, states:, default: nil, off: nil, allow_empty: false)
22
+ @name = name.to_s
23
+ @states = Set.new(states.map(&:to_s))
24
+ @allow_empty = allow_empty
25
+ unless allow_empty
26
+ @states.empty? and raise ArgumentError, 'states cannot be empty'
27
+ end
28
+ if default
29
+ @default = default.to_s
30
+ unless allow_empty?
31
+ @states.member?(@default) or raise ArgumentError,
32
+ "default has to be one of #{@states.to_a * ', '}."
33
+ end
34
+ @selected = @default
35
+ else
36
+ @selected = @states.first
37
+ end
38
+ @off = Array(off)
39
+ end
40
+
41
+ # The selected reader returns the currently selected state of the switch.
42
+ #
43
+ # @return [Object] the currently selected state value
44
+ attr_reader :selected
45
+
46
+ # The selected= method sets the selected state of the switch.
47
+ #
48
+ # @param value [Object] the value to be converted to a string and set as
49
+ # the selected state
50
+ #
51
+ # @raise [ArgumentError] if the provided value is not one of the valid states
52
+ def selected=(value)
53
+ value = value.to_s
54
+ unless allow_empty?
55
+ @states.member?(value) or raise ArgumentError,
56
+ "value has to be one of #{@states.to_a * ', '}."
57
+ end
58
+ @selected = value
59
+ end
60
+
61
+ # The allow_empty? method checks if the switch is allowed to be empty.
62
+ #
63
+ # @return [ TrueClass, FalseClass ] true if the switch is allowed to be
64
+ # empty, false otherwise
65
+ def allow_empty?
66
+ !!@allow_empty
67
+ end
68
+
69
+ # The off? method checks if the current state is in the off set.
70
+ #
71
+ # @return [ TrueClass, FalseClass ] true if the selected state is in the
72
+ # off set, false otherwise
73
+ def off?
74
+ @off.member?(@selected)
75
+ end
76
+
77
+ # The on? method checks if the switch is in the on state, returning true if
78
+ # it is enabled and false if it is disabled.
79
+ #
80
+ # @return [ TrueClass, FalseClass ] true if the switch is on, false if it
81
+ # is off
82
+ def on?
83
+ !off?
84
+ end
85
+
86
+ # The choose method presents a menu to select from available states.
87
+ #
88
+ # This method displays the available states to the user and allows them to
89
+ # select one. It handles the user's choice by updating the selected state
90
+ # or exiting the chooser if the user selects '[EXIT]' or cancels the selection.
91
+ #
92
+ # @return [ nil ] This method does not return a value; it updates the instance
93
+ # variable @selected based on user input.
94
+ def choose
95
+ states = @states + [ '[EXIT]' ]
96
+ case chosen = OllamaChat::Utils::Chooser.choose(states)
97
+ when '[EXIT]', nil
98
+ STDOUT.puts "Exiting chooser."
99
+ when
100
+ @selected = chosen
101
+ end
102
+ end
103
+
104
+ # The show method outputs the current value of the state selector.
105
+ #
106
+ # This method displays the name of the state selector along with its
107
+ # currently selected state in a formatted message to standard output.
108
+ def show
109
+ STDOUT.puts "#{@name} is #{bold(to_s)}."
110
+ end
111
+
112
+ # The to_s method returns the string representation of the selected state.
113
+ #
114
+ # @return [ String ] the string representation of the currently selected
115
+ # state
116
+ def to_s
117
+ @selected.to_s
118
+ end
119
+ end
120
+
121
+ # Sets up state selectors for document policy and think mode based on the
122
+ # provided configuration.
123
+ #
124
+ # @param config [ComplexConfig::Settings] the configuration object containing
125
+ # settings for document policy and think mode
126
+ def setup_state_selectors(config)
127
+ @document_policy = StateSelector.new(
128
+ name: 'Document policy',
129
+ default: config.document_policy,
130
+ states: %w[ embedding ignoring importing summarizing ],
131
+ off: %w[ ignoring ],
132
+ )
133
+ @think_mode = StateSelector.new(
134
+ name: 'Think mode',
135
+ default: config.think.mode,
136
+ states: %w[ enabled disabled low medium high ],
137
+ off: %w[ disabled ],
138
+ )
139
+ @voices = StateSelector.new(
140
+ name: 'Voice',
141
+ default: config.voice.default,
142
+ states: config.voice.list,
143
+ allow_empty: true
144
+ )
145
+ end
146
+ end
@@ -192,7 +192,7 @@ module OllamaChat::Switches
192
192
  )
193
193
 
194
194
  @think_loud = Switch.new(
195
- value: config.think_loud,
195
+ value: config.think.loud,
196
196
  msg: {
197
197
  true => "Thinking out loud, show thinking annotations.",
198
198
  false => "Thinking silently, don't show thinking annotations.",