activematrix 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/jobs/active_matrix/application_job.rb +11 -0
- data/app/models/active_matrix/agent/jobs/memory_reaper.rb +87 -0
- data/app/models/active_matrix/agent.rb +131 -0
- data/app/models/active_matrix/agent_store.rb +51 -0
- data/app/models/active_matrix/application_record.rb +7 -0
- data/app/models/active_matrix/chat_session.rb +76 -0
- data/app/models/active_matrix/knowledge_base.rb +74 -0
- data/lib/active_matrix/engine.rb +14 -0
- data/lib/active_matrix/protocols/cs/message_relationships.rb +318 -0
- data/lib/active_matrix/railtie.rb +8 -0
- data/lib/active_matrix/version.rb +1 -1
- data/lib/active_matrix.rb +11 -9
- data/lib/generators/active_matrix/install/install_generator.rb +0 -7
- metadata +77 -13
- data/lib/generators/active_matrix/install/templates/agent_memory.rb +0 -47
- data/lib/generators/active_matrix/install/templates/conversation_context.rb +0 -72
- data/lib/generators/active_matrix/install/templates/global_memory.rb +0 -70
- data/lib/generators/active_matrix/install/templates/matrix_agent.rb +0 -127
@@ -0,0 +1,318 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveMatrix
|
4
|
+
module Protocols
|
5
|
+
module CS
|
6
|
+
# Handles message relationships (replies, edits, reactions, threads)
|
7
|
+
# @see https://spec.matrix.org/latest/client-server-api/#relationships
|
8
|
+
module MessageRelationships
|
9
|
+
# Send a message as a reply to another event
|
10
|
+
#
|
11
|
+
# @param room_id [String] The room ID
|
12
|
+
# @param event_id [String] The event ID to reply to
|
13
|
+
# @param content [Hash,String] The message content
|
14
|
+
# @param msgtype [String] The message type (defaults to 'm.text')
|
15
|
+
# @param params [Hash] Additional parameters for send_message_event
|
16
|
+
# @return [Response] The response from the server
|
17
|
+
#
|
18
|
+
# @example Reply to a message
|
19
|
+
# api.reply_to(room_id, event_id, "I agree!")
|
20
|
+
#
|
21
|
+
# @example Reply with custom msgtype
|
22
|
+
# api.reply_to(room_id, event_id, { url: "mxc://..." }, msgtype: 'm.image')
|
23
|
+
def reply_to(room_id, event_id, content, msgtype: 'm.text', **params)
|
24
|
+
content = { body: content } if content.is_a?(String)
|
25
|
+
content[:msgtype] ||= msgtype
|
26
|
+
|
27
|
+
# Add the reply relationship
|
28
|
+
content[:'m.relates_to'] = {
|
29
|
+
'm.in_reply_to' => {
|
30
|
+
event_id: event_id
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
send_message_event(room_id, 'm.room.message', content, **params)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Send a threaded message
|
38
|
+
#
|
39
|
+
# @param room_id [String] The room ID
|
40
|
+
# @param thread_root_id [String] The root event ID of the thread
|
41
|
+
# @param content [Hash,String] The message content
|
42
|
+
# @param msgtype [String] The message type (defaults to 'm.text')
|
43
|
+
# @param latest_event_id [String,nil] The latest event in the thread (for fallback)
|
44
|
+
# @param include_fallback [Boolean] Include reply fallback for older clients
|
45
|
+
# @param params [Hash] Additional parameters for send_message_event
|
46
|
+
# @return [Response] The response from the server
|
47
|
+
#
|
48
|
+
# @example Send a threaded message
|
49
|
+
# api.send_threaded_message(room_id, root_event_id, "This is a thread reply")
|
50
|
+
#
|
51
|
+
# @example Send a threaded message with fallback
|
52
|
+
# api.send_threaded_message(room_id, root_id, "Reply", latest_event_id: last_id, include_fallback: true)
|
53
|
+
def send_threaded_message(room_id, thread_root_id, content, msgtype: 'm.text',
|
54
|
+
latest_event_id: nil, include_fallback: false, **params)
|
55
|
+
content = { body: content } if content.is_a?(String)
|
56
|
+
content[:msgtype] ||= msgtype
|
57
|
+
|
58
|
+
# Build the thread relationship
|
59
|
+
relates_to = {
|
60
|
+
rel_type: 'm.thread',
|
61
|
+
event_id: thread_root_id
|
62
|
+
}
|
63
|
+
|
64
|
+
# Add fallback for older clients if requested
|
65
|
+
if include_fallback && latest_event_id
|
66
|
+
relates_to[:'m.in_reply_to'] = {
|
67
|
+
event_id: latest_event_id
|
68
|
+
}
|
69
|
+
relates_to[:is_falling_back] = true
|
70
|
+
end
|
71
|
+
|
72
|
+
content[:'m.relates_to'] = relates_to
|
73
|
+
send_message_event(room_id, 'm.room.message', content, **params)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Edit an existing message
|
77
|
+
#
|
78
|
+
# @param room_id [String] The room ID
|
79
|
+
# @param event_id [String] The event ID to edit
|
80
|
+
# @param new_content [Hash,String] The new message content
|
81
|
+
# @param msgtype [String] The message type (defaults to 'm.text')
|
82
|
+
# @param params [Hash] Additional parameters for send_message_event
|
83
|
+
# @return [Response] The response from the server
|
84
|
+
#
|
85
|
+
# @example Edit a text message
|
86
|
+
# api.edit_message(room_id, event_id, "Updated message content")
|
87
|
+
#
|
88
|
+
# @example Edit with formatted content
|
89
|
+
# api.edit_message(room_id, event_id, {
|
90
|
+
# body: "Updated *formatted* message",
|
91
|
+
# format: "org.matrix.custom.html",
|
92
|
+
# formatted_body: "Updated <em>formatted</em> message"
|
93
|
+
# })
|
94
|
+
def edit_message(room_id, event_id, new_content, msgtype: 'm.text', **params)
|
95
|
+
new_content = { body: new_content } if new_content.is_a?(String)
|
96
|
+
new_content[:msgtype] ||= msgtype
|
97
|
+
|
98
|
+
# Build the edit event content
|
99
|
+
content = {
|
100
|
+
body: "* #{new_content[:body]}", # Fallback with asterisk prefix
|
101
|
+
msgtype: msgtype,
|
102
|
+
'm.new_content' => new_content,
|
103
|
+
'm.relates_to' => {
|
104
|
+
rel_type: 'm.replace',
|
105
|
+
event_id: event_id
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
# Copy format fields to top level if present
|
110
|
+
if new_content[:format]
|
111
|
+
content[:format] = new_content[:format]
|
112
|
+
content[:formatted_body] = "* #{new_content[:formatted_body]}"
|
113
|
+
end
|
114
|
+
|
115
|
+
send_message_event(room_id, 'm.room.message', content, **params)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Send a reaction to an event
|
119
|
+
#
|
120
|
+
# @param room_id [String] The room ID
|
121
|
+
# @param event_id [String] The event ID to react to
|
122
|
+
# @param key [String] The reaction key (usually an emoji)
|
123
|
+
# @param params [Hash] Additional parameters for send_message_event
|
124
|
+
# @return [Response] The response from the server
|
125
|
+
#
|
126
|
+
# @example React with an emoji
|
127
|
+
# api.send_reaction(room_id, event_id, "👍")
|
128
|
+
#
|
129
|
+
# @example React with custom text
|
130
|
+
# api.send_reaction(room_id, event_id, "agree")
|
131
|
+
def send_reaction(room_id, event_id, key, **params)
|
132
|
+
content = {
|
133
|
+
'm.relates_to' => {
|
134
|
+
rel_type: 'm.annotation',
|
135
|
+
event_id: event_id,
|
136
|
+
key: key
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
send_message_event(room_id, 'm.reaction', content, **params)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Remove a reaction from an event
|
144
|
+
#
|
145
|
+
# @param room_id [String] The room ID
|
146
|
+
# @param reaction_event_id [String] The reaction event ID to redact
|
147
|
+
# @param reason [String,nil] Optional reason for removing the reaction
|
148
|
+
# @param params [Hash] Additional parameters for redact_event
|
149
|
+
# @return [Response] The response from the server
|
150
|
+
#
|
151
|
+
# @example Remove a reaction
|
152
|
+
# api.remove_reaction(room_id, reaction_event_id)
|
153
|
+
def remove_reaction(room_id, reaction_event_id, reason: nil, **params)
|
154
|
+
redact_event(room_id, reaction_event_id, reason: reason, **params)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Send a reference to another event
|
158
|
+
#
|
159
|
+
# @param room_id [String] The room ID
|
160
|
+
# @param event_id [String] The event ID to reference
|
161
|
+
# @param content [Hash,String] The message content
|
162
|
+
# @param msgtype [String] The message type (defaults to 'm.text')
|
163
|
+
# @param params [Hash] Additional parameters for send_message_event
|
164
|
+
# @return [Response] The response from the server
|
165
|
+
#
|
166
|
+
# @example Send a message referencing another event
|
167
|
+
# api.send_reference(room_id, event_id, "See the above message")
|
168
|
+
def send_reference(room_id, event_id, content, msgtype: 'm.text', **params)
|
169
|
+
content = { body: content } if content.is_a?(String)
|
170
|
+
content[:msgtype] ||= msgtype
|
171
|
+
|
172
|
+
content[:'m.relates_to'] = {
|
173
|
+
rel_type: 'm.reference',
|
174
|
+
event_id: event_id
|
175
|
+
}
|
176
|
+
|
177
|
+
send_message_event(room_id, 'm.room.message', content, **params)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Get related events for a given event
|
181
|
+
#
|
182
|
+
# @param room_id [String] The room ID
|
183
|
+
# @param event_id [String] The event ID to get relations for
|
184
|
+
# @param rel_type [String,nil] Filter by specific relationship type
|
185
|
+
# @param event_type [String,nil] Filter by specific event type
|
186
|
+
# @param from [String,nil] Pagination token
|
187
|
+
# @param to [String,nil] Pagination token
|
188
|
+
# @param limit [Integer] Maximum number of events to return
|
189
|
+
# @param direction [String] Direction of pagination ('b' for backwards, 'f' for forwards)
|
190
|
+
# @param params [Hash] Additional query parameters
|
191
|
+
# @return [Response] The related events
|
192
|
+
#
|
193
|
+
# @example Get all relations
|
194
|
+
# api.get_relations(room_id, event_id)
|
195
|
+
#
|
196
|
+
# @example Get only reactions
|
197
|
+
# api.get_relations(room_id, event_id, rel_type: 'm.annotation', event_type: 'm.reaction')
|
198
|
+
#
|
199
|
+
# @example Get thread replies
|
200
|
+
# api.get_relations(room_id, event_id, rel_type: 'm.thread')
|
201
|
+
def get_relations(room_id, event_id, rel_type: nil, event_type: nil,
|
202
|
+
from: nil, to: nil, limit: nil, direction: 'b', **params)
|
203
|
+
query = {
|
204
|
+
from: from,
|
205
|
+
to: to,
|
206
|
+
limit: limit,
|
207
|
+
dir: direction
|
208
|
+
}.merge(params).compact
|
209
|
+
|
210
|
+
# Build the appropriate endpoint based on filters
|
211
|
+
endpoint = "/rooms/#{room_id}/relations/#{event_id}"
|
212
|
+
endpoint += "/#{rel_type}" if rel_type
|
213
|
+
endpoint += "/#{event_type}" if rel_type && event_type
|
214
|
+
|
215
|
+
request(:get, client_api_latest, endpoint, query: query)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Get aggregated relations for multiple events
|
219
|
+
#
|
220
|
+
# @param room_id [String] The room ID
|
221
|
+
# @param event_ids [Array<String>] The event IDs to get relations for
|
222
|
+
# @param rel_type [String,nil] Filter by specific relationship type
|
223
|
+
# @param event_type [String,nil] Filter by specific event type
|
224
|
+
# @param params [Hash] Additional body parameters
|
225
|
+
# @return [Response] The aggregated relations
|
226
|
+
#
|
227
|
+
# @example Get aggregated reactions for multiple events
|
228
|
+
# api.get_aggregated_relations(room_id, event_ids, rel_type: 'm.annotation')
|
229
|
+
def get_aggregated_relations(room_id, event_ids, rel_type: nil, event_type: nil, **params)
|
230
|
+
body = {
|
231
|
+
event_ids: event_ids,
|
232
|
+
rel_type: rel_type,
|
233
|
+
event_type: event_type
|
234
|
+
}.merge(params).compact
|
235
|
+
|
236
|
+
request(:post, client_api_latest, "/rooms/#{room_id}/aggregations", body: body)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Get the edit history of an event
|
240
|
+
#
|
241
|
+
# @param room_id [String] The room ID
|
242
|
+
# @param event_id [String] The event ID to get edit history for
|
243
|
+
# @param params [Hash] Additional query parameters
|
244
|
+
# @return [Response] The edit history
|
245
|
+
#
|
246
|
+
# @example Get edit history
|
247
|
+
# api.get_edit_history(room_id, event_id)
|
248
|
+
def get_edit_history(room_id, event_id, **params)
|
249
|
+
get_relations(room_id, event_id, rel_type: 'm.replace', event_type: 'm.room.message', **params)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Get all reactions for an event
|
253
|
+
#
|
254
|
+
# @param room_id [String] The room ID
|
255
|
+
# @param event_id [String] The event ID to get reactions for
|
256
|
+
# @param params [Hash] Additional query parameters
|
257
|
+
# @return [Response] The reactions
|
258
|
+
#
|
259
|
+
# @example Get all reactions
|
260
|
+
# api.get_reactions(room_id, event_id)
|
261
|
+
def get_reactions(room_id, event_id, **params)
|
262
|
+
get_relations(room_id, event_id, rel_type: 'm.annotation', event_type: 'm.reaction', **params)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Get thread messages for a root event
|
266
|
+
#
|
267
|
+
# @param room_id [String] The room ID
|
268
|
+
# @param thread_root_id [String] The thread root event ID
|
269
|
+
# @param params [Hash] Additional query parameters
|
270
|
+
# @return [Response] The thread messages
|
271
|
+
#
|
272
|
+
# @example Get thread messages
|
273
|
+
# api.get_thread_messages(room_id, thread_root_id)
|
274
|
+
def get_thread_messages(room_id, thread_root_id, **params)
|
275
|
+
get_relations(room_id, thread_root_id, rel_type: 'm.thread', **params)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Check if an event has been edited
|
279
|
+
#
|
280
|
+
# @param event [Hash] The event to check
|
281
|
+
# @return [Boolean] True if the event has been edited
|
282
|
+
def event_edited?(event)
|
283
|
+
event.dig(:unsigned, :'m.relations', :'m.replace').present?
|
284
|
+
end
|
285
|
+
|
286
|
+
# Get the latest edit content for an event
|
287
|
+
#
|
288
|
+
# @param event [Hash] The event to get latest content for
|
289
|
+
# @return [Hash,nil] The latest content or nil if not edited
|
290
|
+
def get_latest_edit_content(event)
|
291
|
+
edit_event = event.dig(:unsigned, :'m.relations', :'m.replace')
|
292
|
+
return nil unless edit_event
|
293
|
+
|
294
|
+
# Return the m.new_content if available, otherwise the content
|
295
|
+
edit_event.dig(:content, :'m.new_content') || edit_event[:content]
|
296
|
+
end
|
297
|
+
|
298
|
+
# Check if an event is part of a thread
|
299
|
+
#
|
300
|
+
# @param event [Hash] The event to check
|
301
|
+
# @return [Boolean] True if the event is part of a thread
|
302
|
+
def in_thread?(event)
|
303
|
+
rel_type = event.dig(:content, :'m.relates_to', :rel_type)
|
304
|
+
rel_type == 'm.thread'
|
305
|
+
end
|
306
|
+
|
307
|
+
# Get the thread root ID for an event
|
308
|
+
#
|
309
|
+
# @param event [Hash] The event to get thread root for
|
310
|
+
# @return [String,nil] The thread root event ID or nil if not in a thread
|
311
|
+
def get_thread_root_id(event)
|
312
|
+
return nil unless in_thread?(event)
|
313
|
+
event.dig(:content, :'m.relates_to', :event_id)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
@@ -4,9 +4,17 @@ require 'rails/railtie'
|
|
4
4
|
|
5
5
|
module ActiveMatrix
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
+
Rails.logger.debug 'ActiveMatrix::Railtie: Loading...'
|
8
|
+
|
7
9
|
initializer 'activematrix.configure_rails_initialization' do
|
10
|
+
Rails.logger.debug 'ActiveMatrix::Railtie: Initializer running'
|
8
11
|
# Configure Rails.logger as the default logger
|
9
12
|
ActiveMatrix.logger = Rails.logger
|
13
|
+
Rails.logger.debug 'ActiveMatrix::Railtie: Logger configured'
|
14
|
+
|
15
|
+
# Debug autoload paths
|
16
|
+
Rails.logger.debug { "ActiveMatrix::Railtie: Autoload paths = #{Rails.application.config.autoload_paths}" }
|
17
|
+
Rails.logger.debug { "ActiveMatrix::Railtie: Eager load paths = #{Rails.application.config.eager_load_paths}" }
|
10
18
|
end
|
11
19
|
end
|
12
20
|
end
|
data/lib/active_matrix.rb
CHANGED
@@ -5,12 +5,9 @@ require_relative 'active_matrix/version'
|
|
5
5
|
|
6
6
|
require 'json'
|
7
7
|
require 'zeitwerk'
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require 'active_support/core_ext/time/zones'
|
12
|
-
require 'active_support/core_ext/hash/keys'
|
13
|
-
require 'active_support/core_ext/object/blank'
|
8
|
+
require 'active_record'
|
9
|
+
require 'active_job'
|
10
|
+
require 'state_machines-activerecord'
|
14
11
|
|
15
12
|
module ActiveMatrix
|
16
13
|
# Configuration
|
@@ -83,6 +80,11 @@ module ActiveMatrix
|
|
83
80
|
Loader.ignore("#{__dir__}/generators")
|
84
81
|
Loader.ignore("#{__dir__}/activematrix.rb")
|
85
82
|
|
83
|
+
# Ignore files that don't follow Zeitwerk naming conventions
|
84
|
+
Loader.ignore("#{__dir__}/active_matrix/errors.rb")
|
85
|
+
Loader.ignore("#{__dir__}/active_matrix/events.rb")
|
86
|
+
Loader.ignore("#{__dir__}/active_matrix/uri_module.rb")
|
87
|
+
|
86
88
|
# Configure inflections for special cases
|
87
89
|
Loader.inflector.inflect(
|
88
90
|
'mxid' => 'MXID',
|
@@ -97,11 +99,11 @@ module ActiveMatrix
|
|
97
99
|
# Setup Zeitwerk autoloading
|
98
100
|
Loader.setup
|
99
101
|
|
100
|
-
# Load
|
102
|
+
# Load classes that don't follow Zeitwerk naming conventions
|
101
103
|
require_relative 'active_matrix/errors'
|
102
104
|
require_relative 'active_matrix/events'
|
103
105
|
require_relative 'active_matrix/uri_module'
|
104
106
|
|
105
|
-
# Load
|
106
|
-
require 'active_matrix/
|
107
|
+
# Load Engine for Rails integration
|
108
|
+
require 'active_matrix/engine'
|
107
109
|
end
|
@@ -23,13 +23,6 @@ module ActiveMatrix
|
|
23
23
|
template 'active_matrix.rb', 'config/initializers/active_matrix.rb'
|
24
24
|
end
|
25
25
|
|
26
|
-
def create_models
|
27
|
-
template 'matrix_agent.rb', 'app/models/matrix_agent.rb'
|
28
|
-
template 'agent_memory.rb', 'app/models/agent_memory.rb'
|
29
|
-
template 'conversation_context.rb', 'app/models/conversation_context.rb'
|
30
|
-
template 'global_memory.rb', 'app/models/global_memory.rb'
|
31
|
-
end
|
32
|
-
|
33
26
|
def display_post_install
|
34
27
|
readme 'README' if behavior == :invoke
|
35
28
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activematrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abdelkader Boudih
|
@@ -10,6 +10,20 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 1980-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: maxitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: mocha
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +136,20 @@ dependencies:
|
|
122
136
|
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sqlite3
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.0'
|
125
153
|
- !ruby/object:Gem::Dependency
|
126
154
|
name: syslog
|
127
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,6 +206,20 @@ dependencies:
|
|
178
206
|
- - "~>"
|
179
207
|
- !ruby/object:Gem::Version
|
180
208
|
version: '3.19'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: activejob
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '8.0'
|
216
|
+
type: :runtime
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '8.0'
|
181
223
|
- !ruby/object:Gem::Dependency
|
182
224
|
name: activerecord
|
183
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -238,16 +280,16 @@ dependencies:
|
|
238
280
|
name: state_machines-activerecord
|
239
281
|
requirement: !ruby/object:Gem::Requirement
|
240
282
|
requirements:
|
241
|
-
- - "
|
283
|
+
- - "<="
|
242
284
|
- !ruby/object:Gem::Version
|
243
|
-
version: 0.
|
285
|
+
version: 0.100.0
|
244
286
|
type: :runtime
|
245
287
|
prerelease: false
|
246
288
|
version_requirements: !ruby/object:Gem::Requirement
|
247
289
|
requirements:
|
248
|
-
- - "
|
290
|
+
- - "<="
|
249
291
|
- !ruby/object:Gem::Version
|
250
|
-
version: 0.
|
292
|
+
version: 0.100.0
|
251
293
|
- !ruby/object:Gem::Dependency
|
252
294
|
name: zeitwerk
|
253
295
|
requirement: !ruby/object:Gem::Requirement
|
@@ -262,8 +304,15 @@ dependencies:
|
|
262
304
|
- - "~>"
|
263
305
|
- !ruby/object:Gem::Version
|
264
306
|
version: '2.6'
|
265
|
-
description:
|
266
|
-
|
307
|
+
description: "ActiveMatrix is a comprehensive Rails-native Matrix SDK that enables
|
308
|
+
developers to build sophisticated multi-agent bot systems \nand real-time communication
|
309
|
+
features. This gem provides deep Rails integration with ActiveRecord models, state
|
310
|
+
machines for \nbot lifecycle management, multi-tiered memory systems, intelligent
|
311
|
+
event routing, connection pooling, and built-in \ninter-agent communication. Perfect
|
312
|
+
for building chatbots, automation systems, monitoring agents, and collaborative
|
313
|
+
AI \nsystems within Rails applications. Features include command handling, room
|
314
|
+
management, media support, end-to-end encryption \ncapabilities, and extensive protocol
|
315
|
+
support (CS, AS, IS, SS).\n"
|
267
316
|
email:
|
268
317
|
- terminale@gmail.com
|
269
318
|
- ace@haxalot.com
|
@@ -277,6 +326,13 @@ files:
|
|
277
326
|
- CHANGELOG.md
|
278
327
|
- LICENSE.txt
|
279
328
|
- README.md
|
329
|
+
- app/jobs/active_matrix/application_job.rb
|
330
|
+
- app/models/active_matrix/agent.rb
|
331
|
+
- app/models/active_matrix/agent/jobs/memory_reaper.rb
|
332
|
+
- app/models/active_matrix/agent_store.rb
|
333
|
+
- app/models/active_matrix/application_record.rb
|
334
|
+
- app/models/active_matrix/chat_session.rb
|
335
|
+
- app/models/active_matrix/knowledge_base.rb
|
280
336
|
- lib/active_matrix.rb
|
281
337
|
- lib/active_matrix/account_data_cache.rb
|
282
338
|
- lib/active_matrix/agent_manager.rb
|
@@ -288,6 +344,7 @@ files:
|
|
288
344
|
- lib/active_matrix/cacheable.rb
|
289
345
|
- lib/active_matrix/client.rb
|
290
346
|
- lib/active_matrix/client_pool.rb
|
347
|
+
- lib/active_matrix/engine.rb
|
291
348
|
- lib/active_matrix/errors.rb
|
292
349
|
- lib/active_matrix/event_router.rb
|
293
350
|
- lib/active_matrix/events.rb
|
@@ -301,6 +358,7 @@ files:
|
|
301
358
|
- lib/active_matrix/mxid.rb
|
302
359
|
- lib/active_matrix/protocols/as.rb
|
303
360
|
- lib/active_matrix/protocols/cs.rb
|
361
|
+
- lib/active_matrix/protocols/cs/message_relationships.rb
|
304
362
|
- lib/active_matrix/protocols/is.rb
|
305
363
|
- lib/active_matrix/protocols/msc.rb
|
306
364
|
- lib/active_matrix/protocols/ss.rb
|
@@ -319,19 +377,24 @@ files:
|
|
319
377
|
- lib/generators/active_matrix/install/install_generator.rb
|
320
378
|
- lib/generators/active_matrix/install/templates/README
|
321
379
|
- lib/generators/active_matrix/install/templates/active_matrix.rb
|
322
|
-
- lib/generators/active_matrix/install/templates/agent_memory.rb
|
323
|
-
- lib/generators/active_matrix/install/templates/conversation_context.rb
|
324
380
|
- lib/generators/active_matrix/install/templates/create_agent_memories.rb
|
325
381
|
- lib/generators/active_matrix/install/templates/create_conversation_contexts.rb
|
326
382
|
- lib/generators/active_matrix/install/templates/create_global_memories.rb
|
327
383
|
- lib/generators/active_matrix/install/templates/create_matrix_agents.rb
|
328
|
-
- lib/generators/active_matrix/install/templates/global_memory.rb
|
329
|
-
- lib/generators/active_matrix/install/templates/matrix_agent.rb
|
330
384
|
homepage: https://github.com/seuros/activematrix
|
331
385
|
licenses:
|
332
386
|
- MIT
|
333
387
|
metadata:
|
334
388
|
rubygems_mfa_required: 'true'
|
389
|
+
homepage_uri: https://github.com/seuros/activematrix
|
390
|
+
source_code_uri: https://github.com/seuros/activematrix
|
391
|
+
changelog_uri: https://github.com/seuros/activematrix/blob/master/CHANGELOG.md
|
392
|
+
documentation_uri: https://rubydoc.info/gems/activematrix
|
393
|
+
bug_tracker_uri: https://github.com/seuros/activematrix/issues
|
394
|
+
wiki_uri: https://github.com/seuros/activematrix/wiki
|
395
|
+
tags: matrix, matrix-protocol, matrix-sdk, matrix-api, matrix-client, rails, rails-engine,
|
396
|
+
activerecord, activejob, rails-integration, bot, chatbot, multi-agent, agent-system,
|
397
|
+
bot-framework, real-time, messaging, communication, chat, state-machine
|
335
398
|
rdoc_options: []
|
336
399
|
require_paths:
|
337
400
|
- lib
|
@@ -346,7 +409,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
346
409
|
- !ruby/object:Gem::Version
|
347
410
|
version: '0'
|
348
411
|
requirements: []
|
349
|
-
rubygems_version: 3.6.
|
412
|
+
rubygems_version: 3.6.7
|
350
413
|
specification_version: 4
|
351
|
-
summary: Rails
|
414
|
+
summary: Rails-native Matrix SDK for building multi-agent bot systems and real-time
|
415
|
+
communication
|
352
416
|
test_files: []
|
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class AgentMemory < ApplicationRecord
|
4
|
-
belongs_to :matrix_agent
|
5
|
-
|
6
|
-
validates :key, presence: true, uniqueness: { scope: :matrix_agent_id }
|
7
|
-
|
8
|
-
scope :active, -> { where('expires_at IS NULL OR expires_at > ?', Time.current) }
|
9
|
-
scope :expired, -> { where('expires_at <= ?', Time.current) }
|
10
|
-
|
11
|
-
# Automatically clean up expired memories
|
12
|
-
after_commit :schedule_cleanup, if: :expires_at?
|
13
|
-
|
14
|
-
def expired?
|
15
|
-
expires_at.present? && expires_at <= Time.current
|
16
|
-
end
|
17
|
-
|
18
|
-
def ttl=(seconds)
|
19
|
-
self.expires_at = seconds.present? ? Time.current + seconds : nil
|
20
|
-
end
|
21
|
-
|
22
|
-
def ttl
|
23
|
-
return nil unless expires_at.present?
|
24
|
-
|
25
|
-
remaining = expires_at - Time.current
|
26
|
-
[remaining, 0].max
|
27
|
-
end
|
28
|
-
|
29
|
-
# Cache integration
|
30
|
-
def cache_key
|
31
|
-
"agent_memory/#{matrix_agent_id}/#{key}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def write_to_cache
|
35
|
-
Rails.cache.write(cache_key, value, expires_in: ttl)
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.cleanup_expired!
|
39
|
-
expired.destroy_all
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def schedule_cleanup
|
45
|
-
AgentMemoryCleanupJob.set(wait_until: expires_at).perform_later if defined?(AgentMemoryCleanupJob)
|
46
|
-
end
|
47
|
-
end
|