Class: Brute::Store::MessageStore
- Inherits:
-
Object
- Object
- Brute::Store::MessageStore
- Defined in:
- lib/brute/store/message_store.rb
Overview
Stores session messages as individual JSON files in the OpenCode parts format. Each session gets a directory; each message is a numbered JSON file inside it.
Storage layout:
~/.brute/sessions/{session-id}/
session.meta.json
msg_0001.json
msg_0002.json
...
Message format matches OpenCode’s MessageV2.WithParts:
{ info: { id:, sessionID:, role:, time:, ... },
parts: [{ id:, type:, ... }, ...] }
Instance Attribute Summary collapse
-
#dir ⇒ Object
readonly
Returns the value of attribute dir.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
Instance Method Summary collapse
- #add_step_finish(message_id:, tokens: nil) ⇒ Object
- #add_text_part(message_id:, text:) ⇒ Object
- #add_tool_part(message_id:, tool:, call_id:, input:) ⇒ Object
- #append_assistant(message_id: nil, parent_id: nil, model_id: nil, provider_id: nil) ⇒ Object
- #append_user(text:, message_id: nil) ⇒ Object
-
#complete_assistant(message_id:, tokens: nil) ⇒ Object
Finalize an assistant message with token counts and completion time.
- #complete_tool_part(message_id:, call_id:, output:) ⇒ Object
- #count ⇒ Object
- #error_tool_part(message_id:, call_id:, error:) ⇒ Object
-
#initialize(session_id:, dir: nil) ⇒ MessageStore
constructor
A new instance of MessageStore.
- #message(id) ⇒ Object
- #messages ⇒ Object
Constructor Details
#initialize(session_id:, dir: nil) ⇒ MessageStore
Returns a new instance of MessageStore.
31 32 33 34 35 36 37 38 39 |
# File 'lib/brute/store/message_store.rb', line 31 def initialize(session_id:, dir: nil) @session_id = session_id @dir = dir || File.join(Dir.home, ".brute", "sessions", session_id) @messages = {} # id => { info:, parts: } @seq = 0 @part_seq = 0 @mutex = Mutex.new load_existing end |
Instance Attribute Details
#dir ⇒ Object (readonly)
Returns the value of attribute dir.
29 30 31 |
# File 'lib/brute/store/message_store.rb', line 29 def dir @dir end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
29 30 31 |
# File 'lib/brute/store/message_store.rb', line 29 def session_id @session_id end |
Instance Method Details
#add_step_finish(message_id:, tokens: nil) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/brute/store/message_store.rb', line 142 def add_step_finish(message_id:, tokens: nil) @mutex.synchronize do msg = @messages[] return unless msg part = { id: next_part_id, sessionID: @session_id, messageID: , type: "step-finish", reason: "stop", tokens: tokens || { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, } msg[:parts] << part persist() end end |
#add_text_part(message_id:, text:) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/brute/store/message_store.rb', line 79 def add_text_part(message_id:, text:) @mutex.synchronize do msg = @messages[] return unless msg part = { id: next_part_id, sessionID: @session_id, messageID: , type: "text", text: text } msg[:parts] << part persist() part[:id] end end |
#add_tool_part(message_id:, tool:, call_id:, input:) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/brute/store/message_store.rb', line 92 def add_tool_part(message_id:, tool:, call_id:, input:) @mutex.synchronize do msg = @messages[] return unless msg part = { id: next_part_id, sessionID: @session_id, messageID: , type: "tool", callID: call_id, tool: tool, state: { status: "running", input: input, time: { start: now_ms }, }, } msg[:parts] << part persist() part[:id] end end |
#append_assistant(message_id: nil, parent_id: nil, model_id: nil, provider_id: nil) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/brute/store/message_store.rb', line 59 def append_assistant(message_id: nil, parent_id: nil, model_id: nil, provider_id: nil) id = || msg = { info: { id: id, sessionID: @session_id, role: "assistant", parentID: parent_id, time: { created: now_ms }, modelID: model_id, providerID: provider_id, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, cost: 0.0, }, parts: [], } (id, msg) id end |
#append_user(text:, message_id: nil) ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/brute/store/message_store.rb', line 41 def append_user(text:, message_id: nil) id = || msg = { info: { id: id, sessionID: @session_id, role: "user", time: { created: now_ms }, }, parts: [ { id: next_part_id, sessionID: @session_id, messageID: id, type: "text", text: text }, ], } (id, msg) id end |
#complete_assistant(message_id:, tokens: nil) ⇒ Object
Finalize an assistant message with token counts and completion time.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/brute/store/message_store.rb', line 159 def complete_assistant(message_id:, tokens: nil) @mutex.synchronize do msg = @messages[] return unless msg msg[:info][:time][:completed] = now_ms if tokens msg[:info][:tokens] = { input: tokens[:input] || tokens[:total_input] || 0, output: tokens[:output] || tokens[:total_output] || 0, reasoning: tokens[:reasoning] || tokens[:total_reasoning] || 0, cache: tokens[:cache] || { read: 0, write: 0 }, } end persist() end end |
#complete_tool_part(message_id:, call_id:, output:) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/brute/store/message_store.rb', line 112 def complete_tool_part(message_id:, call_id:, output:) @mutex.synchronize do msg = @messages[] return unless msg part = msg[:parts].find { |p| p[:type] == "tool" && p[:callID] == call_id } return unless part part[:state][:status] = "completed" part[:state][:output] = output part[:state][:time][:end] = now_ms persist() end end |
#count ⇒ Object
185 186 187 |
# File 'lib/brute/store/message_store.rb', line 185 def count @mutex.synchronize { @messages.size } end |
#error_tool_part(message_id:, call_id:, error:) ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/brute/store/message_store.rb', line 127 def error_tool_part(message_id:, call_id:, error:) @mutex.synchronize do msg = @messages[] return unless msg part = msg[:parts].find { |p| p[:type] == "tool" && p[:callID] == call_id } return unless part part[:state][:status] = "error" part[:state][:error] = error.to_s part[:state][:time][:end] = now_ms persist() end end |
#message(id) ⇒ Object
181 182 183 |
# File 'lib/brute/store/message_store.rb', line 181 def (id) @mutex.synchronize { @messages[id] } end |
#messages ⇒ Object
177 178 179 |
# File 'lib/brute/store/message_store.rb', line 177 def @mutex.synchronize { @messages.values } end |