Module: OllamaChat::Dialog

Included in:
Chat
Defined in:
lib/ollama_chat/dialog.rb

Overview

A module that provides interactive selection and configuration functionality for OllamaChat.

The Dialog module encapsulates various helper methods for choosing models, system prompts, document policies, and voices, as well as displaying information and managing chat sessions. It leverages user interaction components like choosers and prompts to enable dynamic configuration during runtime.

Instance Method Summary collapse

Instance Method Details

#ask?(prompt:, prefill: nil) ⇒ String

The ask? method prompts the user with a question and returns their input.

Parameters:

  • prompt (String) —

    the message to display to the user

Returns:

  • (String) —

    the user's response with trailing newline removed



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/ollama_chat/dialog.rb', line 17

def ask?(prompt:, prefill: nil)
  if prefill
    old_pre_input_hook = Reline.pre_input_hook
    Reline.pre_input_hook = -> { Reline.insert_text prefill.to_s }
  end
  speaker = speak(prompt, background: 10)
  Reline.readline(prompt, true)&.chomp

rescue Interrupt
  return nil
ensure
  speaker&.cancel_speaking
  prefill and Reline.pre_input_hook = old_pre_input_hook
end

#ask_for_filename?(action: nil) ⇒ Pathname? (private)

Prompts the user for a filename with history support.

Parameters:

  • action (String, nil) (defaults to: nil) —

    an optional action descriptor appended to the prompt, e.g. "for summarization" ("❓ Enter filename for summarization…")

Returns:

  • (Pathname, nil) —

    the user-supplied filename as a Pathname, or nil if the user cancels (C-c) or provides empty input



189
190
191
192
193
194
# File 'lib/ollama_chat/dialog.rb', line 189

def ask_for_filename?(action: nil)
  action and action = " #{action}"
  switch_history(:filename) {
    ask?(prompt: "❓ Enter filename#{action}, C-c ⇒ cancel: ")
  }.full? { Pathname.new(_1) }
end

#change_voice ⇒ String (private)

The change_voice method allows the user to select a voice from a list of available options. It uses the chooser to present the options and sets the selected voice as the current voice.

Returns:

  • (String) —

    the full name of the chosen voice



159
160
161
# File 'lib/ollama_chat/dialog.rb', line 159

def change_voice
  voices.choose
end

#choose_file_set(patterns) ⇒ Set<Pathname> (private)

The choose_file_set method aggregates all files matching the given patterns by repeatedly invoking choose_filename and collecting their expanded paths into a Set.

Parameters:

  • patterns (Array<String>) —

    optional glob patterns to match; defaults to '**/*'.

Returns:

  • (Set<Pathname>) —

    a set of expanded Pathname objects for each selected file.



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/ollama_chat/dialog.rb', line 125

def choose_file_set(patterns)
  patterns ||= '**/*'
  patterns = Array(patterns).map { Pathname.new(_1).expand_path }
  files = Set[]
  choose_with_state do
    while filename = choose_filename(patterns, chosen: files)
      files << filename.expand_path
    end
  end
  files
end

#confirm?(prompt:, timeout: nil, default: nil, yes: nil, output: STDOUT) ⇒ Object?

The confirm? method displays a prompt and reads a single keypress from the user in raw mode (no Enter required), returning that character. Unlike #ask?, it does not go through Reline, so it never pollutes the command history — making it the right tool for confirmation gates and terse single-key selections such as [v]iew / [c]lear menus.

The returned value depends on whether a positive-response matcher (yes) is supplied:

  • yes: nil (default) — the raw keypress is returned verbatim so the caller can dispatch on it (e.g. case key; when /\Av/i; ...); on timeout the default value is returned, and on interrupt (Ctrl-C) nil is returned.
  • yes: <Regexp/Object> — the keypress is returned only when it satisfies yes === keypress (e.g. yes: /\Ay/i); any other keypress, or an interrupt, yields nil.

