Class: OllamaChat::MessageList

Inherits:
Object
  • Object
show all
Includes:
MessageFormat, Term::ANSIColor
Defined in:
lib/ollama_chat/message_list.rb

Overview

Examples:

Creating a new message list

chat = OllamaChat::Chat.new
messages = OllamaChat::MessageList.new(chat)

Adding messages to the list

messages << Ollama::Message.new(role: 'user', content: 'Hello')
messages << Ollama::Message.new(role: 'assistant', content: 'Hi there!')

Displaying conversation history

messages.list_conversation(5)  # Shows last 5 exchanges

Clearing messages

messages.clear  # Removes all non-system messages

Loading a saved conversation

messages.load_conversation('conversation.json')

Saving current conversation

messages.save_conversation('my_conversation.json')

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from MessageFormat

#message_type, #talk_annotate, #think_annotate

Constructor Details

#initialize(chat) ⇒ MessageList

The initialize method sets up the message list for an OllamaChat session.

belongs to

Parameters:



39
40
41
42
# File 'lib/ollama_chat/message_list.rb', line 39

def initialize(chat)
  @chat     = chat
  @messages = []
end

Instance Attribute Details

#messagesObject (readonly)

The messages attribute reader returns the messages set for this object, initializing it lazily if needed.

The messages set is memoized, meaning it will only be created once per object instance and subsequent calls will return the same OllamaChat::MessageList instance.

messages associated with this instance



58
59
60
# File 'lib/ollama_chat/message_list.rb', line 58

def messages
  @messages
end

#systemObject (readonly)

The system attribute reader returns the system prompt for the chat session.



47
48
49
# File 'lib/ollama_chat/message_list.rb', line 47

def system
  @system
end

Instance Method Details

#<<(message) ⇒ OllamaChat::MessageList

The << operator appends a message to the list of messages and returns self.

Parameters:

  • message (Ollama::Message)

    the message to append

Returns:



80
81
82
83
# File 'lib/ollama_chat/message_list.rb', line 80

def <<(message)
  @messages << message
  self
end

#at_locationString

The at_location method returns the location/time/units information as a string if location is enabled.

Returns:

  • (String)

    the location information



285
286
287
288
289
290
291
292
293
294
295
# File 'lib/ollama_chat/message_list.rb', line 285

def at_location
  if @chat.location.on?
    location_name            = config.location.name
    location_decimal_degrees = config.location.decimal_degrees * ', '
    localtime                = Time.now.iso8601
    units                    = config.location.units
    config.prompts.location % {
      location_name:, location_decimal_degrees:, localtime:, units:,
    }
  end.to_s
end

#clearOllamaChat::MessageList

The clear method removes all non-system messages from the message list.

Returns:



70
71
72
73
# File 'lib/ollama_chat/message_list.rb', line 70

def clear
  @messages.delete_if { _1.role != 'system' }
  self
end

#configObject (private)

The config method provides access to the chat configuration object.

Returns:

  • (Object)

    the configuration object associated with the chat instance



302
303
304
# File 'lib/ollama_chat/message_list.rb', line 302

def config
  @chat.config
end

#determine_pager_commandObject (private)

The determine_pager_command method identifies an appropriate pager command for displaying content. It first checks for a default pager specified by the PAGER environment variable. If no default is found, it attempts to locate ‘less’ or ‘more’ in the system PATH as fallback options. The method returns the selected pager command, ensuring it includes the ‘-r’ flag for proper handling of raw control characters when a fallback pager is used.



314
315
316
# File 'lib/ollama_chat/message_list.rb', line 314

def determine_pager_command
  OllamaChat::EnvConfig::PAGER?
end

#drop(n) ⇒ Integer

Note:
  • System messages are preserved and not considered part of an exchange.

  • If only one incomplete exchange (a single user message) exists, it will be dropped first before removing complete exchanges.

Removes the last ‘n` exchanges from the message list. An exchange consists of a user and an assistant message. If only a single user message is present at the end, it will be removed first before proceeding with complete exchanges.

Parameters:

  • n (Integer)

    The number of exchanges to remove.

Returns:

  • (Integer)

    The actual number of complete exchanges removed. This may be less than ‘n` if there are not enough messages.



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/ollama_chat/message_list.rb', line 182

