Module: OllamaChat::SessionManagement

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

Overview

The OllamaChat::SessionHandling module provides methods for managing chat sessions, including creating, listing, switching, renaming, and deleting sessions.

It integrates closely with the database-backed Session model and ensures that session data is persisted correctly, especially the conversation history.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#sessionOllamaChat::Database::Models::Session (readonly)

The session reader returns the current session object.

Returns:



57
58
59
# File 'lib/ollama_chat/session_management.rb', line 57

def session
  @session
end

Instance Method Details

#change_session(name) ⇒ Object (private)

Changes to a different session, saving the current one and loading the new one.

Parameters:

  • name (String)

    the name or ID of the session to switch to



537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# File 'lib/ollama_chat/session_management.rb', line 537

def change_session(name)
  name.full? or name = ??
  previous_session = nil
  loop do
    if chosen_session = choose_session(name, except_id: session.id, allow_new: true)
      if chosen_session.nil? || chosen_session == session
        confirm?(
          prompt: "\n⏎  Same session chosen, Press any key to continue (%s). ",
          timeout: 3
        )
        break
      end
      session_close
      previous_session = session
      @session = chosen_session
      if session.lock?
        messages.read_conversation_jsonl(session.messages.to_s)
        if current_collection = session.current_collection.full? and
          database_collection?(current_collection)
        then
          set_current_collection(current_collection)
        else
          set_current_collection(:default)
        end
        session.current_model.full? { use_model(_1) }
        set_default_persona_name(session.default_persona_name.full? || :none)
        set_current_system_prompt(session.current_system_prompt.full? || 'default')
        session_apply
        log(:info, "Session changed", data: { session_id: session.id, name: session.name, previous_session_id: previous_session&.id })
        info_session
        break
      else
        @session = previous_session
        @session.lock
        name = ??
        confirm?(
          prompt: "\n⏎  Session locked: could not switch, Press any key to continue (%s). ",
          timeout: 3
        )
        redo
      end
    else
      STDOUT.puts "Cancelled."
      break
    end
  end
ensure
  set_previous_session_on_change(previous_session&.id)
  session_sync
end

#choose_session(session_name, except_id: nil, allow_new: false, exit_app: false) ⇒ OllamaChat::Database::Models::Session? (private)

Finds or selects a session based on a name, ID, or pattern.

Parameters:

  • session_name (String)

    the name, ID, or pattern to search for

  • except_id (String, Integer, nil) (defaults to: nil)

    an ID to exclude from the search results

  • allow_new (Boolean) (defaults to: false)

    whether to offer creating a new session

Returns:



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'lib/ollama_chat/session_management.rb', line 608

def choose_session(session_name, except_id: nil, allow_new: false, exit_app: false)
  session_name = session_name.to_s
  session_query = models::Session
  if except_id
    session_query = session_query.where(Sequel[:id] !~ except_id)
  end
  if session_name =~ /\A\d+\z/ and
    session = session_query.first(id: session_name)
  then
    return session
  end
  selector = if session_name =~ /\A\?+(.*)\z/
               session_name = nil
               Regexp.new($1)
             end
  if session_name and session = session_query.first(name: session_name)
    session
  elsif selector
    now = Time.now
    sessions = session_query.order(Sequel.desc(:updated_at)).map { |session|
      duration = session.age(now:)
      es       = session.estimate_tokens
      count    = session.count_messages
      locked   = if pid = session.locked?
                   if pid == $$
                     " 🔓#{pid} "
                   else
                     " 🔐#{pid} "
                   end
                 else
                   ' '
                 end
      display     = <<~EOT.strip
        #{session.name} 🆔#{session.id}#{locked}📨#{count} 🧩#{es.tokens_formatted}#{duration}
      EOT
      SearchUI::Wrapper.new(
        session.name,
        display:
      )
    }
    selector and sessions = sessions.select { _1 =~ selector }
    session_name = if sessions.size == 1
                      sessions.first.value
                    else
                      allow_new and sessions.unshift(SearchUI::Wrapper.new('[new]', display: '[NEW]'))
                      if exit_app
                        sessions.unshift(SearchUI::Wrapper.new('[quit-app]', display: '[QUIT-APP]'))
                      end
                      sessions.unshift(SearchUI::Wrapper.new('[exit]', display: '[EXIT]'))
                      value = choose_entry(sessions, prompt: 'Select a chat session: %s')&.value
                      if value == '[new]'
                        return new_session
                      elsif value == '[quit-app]'
                        return :quit_app
                      elsif value == '[exit]'
                        return nil
                      end
                      value
                    end
    if session_name
      session_query.first(name: session_name)
    end
  end