Parameters:

  • prompt (String) —

    the prompt to display to the user

  • timeout (Integer, nil) (defaults to: nil) —

    optional timeout in seconds; if nil, the method blocks until input, if 0 it immediately returns the default value without waiting.

  • default (Object, nil) (defaults to: nil) —

    value returned when the timeout expires (defaults to nil)

  • yes (Object, nil) (defaults to: nil) —

    matcher (#===) that defines a positive response; when nil the raw keypress is returned for the caller to interpret (default: nil)

  • output (IO) (defaults to: STDOUT) —

    the IO object to write the prompt and the answer to

Returns:

  • (Object, nil) —

    see the dispatch rules above: the keypress (or default on timeout / nil on interrupt) when yes: is nil, otherwise the keypress only if it matches yes, else nil.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ollama_chat/dialog.rb', line 63

def confirm?(prompt:, timeout: nil, default: nil, yes: nil, output: STDOUT)
  return default if timeout&.zero?
  if prompt.include?('%s')
    prompt = prompt % (timeout ? ('timeout in %us' % timeout) : 'no timeout')
  end
  speaker = speak(prompt, background: 10) if timeout.nil?
  output.print prompt
  min    = 1
  time   = 0
  if timeout
    min  = 0
    time = timeout
  end
  exceptions = [ (IRB::Abort if defined? IRB), Interrupt, IOError ].compact
  begin
    keypress = STDIN.raw(min:, time:, intr: true) do |io|
      io.getc
    end
  rescue *exceptions
    output.puts "\u274C"
    return
  end
  answer = keypress || default
  case
  when yes.nil?
    if keypress
      output.puts "\u2328 #{answer}"
    else
      output.puts "\u231B #{answer}"
    end
    answer
  when answer =~ yes
    if keypress
      output.puts "\u2705 #{answer}"
    else
      output.puts "\u2611 #{answer}"
    end
    answer
  else
    if keypress
      output.puts "\u{1F6AB} #{answer}"
    else
      output.puts "\u231B #{answer}"
    end
    nil
  end
ensure
  speaker&.cancel_speaking
end

#connect_message(base_url:, prefix: '') ⇒ Object (private)

Displays an info-level feedback message indicating that a connection to an Ollama server is being established.

Parameters:

  • base_url (URI, String) —

    the target Ollama server URL

  • prefix (String) (defaults to: '') —

    an optional label prepended to "ollama" to distinguish the connection type, e.g. "embedding " for a dedicated embedding host (default: "")



144
145
146
# File 'lib/ollama_chat/dialog.rb', line 144

def connect_message(base_url:, prefix: '')
  feedback green { "Connecting to #{prefix}ollama #{redact_password(base_url).inspect}…" }, type: :info
end

#connect_message_done ⇒ Object (private)

Displays a success-level feedback message confirming that a connection was established. Counterpart to #connect_message.



150
151
152
# File 'lib/ollama_chat/dialog.rb', line 150

def connect_message_done
  feedback green { "Done." }, type: :success
end

#go_command(s, opt, defaults: {}) ⇒ Hash{String => Object} (private)

Parses and executes a command using Tins::GO.

Parameters:

  • s (String) —

    The Tins::GO option pattern string where each character represents an option, and ':' indicates the option requires an argument.

  • opt (Object) —

    The arguments to be parsed. This object is converted to a string, stripped of whitespace, and split into an array of strings.

Returns:

  • (Hash{String => Object}) —

    A hash mapping option names to their values.



178
179
180
# File 'lib/ollama_chat/dialog.rb', line 178

def go_command(s, opt, defaults: {})
  Tins::GO.go(s, opt.to_s.strip.split(/\s+/), defaults:)
end

#message_list ⇒ MessageList (private)

The message_list method creates and returns a new MessageList instance initialized with the current object as its argument.

Returns:



167
168
169
# File 'lib/ollama_chat/dialog.rb', line 167

def message_list
  MessageList.new(self)
end

#should_overwrite?(filename) ⇒ Boolean (private)

Checks whether a file can be written, prompting for overwrite confirmation if the file already exists.

Parameters:

  • filename (Pathname) —

    the target file to check

Returns:

  • (Boolean) —

    true if the file does not exist or the user confirms overwriting; false if the file exists and the user declines



203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/ollama_chat/dialog.rb', line 203

def should_overwrite?(filename)
  if filename.exist? && !confirm?(
      prompt: "🔔 File #{filename.to_s.inspect} already exists, overwrite? (y/n) ",
      yes: /\Ay/i
    )
  then
    feedback("File not written!", type: :warn)
    false
  else
    true
  end
end