Module: OllamaChat::PersonaeManagement

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

Overview

Module for managing personae in Ollama chat application

This module provides functionality to manage persona files, including creating, reading, updating, and deleting persona definitions stored as Markdown files in the personae directory.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#default_persona_nameString? (readonly, private)

The default_persona_name method returns the name of the default persona.

Returns:

  • (String, nil)

    the name of the default persona or nil if not set



102
103
104
# File 'lib/ollama_chat/personae_management.rb', line 102

def default_persona_name
  @default_persona_name
end

Instance Method Details

#add_personaObject (private)

Creates a new persona file interactively.

The method prompts the user to enter a name for the persona, creates an empty Markdown file with that name in the personae directory (if it does not already exist), opens the file in the configured editor, and finally returns the result of calling #personae_result on the created file.



178
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/personae_management.rb', line 178

def add_persona
  name = determine_valid_new_name_for_persona('to add') or return

  sources       = %w[ [CLIPBOARD] [FILES] [EMPTY/MANUAL] ]
  chosen_source = choose_entry(sources, prompt: 'Where shall we source the persona from? %s')
  chosen_source or return

  content = case chosen_source
            when '[CLIPBOARD]'
              perform_paste_from_clipboard(edit: false)
            when '[FILES]'
              patterns = ask?(
                prompt: "❓ Enter file patterns to load file, C-u ⇒ new, C-c ⇒ cancel: ",
                prefill: '**/*.{txt,md}'
              )
              patterns.nil? ? (return) : (patterns.present? ? load_prompt_from_file(patterns) : nil)
            else
              nil
            end

  pathname = personae_directory + "#{name}.md"
  final_content = content.full? || prompt(:persona).to_s
  pathname.write final_content

  edit_file(pathname)
  nil
end

#ask_to_set_default_persona_name(persona_name) ⇒ Boolean (private)

Interactively asks the user if they want to set the specified persona as the current default for the session.

If the user confirms, the default persona is updated via set_default_persona_name.

Parameters:

  • persona_name (String)

    the name of the persona to potentially set as default

Returns:

  • (Boolean)

    true if the persona was set as the default, false otherwise



638
639
640
641
642
643
644
645
646
647
648
649
# File 'lib/ollama_chat/personae_management.rb', line 638

def ask_to_set_default_persona_name(persona_name)
  yes = confirm?(
    prompt: "🔔 Set the new persona promt as current default persona? (y/n) ",
    yes: /\Ay/i
  )
  if yes
    set_default_persona_name(persona_name)
    true
  else
    false
  end
end

#assistantString, ...

Returns the name of the current default persona.

If the default persona is set to :none or is not configured, it returns nil.

Returns:

  • (String, Symbol, nil)

    the name of the default persona, or nil if none is set.



31
32
33
34
35
# File 'lib/ollama_chat/personae_management.rb', line 31

def assistant
  if default_persona_name && default_persona_name != :none
    default_persona_name
  end
end

#available_personaeArray<String> (private)

Returns a sorted list of available persona file names.

This method scans the personae directory for Markdown files and returns their basenames sorted alphabetically.

Returns:

  • (Array<String>)

    Sorted array of persona filenames without extension



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

def available_personae
  personae_directory.glob('*.md').map { pathname_to_persona_name(_1) }
end

#available_personae_namesArray<SearchUI::Wrapper> (private)

Retrieves a list of available personae, decorated with their favourite status.

Returns:

  • (Array<SearchUI::Wrapper>)

    a list of wrappers containing the persona name and its decorated display string



164
165
166
167
168
169
170
# File 'lib/ollama_chat/personae_management.rb', line 164

def available_personae_names
  favs = all_favourited('persona')
  personae_directory.glob('*.md').map(&:basename).sort.map { |bn|
    persona_name = bn.sub_ext('').to_s
    persona_name_with_favourite(persona_name, favs[persona_name])
  }
end

#backup_personaObject (private)

Backs up the content of a selected persona file.

Prompts the user to select a persona from the available list. If a persona is selected, its current content is read and saved to a designated backup location using File.write. This ensures a safe copy is preserved before any modifications are made to the original file.



295
296
297
298
299
300
301
302
303
# File 'lib/ollama_chat/personae_management.rb', line 295

