Class: Brute::Store::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/brute/store/session.rb

Overview

Manages session persistence. Each session is a conversation that can be saved to disk and resumed later.

Storage layout (per-session directory):

~/.brute/sessions/{session-id}/
  session.meta.json          # session metadata
  context.json               # serialized conversation history
  msg_0001.json              # structured messages (OpenCode format)
  msg_0002.json
  ...

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id: nil, dir: nil) ⇒ Session

Returns a new instance of Session.



24
25
26
27
28
29
30
31
32
# File 'lib/brute/store/session.rb', line 24

def initialize(id: nil, dir: nil)
  @id = id || SecureRandom.uuid
  @base_dir = dir || File.join(Dir.home, ".brute", "sessions")
  @session_dir = File.join(@base_dir, @id)
  @path = File.join(@session_dir, "context.json")
  @title = nil
  @metadata = {}
  FileUtils.mkdir_p(@session_dir)
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



22
23
24
# File 'lib/brute/store/session.rb', line 22

def id
  @id
end

#pathObject (readonly)

Returns the value of attribute path.



22
23
24
# File 'lib/brute/store/session.rb', line 22

def path
  @path
end

#titleObject (readonly)

Returns the value of attribute title.



22
23
24
# File 'lib/brute/store/session.rb', line 22

def title
  @title
end

Class Method Details

.list(dir: nil) ⇒ Object

List all saved sessions, newest first.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/brute/store/session.rb', line 54

def self.list(dir: nil)
  dir ||= File.join(Dir.home, ".brute", "sessions")

  if File.directory?(dir)
    sessions = Dir.glob(File.join(dir, "*", "session.meta.json")).filter_map do |meta_path|
      data = JSON.parse(File.read(meta_path), symbolize_names: true)
      id = data[:id]
      next unless id
      {
        id: id,
        title: data[:title],
        saved_at: data[:saved_at],
        path: File.join(File.dirname(meta_path), "context.json"),
      }
    end

    sessions.sort_by { |s| s[:saved_at] || "" }.reverse
  else
    []
  end
end

Instance Method Details

#deleteObject



76
77
78
# File 'lib/brute/store/session.rb', line 76

def delete
  FileUtils.rm_rf(@session_dir) if File.directory?(@session_dir)
end

#message_storeObject



34
35
36
# File 'lib/brute/store/session.rb', line 34

def message_store
  @message_store ||= MessageStore.new(session_id: @id, dir: @session_dir)
end

#save_messages(messages, title: nil, metadata: {}) ⇒ Object

Serialize an array of LLM::Message objects to disk as JSON.



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/brute/store/session.rb', line 39

def save_messages(messages, title: nil, metadata: {})
  @title = title if title
  @metadata.merge!()

  data = {
    schema_version: 1,
    messages: messages.map { |m| { role: m.role.to_s, content: m.content.to_s } },
  }
  FileUtils.mkdir_p(File.dirname(@path))
  File.write(@path, JSON.pretty_generate(data))

  save_meta
end