end

#delete_sessionObject (private)

Deletes the current session and prompts the user to pick a new one to switch to.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/ollama_chat/session_management.rb', line 266

def delete_session
  current_session_name, current_session_id = session.name, session.id
  STDOUT.puts <<~EOT
    The current session
      #{current_session_name.inspect} (#{current_session_id})
    will be deleted, pick a new session to switch to.
  EOT
  confirm?(prompt: "\n⏎  Press any key to continue (%s). ", timeout: 3)
  chosen = choose_session(??, except_id: current_session_id, allow_new: true, exit_app: true)
  if chosen == :quit_app
    STDOUT.puts "Exiting application."
    exit 0
  end
  if chosen
    chosen.save
    confirm?(
      prompt: "🔔 Delete session #{current_session_name.inspect} (#{current_session_id})? (y/n) ",
      yes: /\Ay/i
    ) or return
    change_session(chosen.id)
    models::Session.where(id: current_session_id).destroy
    log(:info, "Session deleted", data: { session_id: current_session_id, name: current_session_name })
    STDOUT.puts "Just deleted session #{current_session_name.inspect}!"
  end
end

#derive_session_name(length: 128) ⇒ String? (private)

Derives a title for the session based on its content.

Parameters:

  • length (Integer) (defaults to: 128)

    the maximum length of the title (default: 128)

Returns:

  • (String, nil)

    the derived session name, or nil



488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/ollama_chat/session_management.rb', line 488

def derive_session_name(length: 128)
  content = messages.each_message.inject('') do |c, message|
    message.content.present? or next c
    sender_name = sender_name_displayed(message)
    c << "%s: %s\n\n" % [ sender_name, message.content ]
  end
  prompt = prompt(:session_title).to_s % { length:, content: }
  Infobar.busy(
    label: 'Naming session…',
    frames: :braille7,
    output: STDOUT,
  ) do
    generate(prompt:).full? do |name|
      name = name.
        gsub(/(\A(\s|[^A-Za-z])+|(\s|[^A-Za-z])+\z)/m, '').
        gsub(/\s+/, ' ')
      Kramdown::ANSI::Width.truncate(name, length:)
    end
  end
end

#determine_valid_new_name_for_session(action, default_name: nil) ⇒ String? (private)

Interactively prompts the user for a unique session name.

This method will keep prompting the user until a name is provided that does not already exist in the database, or until the user cancels.

Parameters:

  • action (String)

    a description of the action being performed

  • default_name (String, nil) (defaults to: nil)

    an optional prefill value for the prompt

Returns:

  • (String, nil)

    the unique session name, or nil if cancelled



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/ollama_chat/session_management.rb', line 153

def determine_valid_new_name_for_session(action, default_name: nil)
  session_name = nil
  loop do
    session_name = ask?(
      prompt: "❓ Enter new session name #{action}, C-c ⇒ cancel: ",
      prefill: default_name
    )
    if session_name.blank?
      STDOUT.puts "Cancelled."
      return nil
    end
    if models::Session.where(name: session_name).present?
      STDOUT.puts "Session named #{bold{session_name}} already exists."
    else
      break
    end
  end
  session_name
end

#duplicate_sessionObject (private)

Duplicates the current session into a new one.

This method creates a copy of the current session's attributes and prompts the user for a new name and whether to clear the duplicated session's message history.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/ollama_chat/session_management.rb', line 211