def backup_persona
  if persona = choose_persona(prompt: 'Which persona should be safely archived? %s')
    pathname        = persona_name_to_pathname(persona)
    old_content     = pathname.read
    backup_pathname = persona_backup_pathname(persona)
    backup_pathname.write(old_content)
    STDOUT.puts "Wrote backup of #{persona.to_s} to #{backup_pathname.to_s.inspect}."
  end
end

#choose_persona(chosen: nil, none: false, prompt: 'Select a persona: %s') ⇒ String, ... (private)

Interactive method to select a persona from a list.

Allows the user to choose a persona from available options or exit. Selected persona is returned if successful, nil if user exits.

Parameters:

  • chosen (Set, nil) (defaults to: nil)

    Optional set of already selected personae

  • none (Boolean) (defaults to: false)

    whether to include a '[NONE]' option in the list

  • prompt (String) (defaults to: 'Select a persona: %s')

    the prompt message to display when asking for input (default: 'Select a persona: ')

Returns:

  • (String, Symbol, nil)

    The selected persona name, :none, or nil if user exits



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/ollama_chat/personae_management.rb', line 392

def choose_persona(chosen: nil, none: false, prompt: 'Select a persona: %s')
  personae_list = available_personae_names.
    reject { chosen&.member?(_1) }
  if personae_list.empty?
    STDERR.puts "No personae defined."
    return
  end
  personae_list.unshift('[NONE]') if none
  personae_list.unshift('[EXIT]')
  case persona = choose_entry(personae_list, prompt:)
  when '[EXIT]', nil
    STDOUT.puts "Exiting chooser."
    return
  when '[NONE]'
    :none
  else
    persona.value
  end
end

#convert_json_character_to_markdown(character, persona_name) ⇒ String (private)

Transforms raw character data (JSON or YAML) into a high-fidelity, structured Markdown persona profile using the persona architect prompt and the current persona template.

This method leverages the LLM to interpret raw attributes and expand them into evocative prose, ensuring the final output conforms to the system's standard persona structure. It also normalizes placeholders: {user} is converted to %user for runtime personalization, and {char} is replaced with the actual character name provided.

Parameters:

  • character (String)

    the raw character data in JSON format

  • persona_name (String)

    the name of the character to replace {char} with

Returns:

  • (String)

    the resulting structured Markdown persona profile



595
596
597
598
599
600
601
602
# File 'lib/ollama_chat/personae_management.rb', line 595

def convert_json_character_to_markdown(character, persona_name)
  generate(
    prompt:  prompt(:persona_architect).to_s % {
      character:,
      persona_template: prompt(:persona).to_s
    }
  ).gsub(/{{user}}/i, '%{user}').gsub(/{{char}}/i, persona_name)
end

#default_personaPathname? (private)

The default_persona method returns the path to the default persona file.

Returns:

  • (Pathname, nil)

    the Pathname object for the default persona file or nil if no default persona is set



108
109
110
111
112
# File 'lib/ollama_chat/personae_management.rb', line 108

def default_persona
  if default_persona_name && default_persona_name != :none
    personae_directory.join(default_persona_name).sub_ext('.md')
  end
end

#default_persona_profileString?

Retrieves the formatted roleplay prompt for the current default persona.

Returns:

  • (String, nil)

    The formatted persona profile or nil if none set



18
19
20
21
22
# File 'lib/ollama_chat/personae_management.rb', line 18

def default_persona_profile
  if persona = default_persona and persona.exist?
    play_persona(persona)
  end
end

#delete_personaString (private)

Interactive method to delete an existing persona with backup functionality.

Prompts the user to select a persona, asks for confirmation, and creates a timestamped backup of the persona file before deletion.

Returns:

  • (String)

    A JSON object with deletion status on success, or nil if persona was not selected or deletion was cancelled



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/ollama_chat/personae_management.rb', line 229

