Class: TUI::MessageStore
- Inherits:
-
Object
- Object
- TUI::MessageStore
- Defined in:
- lib/tui/message_store.rb
Overview
Thread-safe in-memory store for chat entries displayed in the TUI. Replaces Events::Subscribers::MessageCollector in the WebSocket-based TUI, with no dependency on Rails or the Events module.
Accepts Action Cable event payloads and stores typed entries:
-
‘:rendered, data:, event_type:, id:` for events with structured decorator output
-
‘:message, role:, content:, id:` for user/agent messages (fallback)
-
‘:tool_counter, calls:, responses:` for tool activity
Structured data takes priority when available. Events with nil rendered content fall back to existing behavior: tool events aggregate into counters, messages store role and content.
Tool counters aggregate per agent turn: a new counter starts when a tool_call arrives after a message entry. Consecutive tool events increment the same counter until the next message breaks the chain.
When an event arrives with ‘“action” => “update”` and a known `“id”`, the existing entry is replaced in-place, preserving display order.
Constant Summary collapse
- MESSAGE_TYPES =
%w[user_message agent_message].freeze
- ROLE_MAP =
{ "user_message" => "user", "agent_message" => "assistant" }.freeze
Instance Method Summary collapse
-
#clear ⇒ void
Removes all entries.
-
#initialize ⇒ MessageStore
constructor
A new instance of MessageStore.
-
#last_pending_user_message ⇒ Hash?
Returns the last pending user message for recall editing.
-
#messages ⇒ Array<Hash>
Thread-safe copy of stored entries.
-
#process_event(event_data) ⇒ Boolean
Processes a raw event payload from the WebSocket channel.
-
#remove_by_id(event_id) ⇒ Boolean
Removes an entry by its event ID.
Constructor Details
#initialize ⇒ MessageStore
Returns a new instance of MessageStore.
31 32 33 34 35 |
# File 'lib/tui/message_store.rb', line 31 def initialize @entries = [] @entries_by_id = {} @mutex = Mutex.new end |
Instance Method Details
#clear ⇒ void
This method returns an undefined value.
Removes all entries. Called on view mode change and session switch to prepare for re-decorated viewport events from the server.
76 77 78 79 80 81 |
# File 'lib/tui/message_store.rb', line 76 def clear @mutex.synchronize do @entries = [] @entries_by_id = {} end end |
#last_pending_user_message ⇒ Hash?
Returns the last pending user message for recall editing. Walks entries backwards and returns the first pending user_message found.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/tui/message_store.rb', line 87 def @mutex.synchronize do @entries.reverse_each do |entry| next unless entry[:event_type] == "user_message" if entry[:type] == :rendered && entry.dig(:data, "status") == "pending" return {id: entry[:id], content: entry.dig(:data, "content")} end # Only check the most recent user message break end nil end end |
#messages ⇒ Array<Hash>
Returns thread-safe copy of stored entries.
38 39 40 |
# File 'lib/tui/message_store.rb', line 38 def @mutex.synchronize { @entries.dup } end |
#process_event(event_data) ⇒ Boolean
Processes a raw event payload from the WebSocket channel. Uses structured decorator data when available; falls back to role/content extraction for messages and tool counter aggregation.
Events with ‘“action” => “update”` and a matching `“id”` replace the existing entry’s data in-place rather than appending.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/tui/message_store.rb', line 52 def process_event(event_data) event_id = event_data["id"] if event_data["action"] == "update" && event_id return update_existing(event_data, event_id) end rendered = extract_rendered(event_data) if rendered record_rendered(rendered, event_type: event_data["type"], id: event_id) else case event_data["type"] when "tool_call" then record_tool_call when "tool_response" then record_tool_response when *MESSAGE_TYPES then (event_data) else false end end end |
#remove_by_id(event_id) ⇒ Boolean
Removes an entry by its event ID. Used when a pending message is recalled for editing or deleted by another client.
108 109 110 111 112 113 114 115 116 |
# File 'lib/tui/message_store.rb', line 108 def remove_by_id(event_id) @mutex.synchronize do entry = @entries_by_id.delete(event_id) return false unless entry @entries.delete(entry) true end end |