def duplicate_session
  name = switch_history(:session_name) do
    determine_valid_new_name_for_session(
      'to create', default_name: session.name
    )
  end or return
  old_session = session
  old_session.unlock
  @session = session.duplicate
  set_previous_session_on_change(old_session.id)
  session.update(name:)
  session.lock
  confirm?(
    prompt: "🔔 Clear messages of duplicated session? (y/n) ",
    yes: /\Ay/i
  ) and messages.clear
  session.current_model.full? {
    use_model(_1)
    copy_model_options_to_session
  }
  log(:info, "Session duplicated", data: { session_id: session.id, name: session.name, old_session_id: old_session.id })
  nil
end

#list_sessionsObject (private)

Lists all sessions in a formatted table.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ollama_chat/session_management.rb', line 94

def list_sessions
  use_pager do |output|
    table = Terminal::Table.new
    table.style = {
      all_separators: true,
      border:         :unicode_round,
    }
    table.headings = %w[ ID NAME SIZE #TOK COUNT UPDATED ].map { |header| bold { header } }
    now = Time.now
    models::Session.order(Sequel.desc(:updated_at)).each do |s|
      name        = Kramdown::ANSI::Width.truncate(s.name, length: 32)
      name        = session.id == s.id ? bold { name } : name
      name        = if pid = s.locked?
                      if pid == $$
                        "#{name} 🔓"
                      else
                        "#{name} 🔐"
                      end
                    else
                      name
                    end
      es = s.estimate_tokens
      table << [
        s.id.to_s,
        name,
        es.bytes_formatted,
        es.tokens_formatted,
        s.count_messages,
        s.age(now:),
      ]
    end
    table.align_column 0, :right
    table.align_column 2, :left
    table.align_column 3, :right
    table.align_column 4, :right
    table.align_column 5, :right
    output.puts table
  end
end

Loads the collection of links from the current session.

This method reads the links attribute from the session and deserializes it from JSONL format.

Returns:

  • (Array<String>)

    The list of links associated with the session.



48
49
50
51
# File 'lib/ollama_chat/session_management.rb', line 48

def load_links_from_session
  input = StringIO.new(session.links)
  OllamaChat::Utils::JSONJSONLIO.new('as.jsonl').read_io(input:)
end

#new_sessionOllamaChat::Database::Models::Session (private)

Creates a new, default session instance.

Returns:



65
66
67
# File 'lib/ollama_chat/session_management.rb', line 65

def new_session
  models::Session.with_defaults(self)
end

#preferred_sessionOllamaChat::Database::Models::Session (private)

Retrieves the preferred session from the database, or creates a new one if none exist.

Returns:



74
75
76
77
78
79
# File 'lib/ollama_chat/session_management.rb', line 74

def preferred_session
  models::Session.
    where(working_directory: Dir.pwd).
    order(:updated_at).last ||
    new_session
end

#previous_sessionOllamaChat::Database::Models::Session? (private)

Returns the session associated with the stored @previous_session_id, provided the session exists in the database and is not currently locked.

Returns:



86
87
88
89
90
91
# File 'lib/ollama_chat/session_management.rb', line 86

def previous_session
  @previous_session_id  or return
  prev = models::Session.where(id: @previous_session_id).first or return
  prev.locked? and return
  prev
end

#rename_sessionObject (private)

Note:

The use of 1.times do and redo ensures a single-retry capability for automatic name derivation.

Prompts the user to rename the current session interactively.

This method manages a sophisticated renaming workflow:

  1. It presents an interactive prompt using ask?.
  2. If the user provides an empty string, it attempts to automatically derive a new name using derive_session_name.
  3. After derivation, it uses redo to re-prompt the user, now pre-filling the prompt with the newly suggested name.
  4. If the user provides an arbitrary string, the session is renamed.
  5. If the user interrupts (e.g., via C-c), the process is cancelled.


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/ollama_chat/session_management.rb', line 305

def rename_session
  switch_history(:session_name) do
    name = nil
    1.times do
      derived = false
      prefill ||= session.name
      name = ask?(
        prompt: "❓ Enter the new name for the session (C-u ⇒ auto, C-c ⇒ cancel): ",
        prefill:
      )
      if name.nil?
        STDERR.puts "\nInterrupt: Session renaming was cancelled."
        return
      end
      if name.empty?
        if derived
          break
        else
          derived = true
          if prefill = derive_session_name.full?
            redo
          end
        end
      end
    end
    if name == session.name
      STDOUT.puts "Keeping the old name #{name.inspect}."
    elsif name.present?
      if exists = models::Session.where(name:).present?
        STDOUT.puts "Session with name #{name.inspect} already exists."
      else
        session.update(name:)
        log(:info, "Session renamed", data: { session_id: session.id, new_name: name })
        STDOUT.puts "Renamed current session to #{name.inspect}."
      end
    else
      STDERR.puts "Could not rename current session!"
    end
  rescue Sequel::UniqueConstraintViolation
    STDERR.puts "Could not rename session to #{name.inspect}, already exists!"
  end
end

#repair_group_uuidsObject (private)

Repairs group_uuid assignments in the current message list.

Walks the message array backwards looking for user messages (that are not tool calls) lacking a group_uuid. For each such anchor it:

  1. Swaps a preceding runtime_information tool message so the user message comes first (structural invariant).
  2. Propagates the anchor's UUID forward to all subsequent messages until the next user message or the end of the list.

After the backward pass, any remaining orphaned messages (e.g. system messages not part of a user-led exchange) are assigned fresh UUIDs via initialize_group_uuid.

Persists the repaired message list via store_messages_in_session.



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
# File 'lib/ollama_chat/session_management.rb', line 688

def repair_group_uuids
  msgs = messages.messages # Direct reference to the internal array
  msgs.empty? and return

  # Work backwards to find and repair user-anchored groups
  i = msgs.size - 1
  while i >= 0
    # Find the first 'user' message from the back that lacks a group_uuid
    if msgs[i].role == 'user' && !msgs[i].tool? && msgs[i].group_uuid.nil?
      anchor_index = i
      group_uuid = msgs[anchor_index].initialize_group_uuid.group_uuid

      # 1. Structural Swap: [RuntimeInfo, User] -> [User, RuntimeInfo]
      if anchor_index > 0 && msgs[anchor_index - 1].tool_name == 'runtime_information'
        msgs[anchor_index - 1], msgs[anchor_index] = msgs[anchor_index], msgs[anchor_index - 1]
        i            -= 1
        anchor_index -= 1
      end

      # 2. Forward Propagation: Assign the same UUID to all following messages
      # until we hit another user message or the end of the list.
      ((anchor_index + 1)...msgs.size).each do |k|
        msgs[k].group_uuid and break
        msgs[k].group_uuid = group_uuid
      end

      # We just fixed a whole block; the next possible anchor is before this one.
    end
    i -= 1
  end

  # Handle any orphaned messages that aren't part of a user-led exchange,
  # e.g. system messages
  msgs.each(&:initialize_group_uuid)

  store_messages_in_session
end

#report_conversation(name: nil, save: false) ⇒ Object (private)

Generates a report and displays or saves the result.

Parameters:

  • name (String, nil) (defaults to: nil)

    specific report template name (skips chooser)

  • save (Boolean) (defaults to: false)

    save to file instead of pager (default: false)



461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/ollama_chat/session_management.rb', line 461

def report_conversation(name: nil, save: false)
  if save
    filename = ask_for_filename?(action: 'for report') or return
    should_overwrite?(filename) or return
    result = report_session(name:)
    if result.full?
      filename.write(result)
      STDOUT.puts "File successfully written."
    else
      STDERR.puts "Nothing to report!"
    end
  else
    result = report_session(name:)
    if result.full?
      use_pager do |output|
        output.puts kramdown_ansi_parse(result)
      end
    else
      STDERR.puts "Nothing to report!"
    end
  end
end

#report_session(name: nil) ⇒ String? (private)

Generates a report document for the current session's conversation.

Uses a user-selected prompt template from the 'session' context (e.g. coding_brief, roleplay_story) to produce a single cohesive document describing the session. Uses compacted_messages (summary + recent tail) rather than each_message so the interpolated content stays bounded even after multiple compaction rounds.

Parameters:

  • name (String, nil) (defaults to: nil)

    specific template name (skips chooser)

Returns:

  • (String, nil)

    the report or nil if empty



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# File 'lib/ollama_chat/session_management.rb', line 428

def report_session(name: nil)
  content = messages.compacted_messages.inject('') do |c, message|
    message.content.present? or next c
    sender = sender_name_displayed(message)
    c << "%s: %s\n\n" % [ sender, message.content ]
  end
  content.empty? and return

  template = if name
               prompt(name, context: 'session')
             else
               choose_prompt(
                 context: 'session',
                 prompt: 'Which report template? %s'
               )
             end
  template or return

  system = prompt(:report, context: 'system').to_s

  Infobar.busy(
    label: 'Generating session report…',
    frames: :braille7,
    output: STDOUT,
  ) do
    generate(system:, prompt: template.to_s % { content: }, think: true)
  end
end

#session_applyObject (private)



257
258
259
260
261
262
# File 'lib/ollama_chat/session_management.rb', line 257

def session_apply
  session.update(working_directory: Dir.pwd)
  init_history
  repair_group_uuids
  session
end

#session_closeObject (private)

Closes the current session synchronizing it first and releasing the process lock. This should be called during application shutdown or when switching sessions to ensure the session is available for future instances.



528
529
530
531
# File 'lib/ollama_chat/session_management.rb', line 528

def session_close
  session_sync
  session.unlock
end

#session_syncOllamaChat::Database::Models::Session (private)

Synchronizes the current session state to the database.

Persists messages, links, and history, updates the working directory, and re-locks the session. Called before closing or switching sessions to ensure no unsaved state is lost.

Returns:



516
517
518
519
520
521
522
523
# File 'lib/ollama_chat/session_management.rb', line 516

def session_sync
  store_messages_in_session
  links.sync
  save_history
  session.working_directory = Dir.pwd
  session.lock
  session
end

#set_new_sessionnil (private)

Creates and activates a new session with a unique name.

This method prompts for a name, initializes a new session record, locks it, and sets up the associated model and options.

Returns:

  • (nil)


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

def set_new_session
  name = switch_history(:session_name) do
    determine_valid_new_name_for_session('to create')
  end
  session_close
  previous_session_id = @session.id
  @session = new_session
  set_previous_session_on_change(previous_session_id)
  session.lock? or raise OllamaChat::OllamaChatError,
    "Could not lock session #{session.id} #{session.errors.full?(:inspect)}"
  if name.full?
    session.update(name:)
  else
    session.touch
  end
  session_apply
  messages.clear
  session.current_model.full? {
    use_model(_1)
    copy_model_options_to_session
  }
  log(:info, "New session created", data: { session_id: session.id, name: session.name })
  nil
ensure
  session.lock
end

#set_previous_session_on_change(previous_session_id) ⇒ Object (private)

Records the previous session ID after a session transition.

Stores the ID in @previous_session_id so that #previous_session can later retrieve it, unless the ID refers to the currently active session (i.e., the user re-selected the same session).

Parameters:

  • previous_session_id (Integer, nil)

    the ID of the session that was active before the transition; nil if no transition occurred



596
597
598
599
600
# File 'lib/ollama_chat/session_management.rb', line 596

def set_previous_session_on_change(previous_session_id)
  if previous_session_id && previous_session_id != session.id
    @previous_session_id = previous_session_id
  end
end

#setup_sessionOllamaChat::Database::Models::Session (private)

Sets up the current session based on command-line options or the last used session.

Returns:



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/ollama_chat/session_management.rb', line 239

def setup_session
  @session = if session_name = @opts[?l]
               choose_session(session_name,  allow_new: true)
             elsif @opts[?n]
               new_session
             else
               preferred_session
             end
  session or abort "No session named #{bold{session_name.inspect}} found."
  if session.lock?
    messages.read_conversation_jsonl(session.messages.to_s)
    session_apply
  else
    raise OllamaChat::OllamaChatError,
      "Could not lock session #{session.id} #{session.errors.full?(:inspect)}"
  end
end

#show_session(output: STDOUT) ⇒ Object (private)

Displays information about the current session.

Parameters:

  • output (IO) (defaults to: STDOUT)

    the output stream to write the information to (default: STDOUT)



137
138
139
140
141
142
143
# File 'lib/ollama_chat/session_management.rb', line 137

def show_session(output: STDOUT)
  es             = messages.full_estimate_tokens
  messages_count = session.count_messages
  output.puts "#{bold{session.name}} (#{italic{session.id}}), "\
    "#{es.tokens_formatted} (#{es.bytes_formatted}), "\
    "#{messages_count} messages"
end

Persists a collection of links to the session in the database.

This method serializes the links into JSONL format and updates the links attribute of the current session.

Parameters:

  • links (Enumerable)

    The collection of links to save.



32
33
34
35
36
37
38
39
40
# File 'lib/ollama_chat/session_management.rb', line 32

def store_links_in_session(links)
  output = StringIO.new
  OllamaChat::Utils::JSONJSONLIO.new('as.jsonl').write_io(
    output:, collection: links
  )
  session.update(links: output.string)
  log(:info, "Links stored in session", data: { session_id: session.id, count: links.count })
  self
end

#store_messages_in_sessionObject

Persists the current conversation messages to the database.

This method serializes the current message list into JSONL format and updates the messages attribute of the current session.



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/ollama_chat/session_management.rb', line 12

def store_messages_in_session
  output = StringIO.new
  messages.write_conversation_jsonl(output)
  session.update(messages: output.string)
  es = session.estimate_tokens # We just use the formatted bytecount
  log(:info, "Messages stored in session", data: {
    session_id:    session.id,
    size:          es.bytes_formatted,
    context_usage: ,
    messages:      session.count_messages
  })
  self
end

#summarize_conversation(sentence: false, save: false) ⇒ Object (private)

Summarizes the conversation and displays or saves the result.

Parameters:

  • sentence (Boolean) (defaults to: false)

    summarize each message in one sentence (default: false)

  • save (Boolean) (defaults to: false)

    save to file instead of pager (default: false)



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/ollama_chat/session_management.rb', line 391

def summarize_conversation(sentence: false, save: false)
  if save
    filename = ask_for_filename?(action: 'for summarization') or return
    should_overwrite?(filename) or return
    summary = summarize_session(sentence:) do |content|
      infobar.puts kramdown_ansi_parse(content)
    end
    if summary.full?
      filename.write(summary)
      STDOUT.puts "File successfully written."
    else
      STDERR.puts "Nothing to summarize!"
    end
  else
    summary = summarize_session(sentence:) do |content|
      infobar.puts kramdown_ansi_parse(content) << ?\n
    end
    if summary.full?
      use_pager do |output|
        output.puts kramdown_ansi_parse(summary)
      end
    else
      STDERR.puts "Nothing to summarize!"
    end
  end
end

#summarize_session(sentence: false, &block) ⇒ String? (private)

Generates a summary of the current session's conversation.

Parameters:

  • sentence (Boolean) (defaults to: false)

    whether to summarize each message in one sentence (default: false)

  • block (Proc)

    a block to handle each summary fragment

Returns:

  • (String, nil)

    the session summary or nil if empty



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/ollama_chat/session_management.rb', line 353

def summarize_session(sentence: false, &block)
  unit                  = sentence ? 'sentence' : 'paragraph'
  contents              = []
  messages_to_summarize = messages.each_message
  messages_to_summarize = messages_to_summarize.with_infobar(
    label:   'Summarizing message',
    total:   messages_to_summarize.count,
    message: infobar_message,
  )
  messages_to_summarize.each do |message|
    message_content = message.content.full?
    unless message_content
      -infobar
      next
    end
    sender_name_output = sender_name_displayed(message)
    sender_name        = sender_name_displayed(message, template: false)
    context            = contents * "\n\n"
    summary            = generate(
      prompt:  prompt(:session_summarize).to_s % {
        sender_name:, unit:, message_content:, context:
      }
    )
    content = '**%s**: %s' % [ sender_name_output, summary ]
    block&.(content)
    contents << content
    +infobar
  end
  contents.empty? and return

  contents.unshift(%{# Summary of session "#{session.name}"})
  contents * "\n\n"
end