def delete_persona
  if persona = choose_persona(prompt: 'Which persona is no longer needed? %s')
    pathname        = persona_name_to_pathname(persona)
    backup_pathname = persona_backup_pathname(persona)
    if pathname.exist?
      STDOUT.puts "Deleting '#{bold{persona}}'..."
      STDOUT.puts "Backup will be saved to: #{backup_pathname}"

      if confirm?(prompt: "🔔 Are you sure? (y/n) ", yes: /\Ay/i)
        FileUtils.mv pathname, backup_pathname
        default_persona_name == persona and
          set_default_persona_name(:none)
        STDOUT.puts "Persona #{bold{persona}} deleted successfully"
        self
      else
        STDOUT.puts "Deletion cancelled."
        return
      end
    else
      STDOUT.puts "Persona not found."
      return
    end
  end
end

#determine_valid_new_name_for_persona(action) ⇒ String? (private)

Interactively determines a valid, non-conflicting name for a new persona.

Parameters:

  • action (String)

    The action being performed (e.g., 'to import')

Returns:

  • (String, nil)

    The validated persona name or nil if cancelled



518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/ollama_chat/personae_management.rb', line 518

def determine_valid_new_name_for_persona(action)
  persona_name = nil
  loop do
    persona_name = ask?(
      prompt: "❓ Enter new persona prompt name #{action}, C-c ⇒ cancel: "
    )
    if persona_name.nil?
      STDOUT.puts "Cancelled."
      return nil
    end
    if persona_name_to_pathname(persona_name).exist?
      STDOUT.puts "Persona prompt named #{bold{persona_name}} already exists."
    else
      break
    end
  end
  persona_name
end

#duplicate_personaself? (private)

Interactively duplicates an existing persona profile to a new name.

The process follows these steps:

  1. Prompts the user to select a source persona via choose_persona.
  2. Prompts the user to enter a unique name for the duplicate via determine_valid_new_name_for_persona.
  3. Copies the content from the source persona file to the new persona file.

Returns:

  • (self, nil)

    returns self on success, or nil if the operation was cancelled during persona selection or name entry.



547
548
549
550
551
552
553
554
# File 'lib/ollama_chat/personae_management.rb', line 547

def duplicate_persona
  persona          = choose_persona(prompt: 'Which persona shall serve as the blueprint? %s') or return
  pathname         = persona_name_to_pathname(persona)
  new_persona_name = determine_valid_new_name_for_persona('to ducplicate as') or return
  new_pathname     = persona_name_to_pathname(new_persona_name)
  new_pathname.write(pathname.read)
  self
end

#edit_personaString? (private)

Interactive method to edit an existing persona file.

Prompts the user to select a persona, opens it for editing, backups the old content, and returns the result after editing.

Returns:

  • (String, nil)

    persona name or nil if cancelled



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/ollama_chat/personae_management.rb', line 260

def edit_persona
  if persona = choose_persona(prompt: 'Which persona needs some polishing? %s')
    pathname = persona_name_to_pathname(persona)
    old_content = pathname.read
    if edit_file(pathname)
      changed = pathname.read != old_content
      if changed
        persona_backup_pathname(persona).write(old_content)
        ask_to_set_default_persona_name(persona)
      end
      persona
    end
  end
end

#export_personaself? (private)

Interactively exports a persona profile to a specified file.

The process follows these steps:

  1. Prompts the user to select a persona via choose_persona.
  2. Displays the persona's current content to the terminal.
  3. Prompts for a destination filename via determine_valid_output_filename.
  4. Writes the persona content to the chosen file.

Returns:

  • (self, nil)

    returns self if the export was successful, or nil if the process was cancelled during persona selection or filename entry.



615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/ollama_chat/personae_management.rb', line 615

def export_persona
  persona  = choose_persona(prompt: 'Which persona are you taking with you? %s') or return
  pathname = persona_name_to_pathname(persona)
  content  = pathname.read
  STDOUT.puts kramdown_ansi_parse(
    content + "\n---"
  )
  filename = determine_valid_output_filename('to write to') or return
  filename.write(content)
  STDOUT.puts "Persona #{persona.inspect} was exported as #{filename.to_path.inspect}?"
  self
end

#import_persona(pathname) ⇒ String? (private)

Imports a persona from a Markdown file, prompting for a new name.

Parameters:

  • pathname (Pathname, String)

    The path to the file to import

Returns:

  • (String, nil)

    The name of the imported persona or nil if cancelled



560
561
562
563
564
565
566
# File 'lib/ollama_chat/personae_management.rb', line 560