def drop(n)
  n = n.to_i.clamp(1, Float::INFINITY)
  non_system_messages = @messages.reject { _1.role == 'system' }
  if non_system_messages&.last&.role == 'user'
    @messages.pop
    n -= 1
  end
  if n == 0
    STDOUT.puts "Dropped the last exchange."
    return 1
  end
  if non_system_messages.empty?
    STDOUT.puts "No more exchanges can be dropped."
    return 0
  end
  m = 0
  while @messages.size > 1 && n > 0
    @messages.pop(2)
    m += 1
    n -= 1
  end
  STDOUT.puts "Dropped the last #{m} exchanges."
  m
end

#lastOllama::Message

Returns the last message from the conversation.

Returns:

  • (Ollama::Message)

    The last message in the conversation, or nil if there are no messages.



89
90
91
# File 'lib/ollama_chat/message_list.rb', line 89

def last
  @messages.last
end

#list_conversation(last = nil) ⇒ OllamaChat::MessageList

The list_conversation method displays the last n messages from the conversation.

Parameters:

  • last (Integer) (defaults to: nil)

    the number of messages to display (default: nil)

Returns:



142
143
144
145
146
147
148
149
150
# File 'lib/ollama_chat/message_list.rb', line 142

def list_conversation(last = nil)
  last = (last || @messages.size).clamp(0, @messages.size)
  use_pager do |output|
    @messages[-last..-1].to_a.each do |message|
      output.puts message_text_for(message)
    end
  end
  self
end

#load_conversation(filename) ⇒ OllamaChat::MessageList

The load_conversation method loads a conversation from a file and populates the message list.

Parameters:

  • filename (String)

    the path to the file containing the conversation

Returns:



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/ollama_chat/message_list.rb', line 109

def load_conversation(filename)
  unless File.exist?(filename)
    STDERR.puts "File #{filename.inspect} doesn't exist. Choose another filename."
    return
  end
  @messages =
    File.open(filename, 'r') do |output|
      JSON(output.read).map { Ollama::Message.from_hash(_1) }
    end
  self
end

#message_text_for(message) ⇒ String (private)

The message_text_for method generates formatted text representation of a message including its role, content, thinking annotations, and associated images. It applies color coding to different message roles and uses markdown parsing when enabled. The method also handles special formatting for thinking annotations and image references within the message.

Parameters:

  • message (Object)

    the message object containing role, content, thinking, and images

Returns:

  • (String)

    the formatted text representation of the message



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/ollama_chat/message_list.rb', line 344

def message_text_for(message)
  role_color = case message.role
               when 'user' then 172
               when 'assistant' then 111
               when 'system' then 213
               else 210
               end
  thinking = if @chat.think.on?
               think_annotate do
                 message.thinking.full? { @chat.markdown.on? ? @chat.kramdown_ansi_parse(_1) : _1 }
               end
             end
  content = message.content.full? { @chat.markdown.on? ? @chat.kramdown_ansi_parse(_1) : _1 }
  message_text = message_type(message.images) + " "
  message_text += bold { color(role_color) { message.role } }
  if thinking
    message_text += [ ?:, thinking, talk_annotate { content } ].compact.
      map { _1.chomp } * ?\n
  else
    message_text += ":\n#{content}"
  end
  message.images.full? { |images|
    message_text += "\nImages: " + italic { images.map(&:path) * ', ' }
  }
  message_text
end

#save_conversation(filename) ⇒ OllamaChat::MessageList

The save_conversation method saves the current conversation to a file.

Parameters:

  • filename (String)

    the path where the conversation will be saved

Returns:



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

def save_conversation(filename)
  if File.exist?(filename)
    STDERR.puts "File #{filename.inspect} already exists. Choose another filename."
    return
  end
  File.open(filename, ?w) do |output|
    output.puts JSON(@messages)
  end
  self
end

#second_lastOllama::Message

The second_last method returns the second-to-last message from the conversation if there are more than one non-system messages.

Returns:

  • (Ollama::Message)

    the second-to-last message



97
98
99
100
101
# File 'lib/ollama_chat/message_list.rb', line 97

