Class: Event
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Event
- Includes:
- Broadcasting
- Defined in:
- app/models/event.rb
Overview
A persisted record of something that happened during a session. Events are the single source of truth for conversation history —there is no separate chat log, only events attached to a session.
Defined Under Namespace
Modules: Broadcasting
Constant Summary collapse
- TYPES =
%w[system_message user_message agent_message tool_call tool_response].freeze
- LLM_TYPES =
%w[user_message agent_message].freeze
- CONTEXT_TYPES =
%w[system_message user_message agent_message tool_call tool_response].freeze
- CONVERSATION_TYPES =
%w[user_message agent_message system_message].freeze
- THINK_TOOL =
"think"- SPAWN_TOOLS =
%w[spawn_subagent spawn_specialist].freeze
- PENDING_STATUS =
"pending"- TOOL_TYPES =
Event types that require a tool_use_id to pair call with response.
%w[tool_call tool_response].freeze
- ROLE_MAP =
{"user_message" => "user", "agent_message" => "assistant"}.freeze
- BYTES_PER_TOKEN =
Heuristic: average bytes per token for English prose.
4
Constants included from Broadcasting
Broadcasting::ACTION_CREATE, Broadcasting::ACTION_UPDATE
Instance Attribute Summary collapse
-
#event_type ⇒ String
One of TYPES: system_message, user_message, agent_message, tool_call, tool_response.
-
#payload ⇒ Hash
Event-specific data (content, tool_name, tool_input, etc.).
-
#timestamp ⇒ Integer
Nanoseconds since epoch (Process::CLOCK_REALTIME).
-
#token_count ⇒ Integer
Cached token count for this event’s payload (0 until counted).
-
#tool_use_id ⇒ String
ID correlating tool_call and tool_response events (Anthropic-assigned, or a SecureRandom.uuid fallback when the API returns nil; required for tool_call and tool_response events).
Class Method Summary collapse
-
.context_events ⇒ ActiveRecord::Relation
Events included in the LLM context window (messages + tool interactions).
-
.deliverable ⇒ ActiveRecord::Relation
Events eligible for LLM context (excludes pending messages).
-
.excluding_spawn_events ⇒ ActiveRecord::Relation
Excludes spawn_subagent/spawn_specialist tool_call and tool_response events.
-
.llm_messages ⇒ ActiveRecord::Relation
Events that represent conversation turns sent to the LLM API.
-
.pending ⇒ ActiveRecord::Relation
User messages queued during active agent processing, not yet sent to LLM.
Instance Method Summary collapse
-
#api_role ⇒ String
Maps event_type to the Anthropic Messages API role.
-
#context_event? ⇒ Boolean
True if this event is part of the LLM context window.
-
#conversation_or_think? ⇒ Boolean
True if this is a conversation event (user/agent/system message) or a think tool_call — the events Mneme treats as “conversation” for boundary tracking.
-
#estimate_tokens ⇒ Integer
Heuristic token estimate: ~4 bytes per token for English prose.
-
#llm_message? ⇒ Boolean
True if this event represents an LLM conversation turn.
-
#pending? ⇒ Boolean
True if this is a pending message not yet sent to the LLM.
Instance Attribute Details
#event_type ⇒ String
Returns one of TYPES: system_message, user_message, agent_message, tool_call, tool_response.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 |
# File 'app/models/event.rb', line 20 class Event < ApplicationRecord include Event::Broadcasting TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze LLM_TYPES = %w[user_message agent_message].freeze CONTEXT_TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze CONVERSATION_TYPES = %w[user_message agent_message system_message].freeze THINK_TOOL = "think" SPAWN_TOOLS = %w[spawn_subagent spawn_specialist].freeze PENDING_STATUS = "pending" # Event types that require a tool_use_id to pair call with response. TOOL_TYPES = %w[tool_call tool_response].freeze ROLE_MAP = {"user_message" => "user", "agent_message" => "assistant"}.freeze # Heuristic: average bytes per token for English prose. BYTES_PER_TOKEN = 4 belongs_to :session has_many :pinned_events, dependent: :destroy validates :event_type, presence: true, inclusion: {in: TYPES} validates :payload, presence: true validates :timestamp, presence: true # Anthropic requires every tool_use to have a matching tool_result with the same ID validates :tool_use_id, presence: true, if: -> { event_type.in?(TOOL_TYPES) } after_create :schedule_token_count, if: :llm_message? # @!method self.llm_messages # Events that represent conversation turns sent to the LLM API. # @return [ActiveRecord::Relation] scope :llm_messages, -> { where(event_type: LLM_TYPES) } # @!method self.context_events # Events included in the LLM context window (messages + tool interactions). # @return [ActiveRecord::Relation] scope :context_events, -> { where(event_type: CONTEXT_TYPES) } # @!method self.pending # User messages queued during active agent processing, not yet sent to LLM. # @return [ActiveRecord::Relation] scope :pending, -> { where(status: PENDING_STATUS) } # @!method self.deliverable # Events eligible for LLM context (excludes pending messages). # NULL status means delivered/processed — the only excluded value is "pending". # @return [ActiveRecord::Relation] scope :deliverable, -> { where(status: nil) } # @!method self.excluding_spawn_events # Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. # Used when building parent context for sub-agents — spawn events cause role # confusion because the sub-agent sees sibling spawn results and mistakes # itself for the parent. # @return [ActiveRecord::Relation] scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } # Maps event_type to the Anthropic Messages API role. # @return [String] "user" or "assistant" def api_role ROLE_MAP.fetch(event_type) end # @return [Boolean] true if this event represents an LLM conversation turn def event_type.in?(LLM_TYPES) end # @return [Boolean] true if this event is part of the LLM context window def context_event? event_type.in?(CONTEXT_TYPES) end # @return [Boolean] true if this is a pending message not yet sent to the LLM def pending? status == PENDING_STATUS end # @return [Boolean] true if this is a conversation event (user/agent/system message) # or a think tool_call — the events Mneme treats as "conversation" for boundary tracking def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end # Heuristic token estimate: ~4 bytes per token for English prose. # Tool events are estimated from the full payload JSON since tool_input # and tool metadata contribute to token count. Messages use content only. # # @return [Integer] estimated token count (at least 1) def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end private def schedule_token_count CountEventTokensJob.perform_later(id) end end |
#payload ⇒ Hash
Returns event-specific data (content, tool_name, tool_input, etc.).
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 |
# File 'app/models/event.rb', line 20 class Event < ApplicationRecord include Event::Broadcasting TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze LLM_TYPES = %w[user_message agent_message].freeze CONTEXT_TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze CONVERSATION_TYPES = %w[user_message agent_message system_message].freeze THINK_TOOL = "think" SPAWN_TOOLS = %w[spawn_subagent spawn_specialist].freeze PENDING_STATUS = "pending" # Event types that require a tool_use_id to pair call with response. TOOL_TYPES = %w[tool_call tool_response].freeze ROLE_MAP = {"user_message" => "user", "agent_message" => "assistant"}.freeze # Heuristic: average bytes per token for English prose. BYTES_PER_TOKEN = 4 belongs_to :session has_many :pinned_events, dependent: :destroy validates :event_type, presence: true, inclusion: {in: TYPES} validates :payload, presence: true validates :timestamp, presence: true # Anthropic requires every tool_use to have a matching tool_result with the same ID validates :tool_use_id, presence: true, if: -> { event_type.in?(TOOL_TYPES) } after_create :schedule_token_count, if: :llm_message? # @!method self.llm_messages # Events that represent conversation turns sent to the LLM API. # @return [ActiveRecord::Relation] scope :llm_messages, -> { where(event_type: LLM_TYPES) } # @!method self.context_events # Events included in the LLM context window (messages + tool interactions). # @return [ActiveRecord::Relation] scope :context_events, -> { where(event_type: CONTEXT_TYPES) } # @!method self.pending # User messages queued during active agent processing, not yet sent to LLM. # @return [ActiveRecord::Relation] scope :pending, -> { where(status: PENDING_STATUS) } # @!method self.deliverable # Events eligible for LLM context (excludes pending messages). # NULL status means delivered/processed — the only excluded value is "pending". # @return [ActiveRecord::Relation] scope :deliverable, -> { where(status: nil) } # @!method self.excluding_spawn_events # Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. # Used when building parent context for sub-agents — spawn events cause role # confusion because the sub-agent sees sibling spawn results and mistakes # itself for the parent. # @return [ActiveRecord::Relation] scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } # Maps event_type to the Anthropic Messages API role. # @return [String] "user" or "assistant" def api_role ROLE_MAP.fetch(event_type) end # @return [Boolean] true if this event represents an LLM conversation turn def event_type.in?(LLM_TYPES) end # @return [Boolean] true if this event is part of the LLM context window def context_event? event_type.in?(CONTEXT_TYPES) end # @return [Boolean] true if this is a pending message not yet sent to the LLM def pending? status == PENDING_STATUS end # @return [Boolean] true if this is a conversation event (user/agent/system message) # or a think tool_call — the events Mneme treats as "conversation" for boundary tracking def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end # Heuristic token estimate: ~4 bytes per token for English prose. # Tool events are estimated from the full payload JSON since tool_input # and tool metadata contribute to token count. Messages use content only. # # @return [Integer] estimated token count (at least 1) def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end private def schedule_token_count CountEventTokensJob.perform_later(id) end end |
#timestamp ⇒ Integer
Returns nanoseconds since epoch (Process::CLOCK_REALTIME).
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 |
# File 'app/models/event.rb', line 20 class Event < ApplicationRecord include Event::Broadcasting TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze LLM_TYPES = %w[user_message agent_message].freeze CONTEXT_TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze CONVERSATION_TYPES = %w[user_message agent_message system_message].freeze THINK_TOOL = "think" SPAWN_TOOLS = %w[spawn_subagent spawn_specialist].freeze PENDING_STATUS = "pending" # Event types that require a tool_use_id to pair call with response. TOOL_TYPES = %w[tool_call tool_response].freeze ROLE_MAP = {"user_message" => "user", "agent_message" => "assistant"}.freeze # Heuristic: average bytes per token for English prose. BYTES_PER_TOKEN = 4 belongs_to :session has_many :pinned_events, dependent: :destroy validates :event_type, presence: true, inclusion: {in: TYPES} validates :payload, presence: true validates :timestamp, presence: true # Anthropic requires every tool_use to have a matching tool_result with the same ID validates :tool_use_id, presence: true, if: -> { event_type.in?(TOOL_TYPES) } after_create :schedule_token_count, if: :llm_message? # @!method self.llm_messages # Events that represent conversation turns sent to the LLM API. # @return [ActiveRecord::Relation] scope :llm_messages, -> { where(event_type: LLM_TYPES) } # @!method self.context_events # Events included in the LLM context window (messages + tool interactions). # @return [ActiveRecord::Relation] scope :context_events, -> { where(event_type: CONTEXT_TYPES) } # @!method self.pending # User messages queued during active agent processing, not yet sent to LLM. # @return [ActiveRecord::Relation] scope :pending, -> { where(status: PENDING_STATUS) } # @!method self.deliverable # Events eligible for LLM context (excludes pending messages). # NULL status means delivered/processed — the only excluded value is "pending". # @return [ActiveRecord::Relation] scope :deliverable, -> { where(status: nil) } # @!method self.excluding_spawn_events # Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. # Used when building parent context for sub-agents — spawn events cause role # confusion because the sub-agent sees sibling spawn results and mistakes # itself for the parent. # @return [ActiveRecord::Relation] scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } # Maps event_type to the Anthropic Messages API role. # @return [String] "user" or "assistant" def api_role ROLE_MAP.fetch(event_type) end # @return [Boolean] true if this event represents an LLM conversation turn def event_type.in?(LLM_TYPES) end # @return [Boolean] true if this event is part of the LLM context window def context_event? event_type.in?(CONTEXT_TYPES) end # @return [Boolean] true if this is a pending message not yet sent to the LLM def pending? status == PENDING_STATUS end # @return [Boolean] true if this is a conversation event (user/agent/system message) # or a think tool_call — the events Mneme treats as "conversation" for boundary tracking def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end # Heuristic token estimate: ~4 bytes per token for English prose. # Tool events are estimated from the full payload JSON since tool_input # and tool metadata contribute to token count. Messages use content only. # # @return [Integer] estimated token count (at least 1) def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end private def schedule_token_count CountEventTokensJob.perform_later(id) end end |
#token_count ⇒ Integer
Returns cached token count for this event’s payload (0 until counted).
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 |
# File 'app/models/event.rb', line 20 class Event < ApplicationRecord include Event::Broadcasting TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze LLM_TYPES = %w[user_message agent_message].freeze CONTEXT_TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze CONVERSATION_TYPES = %w[user_message agent_message system_message].freeze THINK_TOOL = "think" SPAWN_TOOLS = %w[spawn_subagent spawn_specialist].freeze PENDING_STATUS = "pending" # Event types that require a tool_use_id to pair call with response. TOOL_TYPES = %w[tool_call tool_response].freeze ROLE_MAP = {"user_message" => "user", "agent_message" => "assistant"}.freeze # Heuristic: average bytes per token for English prose. BYTES_PER_TOKEN = 4 belongs_to :session has_many :pinned_events, dependent: :destroy validates :event_type, presence: true, inclusion: {in: TYPES} validates :payload, presence: true validates :timestamp, presence: true # Anthropic requires every tool_use to have a matching tool_result with the same ID validates :tool_use_id, presence: true, if: -> { event_type.in?(TOOL_TYPES) } after_create :schedule_token_count, if: :llm_message? # @!method self.llm_messages # Events that represent conversation turns sent to the LLM API. # @return [ActiveRecord::Relation] scope :llm_messages, -> { where(event_type: LLM_TYPES) } # @!method self.context_events # Events included in the LLM context window (messages + tool interactions). # @return [ActiveRecord::Relation] scope :context_events, -> { where(event_type: CONTEXT_TYPES) } # @!method self.pending # User messages queued during active agent processing, not yet sent to LLM. # @return [ActiveRecord::Relation] scope :pending, -> { where(status: PENDING_STATUS) } # @!method self.deliverable # Events eligible for LLM context (excludes pending messages). # NULL status means delivered/processed — the only excluded value is "pending". # @return [ActiveRecord::Relation] scope :deliverable, -> { where(status: nil) } # @!method self.excluding_spawn_events # Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. # Used when building parent context for sub-agents — spawn events cause role # confusion because the sub-agent sees sibling spawn results and mistakes # itself for the parent. # @return [ActiveRecord::Relation] scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } # Maps event_type to the Anthropic Messages API role. # @return [String] "user" or "assistant" def api_role ROLE_MAP.fetch(event_type) end # @return [Boolean] true if this event represents an LLM conversation turn def event_type.in?(LLM_TYPES) end # @return [Boolean] true if this event is part of the LLM context window def context_event? event_type.in?(CONTEXT_TYPES) end # @return [Boolean] true if this is a pending message not yet sent to the LLM def pending? status == PENDING_STATUS end # @return [Boolean] true if this is a conversation event (user/agent/system message) # or a think tool_call — the events Mneme treats as "conversation" for boundary tracking def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end # Heuristic token estimate: ~4 bytes per token for English prose. # Tool events are estimated from the full payload JSON since tool_input # and tool metadata contribute to token count. Messages use content only. # # @return [Integer] estimated token count (at least 1) def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end private def schedule_token_count CountEventTokensJob.perform_later(id) end end |
#tool_use_id ⇒ String
Returns ID correlating tool_call and tool_response events (Anthropic-assigned, or a SecureRandom.uuid fallback when the API returns nil; required for tool_call and tool_response events).
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 |
# File 'app/models/event.rb', line 20 class Event < ApplicationRecord include Event::Broadcasting TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze LLM_TYPES = %w[user_message agent_message].freeze CONTEXT_TYPES = %w[system_message user_message agent_message tool_call tool_response].freeze CONVERSATION_TYPES = %w[user_message agent_message system_message].freeze THINK_TOOL = "think" SPAWN_TOOLS = %w[spawn_subagent spawn_specialist].freeze PENDING_STATUS = "pending" # Event types that require a tool_use_id to pair call with response. TOOL_TYPES = %w[tool_call tool_response].freeze ROLE_MAP = {"user_message" => "user", "agent_message" => "assistant"}.freeze # Heuristic: average bytes per token for English prose. BYTES_PER_TOKEN = 4 belongs_to :session has_many :pinned_events, dependent: :destroy validates :event_type, presence: true, inclusion: {in: TYPES} validates :payload, presence: true validates :timestamp, presence: true # Anthropic requires every tool_use to have a matching tool_result with the same ID validates :tool_use_id, presence: true, if: -> { event_type.in?(TOOL_TYPES) } after_create :schedule_token_count, if: :llm_message? # @!method self.llm_messages # Events that represent conversation turns sent to the LLM API. # @return [ActiveRecord::Relation] scope :llm_messages, -> { where(event_type: LLM_TYPES) } # @!method self.context_events # Events included in the LLM context window (messages + tool interactions). # @return [ActiveRecord::Relation] scope :context_events, -> { where(event_type: CONTEXT_TYPES) } # @!method self.pending # User messages queued during active agent processing, not yet sent to LLM. # @return [ActiveRecord::Relation] scope :pending, -> { where(status: PENDING_STATUS) } # @!method self.deliverable # Events eligible for LLM context (excludes pending messages). # NULL status means delivered/processed — the only excluded value is "pending". # @return [ActiveRecord::Relation] scope :deliverable, -> { where(status: nil) } # @!method self.excluding_spawn_events # Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. # Used when building parent context for sub-agents — spawn events cause role # confusion because the sub-agent sees sibling spawn results and mistakes # itself for the parent. # @return [ActiveRecord::Relation] scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } # Maps event_type to the Anthropic Messages API role. # @return [String] "user" or "assistant" def api_role ROLE_MAP.fetch(event_type) end # @return [Boolean] true if this event represents an LLM conversation turn def event_type.in?(LLM_TYPES) end # @return [Boolean] true if this event is part of the LLM context window def context_event? event_type.in?(CONTEXT_TYPES) end # @return [Boolean] true if this is a pending message not yet sent to the LLM def pending? status == PENDING_STATUS end # @return [Boolean] true if this is a conversation event (user/agent/system message) # or a think tool_call — the events Mneme treats as "conversation" for boundary tracking def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end # Heuristic token estimate: ~4 bytes per token for English prose. # Tool events are estimated from the full payload JSON since tool_input # and tool metadata contribute to token count. Messages use content only. # # @return [Integer] estimated token count (at least 1) def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end private def schedule_token_count CountEventTokensJob.perform_later(id) end end |
Class Method Details
.context_events ⇒ ActiveRecord::Relation
Events included in the LLM context window (messages + tool interactions).
58 |
# File 'app/models/event.rb', line 58 scope :context_events, -> { where(event_type: CONTEXT_TYPES) } |
.deliverable ⇒ ActiveRecord::Relation
Events eligible for LLM context (excludes pending messages). NULL status means delivered/processed — the only excluded value is “pending”.
69 |
# File 'app/models/event.rb', line 69 scope :deliverable, -> { where(status: nil) } |
.excluding_spawn_events ⇒ ActiveRecord::Relation
Excludes spawn_subagent/spawn_specialist tool_call and tool_response events. Used when building parent context for sub-agents — spawn events cause role confusion because the sub-agent sees sibling spawn results and mistakes itself for the parent.
77 78 79 80 |
# File 'app/models/event.rb', line 77 scope :excluding_spawn_events, -> { where.not("event_type IN (?) AND json_extract(payload, '$.tool_name') IN (?)", TOOL_TYPES, SPAWN_TOOLS) } |
.llm_messages ⇒ ActiveRecord::Relation
Events that represent conversation turns sent to the LLM API.
53 |
# File 'app/models/event.rb', line 53 scope :llm_messages, -> { where(event_type: LLM_TYPES) } |
.pending ⇒ ActiveRecord::Relation
User messages queued during active agent processing, not yet sent to LLM.
63 |
# File 'app/models/event.rb', line 63 scope :pending, -> { where(status: PENDING_STATUS) } |
Instance Method Details
#api_role ⇒ String
Maps event_type to the Anthropic Messages API role.
84 85 86 |
# File 'app/models/event.rb', line 84 def api_role ROLE_MAP.fetch(event_type) end |
#context_event? ⇒ Boolean
Returns true if this event is part of the LLM context window.
94 95 96 |
# File 'app/models/event.rb', line 94 def context_event? event_type.in?(CONTEXT_TYPES) end |
#conversation_or_think? ⇒ Boolean
Returns true if this is a conversation event (user/agent/system message) or a think tool_call — the events Mneme treats as “conversation” for boundary tracking.
105 106 107 108 |
# File 'app/models/event.rb', line 105 def conversation_or_think? event_type.in?(CONVERSATION_TYPES) || (event_type == "tool_call" && payload["tool_name"] == THINK_TOOL) end |
#estimate_tokens ⇒ Integer
Heuristic token estimate: ~4 bytes per token for English prose. Tool events are estimated from the full payload JSON since tool_input and tool metadata contribute to token count. Messages use content only.
115 116 117 118 119 120 121 122 |
# File 'app/models/event.rb', line 115 def estimate_tokens text = if event_type.in?(TOOL_TYPES) payload.to_json else payload["content"].to_s end [(text.bytesize / BYTES_PER_TOKEN.to_f).ceil, 1].max end |
#llm_message? ⇒ Boolean
Returns true if this event represents an LLM conversation turn.
89 90 91 |
# File 'app/models/event.rb', line 89 def event_type.in?(LLM_TYPES) end |
#pending? ⇒ Boolean
Returns true if this is a pending message not yet sent to the LLM.
99 100 101 |
# File 'app/models/event.rb', line 99 def pending? status == PENDING_STATUS end |