def import_persona(pathname)
  content          = pathname.read
  persona_name     = determine_valid_new_name_for_persona('to import') or return
  persona_pathname = persona_name_to_pathname(persona_name)
  persona_pathname.write(content)
  persona_name
end

#import_persona_from_json(json_data) ⇒ String? (private)

Imports a character persona from JSON data, prompts for a name, and saves the resulting Markdown profile to disk.

Parameters:

  • json_data (String)

    The raw character data in JSON format.

Returns:

  • (String, nil)

    The name of the created persona if successful, or nil if the process was cancelled or failed.



574
575
576
577
578
579
580
# File 'lib/ollama_chat/personae_management.rb', line 574

def import_persona_from_json(json_data)
  persona_name = determine_valid_new_name_for_persona('to import from JSON/PNG') or return
  markdown = convert_json_character_to_markdown(json_data, persona_name)
  persona_pathname = persona_name_to_pathname(persona_name)
  persona_pathname.write(markdown)
  persona_name
end

#info_personaObject (private)

Displays detailed information about a selected persona.

Shows the persona's profile using kramdown formatting with ansi parsing.



333
334
335
336
337
338
339
340
# File 'lib/ollama_chat/personae_management.rb', line 333

def info_persona
  if persona = choose_persona(prompt: 'Who would you like to learn more about? %s')
    description = persona_description(persona) or return
    use_pager do |output|
      output.puts kramdown_ansi_parse(description)
    end
  end
end

#initial_persona_nameString?

The initial_persona_name method retrieves the initial persona for the chat session.

Returns:

  • (String, nil)

    the persona name or nil if not set



11
12
13
# File 'lib/ollama_chat/personae_management.rb', line 11

def initial_persona_name
  session&.default_persona_name
end

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

Lists all available persona names in a formatted table.

Parameters:

  • output (IO) (defaults to: STDOUT)

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



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
370
371
372
373
374
375
376
377
378
379
# File 'lib/ollama_chat/personae_management.rb', line 345