def second_last
  if @messages.reject { _1.role == 'system' }.size > 1
    @messages[-2]
  end
end

#set_system_prompt(system) ⇒ OllamaChat::MessageList

Note:

This method:

  • Removes all existing system prompts from the message list

  • Adds the new system prompt to the beginning of the message list if provided

  • Handles edge cases such as clearing prompts when ‘system` is `nil` or `false`

Sets the system prompt for the chat session.

Parameters:

  • system (String, nil)

    The new system prompt. If ‘nil` or `false`, clears the system prompt.

Returns:



217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/ollama_chat/message_list.rb', line 217

def set_system_prompt(system)
  @messages.reject! { |msg| msg.role == 'system' }
  if new_system_prompt = system.full?(:to_s)
    @system = new_system_prompt
    @messages.unshift(
      Ollama::Message.new(role: 'system', content: self.system)
    )
  else
    @system = nil
  end
  self
end

#show_last(n = nil) ⇒ OllamaChat::MessageList

The show_last method displays the text of the last message if it is not from the user. It uses a pager for output and returns the instance itself.

Returns:



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/ollama_chat/message_list.rb', line 156

def show_last(n = nil)
  n ||= 1
  messages = @messages.reject { |message| message.role == 'user' }
  n = n.clamp(0..messages.size)
  n <= 0 and return
  use_pager do |output|
    messages[-n..-1].to_a.each do |message|
      output.puts message_text_for(message)
    end
  end
  self
end

#show_system_promptself, NilClass

The show_system_prompt method displays the system prompt configured for the chat session.

It retrieves the system prompt from the @system instance variable, parses it using Kramdown::ANSI, and removes any trailing newlines. If the resulting string is empty, the method returns immediately.

Otherwise, it prints a formatted message to the console, including the configured system prompt and its length in characters.

Returns:

  • (self, NilClass)

    nil if the system prompt is empty, otherwise self.



241
242
243
244
245
246
247
248
249
250
251
# File 'lib/ollama_chat/message_list.rb', line 241

def show_system_prompt
  system_prompt = @chat.kramdown_ansi_parse(system.to_s).gsub(/\n+\z/, '').full?
  system_prompt or return
  STDOUT.puts <<~EOT
    Configured system prompt is:
    #{system_prompt}

    System prompt length: #{bold{system_prompt.size}} characters.
  EOT
  self
end

#sizeInteger

Returns the number of messages stored in the message list.

Returns:

  • (Integer)

    The size of the message list.



63
64
65
# File 'lib/ollama_chat/message_list.rb', line 63

def size
  @messages.size
end

#to_aryArray

The to_ary method converts the message list into an array of Ollama::Message objects. If location support was enabled and the message list contains a system message, the system messages is decorated with the curent location, time, and unit preferences.

messages in the list.

Returns:

  • (Array)

    An array of Ollama::Message objects representing the



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/ollama_chat/message_list.rb', line 260

def to_ary
  location = at_location.full?
  add_system = !!location
  result = @messages.map do |message|
    if message.role == 'system' && location
      add_system = false
      content = message.content + "\n\n#{location}"
      Ollama::Message.new(role: message.role, content:)
    else
      message
    end
  end
  if add_system
    prompt = @chat.config.system_prompts.assistant?
    content = [ prompt, location ].compact * "\n\n"
    message = Ollama::Message.new(role: 'system', content:)
    result.unshift message
  end
  result
end

#use_pager {|the| ... } ⇒ Object (private)

The use_pager method wraps the given block with a pager context. If the output would exceed the terminal’s line capacity, it pipes the content through an appropriate pager command (like ‘less’ or ‘more’).

Yields:

  • A block that yields an IO object to write output to

Yield Parameters:

  • the (IO)

    IO object to write to



324
325
326
327
328
329
330
331
332
# File 'lib/ollama_chat/message_list.rb', line 324

def use_pager
  command       = determine_pager_command
  output_buffer = StringIO.new
  yield output_buffer
  messages = output_buffer.string
  Kramdown::ANSI::Pager.pager(command:, lines: messages.count(?\n)) do |output|
    output.puts messages
  end
end