def list_personae(output: STDOUT)
  use_pager do |output|
    personae = available_personae
    if personae.empty?
      STDOUT.puts "No personae defined."
      return
    end

    favs = all_favourited('persona')

    table = Terminal::Table.new
    table.style = {
      all_separators: true,
      border:         :unicode_round,
    }
    table.headings = %w[ NAME SIZE #TOK ].map { |header| bold { header } }

    personae.map do |persona_name|
      pathname = persona_name_to_pathname(persona_name)
      pathname.exist? or next
      [ pathname, pathname.size ]
    end.compact.sort_by(&:last).reverse_each do |pathname, size_bytes|
      persona_name = pathname.basename.sub_ext('').to_s
      es           = OllamaChat::TokenEstimator.estimate(size_bytes)
      is_default   = default_persona_name == persona_name
      display_name = prefix_favourite(is_default ? bold { persona_name } : persona_name, favs[persona_name])

      table << [ display_name, es.bytes_formatted, es.tokens_formatted, ]
    end

    table.align_column 1, :right
    table.align_column 2, :right
    output.puts table
  end
end

#load_persona_file(persona) ⇒ Array<Pathname, String> (private)

Loads a persona file from disk.

Parameters:

  • persona (String)

    The basename of the persona (without extension)

Returns:

  • (Array<Pathname, String>)

    Returns the pathname and its content as a string



459
460
461
462
463
464
# File 'lib/ollama_chat/personae_management.rb', line 459

def load_persona_file(persona)
  pathname = persona_name_to_pathname(persona)
  if pathname.exist?
    return pathname, pathname.read
  end
end

#load_personaeObject (private)

Interactive method to load multiple personae for use.

Allows sequential selection of multiple personae. Returns JSON results for each loaded persona.



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/ollama_chat/personae_management.rb', line 416

def load_personae
  chosen = Set[]
  choose_with_state do
    while persona = choose_persona(chosen:, prompt: 'Who else should join the conversation? %s')
      persona == :none and next
      chosen << persona
    end
  end

  if chosen.empty?
    STDOUT.puts "No persona loaded."
    return
  end

  personae_result(chosen)
end

#pathname_to_persona_name(pathname) ⇒ String (private)

Converts a persona pathname to its prompt name.

Parameters:

  • pathname (Pathname, String)

    The path to the persona file

Returns:

  • (String)

    The persona name without extension



510
511
512
# File 'lib/ollama_chat/personae_management.rb', line 510

def pathname_to_persona_name(pathname)
  pathname.basename.sub_ext('').to_s
end

#persona_backup_pathname(persona) ⇒ Pathname (private)

Note:

The timestamp ensures each backup has a unique filename when multiple backups of the same persona exist

Generates the backup pathname for a persona file with timestamp.

Creates a unique backup filename with the persona name, timestamp, and .md.bak extension. The timestamp format is YYYYMMDDHHMMSS for precise identification of backup versions.

Parameters:

  • persona (String)

    The persona name to create a backup for

Returns:

  • (Pathname)

    The full path to the backup file



217
218
219
220
# File 'lib/ollama_chat/personae_management.rb', line 217

def persona_backup_pathname(persona)
  timestamp = Time.now.strftime('%Y%m%d%H%M%S')
  personae_backup_directory + (persona + ?- + timestamp + '.md.bak')
end

#persona_description(persona, substitute_variables: false) ⇒ String? (private)

Generates a formatted description of a persona, including its path and profile.

Parameters:

  • persona (String)

    The persona name.

  • substitute_variables (Boolean) (defaults to: false)

    Whether to substitute variables in the profile.

Returns:

  • (String, nil)

    The formatted description or nil if the persona is not found.



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/ollama_chat/personae_management.rb', line 311

def persona_description(persona, substitute_variables: false)
  persona_path, persona_profile = load_persona_file(persona)
  if substitute_variables
    persona_profile = self.substitute_variables(persona_profile)
  end
  persona_profile or return
  <<~EOT
    # Persona #{persona}

    File #{persona_path.to_path}

    ---

    #{persona_profile}

    ---
  EOT
end

#persona_name_to_pathname(persona_name) ⇒ Pathname (private)

Converts a persona prompt name to its full filesystem pathname.

Parameters:

  • persona_name (String)

    The name of the persona (without extension)

Returns:

  • (Pathname)

    The full path to the .md persona file



502
503
504
# File 'lib/ollama_chat/personae_management.rb', line 502

def persona_name_to_pathname(persona_name)
  personae_directory.join(persona_name).sub_ext('.md')
end

#persona_name_with_favourite(name, favourited) ⇒ SearchUI::Wrapper (private)

Helper to wrap a persona name with its favourite status for the UI.

Parameters:

  • name (String)

    the name of the persona

  • favourited (Boolean)

    whether the persona is marked as a favourite

Returns:

  • (SearchUI::Wrapper)

    a wrapper containing the original name and the decorated display string



154
155
156
157
# File 'lib/ollama_chat/personae_management.rb', line 154

def persona_name_with_favourite(name, favourited)
  display = prefix_favourite(name, favourited)
  SearchUI::Wrapper.new(name, display:)
end

#personae_backup_directoryPathname (private)

Returns the directory path for persona backup files.

Returns:

  • (Pathname)

    Path to the backups subdirectory within the personae directory



55
56
57
# File 'lib/ollama_chat/personae_management.rb', line 55

def personae_backup_directory
  personae_directory + 'backups'
end

#personae_directoryPathname (private)

Note:

The directory is created automatically if it doesn't exist

Returns the directory path where persona files are stored.

The path is constructed using the XDG_CONFIG_HOME environment variable for platform-agnostic configuration storage.

Returns:

  • (Pathname)

    Path to the personae directory



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

def personae_directory
  OC::XDG_CONFIG_HOME + 'personae'
end

#personae_result(personae) ⇒ String? (private)

Compiles the descriptions for one or more personae into a single string.

Loads the profile for each persona and concatenates their descriptions.

Parameters:

  • personae (String, Array<String>)

    Persona name(s) to load.

Returns:

  • (String, nil)

    A string containing all descriptions, or nil if the result is blank.



440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/ollama_chat/personae_management.rb', line 440

def personae_result(personae)
  personae = Array(personae)

  result = +''

  personae.each do |persona|
    description = persona_description(persona, substitute_variables: true) or next
    result << description << "\n"
  end

  result.full?
end

#play_persona(persona) ⇒ String (private)

Generates the roleplay prompt string for a persona.

Creates a formatted prompt string that includes the persona name and profile.

Parameters:

  • persona (String, Pathname)

    The persona name or path to include in the prompt

Returns:

  • (String)

    Formatted roleplay prompt



485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/ollama_chat/personae_management.rb', line 485

def play_persona(persona)
  pathname, profile = load_persona_file(persona)
  profile = substitute_variables(profile)
  profile_intro = <<~EOT
    Roleplay as persona %{persona} (no nead to read the file) loaded from %{pathname}

    %{profile}
  EOT
  profile_intro % {
    persona:, pathname:, profile:
  }
end

#select_persona_path(no_prefill: false) ⇒ String? (private)

Prompts the user to select a persona, copies its filesystem path to the clipboard, and sets it as the prefill prompt for the next interaction.

Parameters:

  • no_prefill (Boolean) (defaults to: false)

    Whether to skip updating the prefill prompt.

Returns:

  • (String, nil)

    the filesystem path of the selected persona, or nil if the selection was cancelled.



281
282
283
284
285
286
287
# File 'lib/ollama_chat/personae_management.rb', line 281

def select_persona_path(no_prefill: false)
  persona = choose_persona(prompt: "Which persona's path do you need? %s") or return
  path = persona_name_to_pathname(persona).to_s
  perform_copy_to_clipboard(text: path, edit: false)
  no_prefill or self.prefill_prompt = path
  path
end

#set_default_personaString? (private)

Interactively selects a persona and sets it as the default for the session.

This method prompts the user to choose a persona from the available list using choose_persona. If a valid persona is selected, it updates the session and the internal state via set_default_persona_name.

Returns:

  • (String, nil)

    The name of the persona that was set as default, or nil if the selection was cancelled or no persona was chosen.



93
94
95
96
97
# File 'lib/ollama_chat/personae_management.rb', line 93

def set_default_persona
  if persona = choose_persona(none: true, prompt: 'Who would you like to talk to today? %s')
    set_default_persona_name(persona)
  end
end

#set_default_persona_name(persona_name) ⇒ String? (private)

Sets the default persona name and updates the session.

Parameters:

  • persona_name (String, nil)

    the name of the persona to set as default

Returns:

  • (String, nil)

    the set default persona name or nil if not set



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ollama_chat/personae_management.rb', line 73

def set_default_persona_name(persona_name)
  if persona_name.present? && persona_name != :none
    @default_persona_name = Pathname.new(persona_name).basename.sub_ext('').to_path
    @session.update(default_persona_name:)
  else
    @session.update(default_persona_name: nil)
    @default_persona_name = nil
  end
  messages.set_system_prompt(session&.current_system_prompt.full?)
  default_persona_name
end

#setup_persona_from_sessionPathname, ... (private)

Initializes the default persona for the current chat session.

This method ensures that a default persona is configured at startup:

  1. If a default persona is already set, it returns immediately.
  2. Otherwise, it attempts to retrieve the initial persona prompt name from the session and verifies if the corresponding Markdown file exists.
  3. If a valid file is found, it sets it as the default persona.
  4. The ensure block guarantees that the session always has a default persona assigned, falling back to :none if no valid persona is found.

Returns:

  • (Pathname, String, nil)

    The resulting default persona path or name, or nil if no persona is set.



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

def setup_persona_from_session
  default_persona and return
  if persona = initial_persona_name and
    persona_pathname = personae_directory + (persona + '.md') and
    persona_pathname.exist?
  then
    set_default_persona_name(persona_pathname)
  end
ensure
  default_persona or set_default_persona_name(:none)
end

#setup_personae_directoryObject (private)

Creates the personae directory structure if it doesn't already exist.

This method ensures both the main personae directory and the backups subdirectory exist for proper file organization.



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

def setup_personae_directory
  FileUtils.mkdir_p personae_backup_directory
end

#substitute_variables(profile) ⇒ String (private)

The substitute_variables method handles the substitution of variables in profiles. It replaces placeholders with actual values.

Parameters:

  • profile (String)

    the profile string to be processed

Returns:

  • (String)

    the processed string with variables substituted



472
473
474
475
476
# File 'lib/ollama_chat/personae_management.rb', line 472

def substitute_variables(profile)
  profile = profile.gsub(/%(?=[^{])/, '%%')
  profile = profile % { user: }
  profile
end