activematrix 0.0.0 → 0.0.2

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +218 -51
  3. data/lib/active_matrix/agent_manager.rb +275 -0
  4. data/lib/active_matrix/agent_registry.rb +154 -0
  5. data/lib/{matrix_sdk → active_matrix}/api.rb +18 -22
  6. data/lib/{matrix_sdk → active_matrix}/bot/base.rb +42 -39
  7. data/lib/{matrix_sdk → active_matrix}/bot/main.rb +4 -5
  8. data/lib/active_matrix/bot/multi_instance_base.rb +189 -0
  9. data/lib/active_matrix/bot.rb +7 -0
  10. data/lib/{matrix_sdk → active_matrix}/client.rb +21 -34
  11. data/lib/active_matrix/client_pool.rb +194 -0
  12. data/lib/{matrix_sdk → active_matrix}/errors.rb +4 -4
  13. data/lib/active_matrix/event_router.rb +215 -0
  14. data/lib/active_matrix/logging.rb +56 -0
  15. data/lib/active_matrix/memory/agent_memory.rb +128 -0
  16. data/lib/active_matrix/memory/base.rb +101 -0
  17. data/lib/active_matrix/memory/conversation_memory.rb +161 -0
  18. data/lib/active_matrix/memory/global_memory.rb +153 -0
  19. data/lib/active_matrix/memory.rb +28 -0
  20. data/lib/{matrix_sdk → active_matrix}/mxid.rb +2 -2
  21. data/lib/{matrix_sdk → active_matrix}/protocols/as.rb +1 -1
  22. data/lib/{matrix_sdk → active_matrix}/protocols/cs.rb +6 -8
  23. data/lib/{matrix_sdk → active_matrix}/protocols/is.rb +1 -1
  24. data/lib/{matrix_sdk → active_matrix}/protocols/msc.rb +6 -8
  25. data/lib/{matrix_sdk → active_matrix}/protocols/ss.rb +2 -2
  26. data/lib/active_matrix/railtie.rb +18 -0
  27. data/lib/{matrix_sdk → active_matrix}/response.rb +2 -2
  28. data/lib/{matrix_sdk → active_matrix}/room.rb +148 -72
  29. data/lib/{matrix_sdk → active_matrix}/rooms/space.rb +3 -7
  30. data/lib/{matrix_sdk → active_matrix}/user.rb +23 -15
  31. data/lib/active_matrix/util/account_data_cache.rb +129 -0
  32. data/lib/active_matrix/util/cacheable.rb +73 -0
  33. data/lib/{matrix_sdk → active_matrix}/util/events.rb +8 -8
  34. data/lib/{matrix_sdk → active_matrix}/util/extensions.rb +6 -15
  35. data/lib/active_matrix/util/state_event_cache.rb +167 -0
  36. data/lib/{matrix_sdk → active_matrix}/util/uri.rb +4 -4
  37. data/lib/active_matrix/version.rb +5 -0
  38. data/lib/active_matrix.rb +81 -0
  39. data/lib/generators/active_matrix/bot/bot_generator.rb +38 -0
  40. data/lib/generators/active_matrix/bot/templates/bot.rb.erb +111 -0
  41. data/lib/generators/active_matrix/bot/templates/bot_spec.rb.erb +68 -0
  42. data/lib/generators/active_matrix/install/install_generator.rb +44 -0
  43. data/lib/generators/active_matrix/install/templates/README +30 -0
  44. data/lib/generators/active_matrix/install/templates/active_matrix.rb +33 -0
  45. data/lib/generators/active_matrix/install/templates/agent_memory.rb +47 -0
  46. data/lib/generators/active_matrix/install/templates/conversation_context.rb +72 -0
  47. data/lib/generators/active_matrix/install/templates/create_agent_memories.rb +17 -0
  48. data/lib/generators/active_matrix/install/templates/create_conversation_contexts.rb +21 -0
  49. data/lib/generators/active_matrix/install/templates/create_global_memories.rb +20 -0
  50. data/lib/generators/active_matrix/install/templates/create_matrix_agents.rb +26 -0
  51. data/lib/generators/active_matrix/install/templates/global_memory.rb +70 -0
  52. data/lib/generators/active_matrix/install/templates/matrix_agent.rb +127 -0
  53. metadata +168 -30
  54. data/lib/matrix_sdk/bot.rb +0 -4
  55. data/lib/matrix_sdk/util/account_data_cache.rb +0 -91
  56. data/lib/matrix_sdk/util/state_event_cache.rb +0 -92
  57. data/lib/matrix_sdk/util/tinycache.rb +0 -140
  58. data/lib/matrix_sdk/util/tinycache_adapter.rb +0 -87
  59. data/lib/matrix_sdk/version.rb +0 -5
  60. data/lib/matrix_sdk.rb +0 -75
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module ActiveMatrix
6
+ module Memory
7
+ # Global memory storage accessible to all agents
8
+ class GlobalMemory < Base
9
+ include Singleton
10
+
11
+ # Get a value from global memory
12
+ def get(key)
13
+ fetch_with_cache(key) do
14
+ return nil unless defined?(::GlobalMemory)
15
+
16
+ ::GlobalMemory.get(key)
17
+ end
18
+ end
19
+
20
+ # Set a value in global memory
21
+ def set(key, value, category: nil, expires_in: nil, public_read: true, public_write: false)
22
+ return false unless defined?(::GlobalMemory)
23
+
24
+ write_through(key, value, expires_in: expires_in) do
25
+ ::GlobalMemory.set(key, value,
26
+ category: category,
27
+ expires_in: expires_in,
28
+ public_read: public_read,
29
+ public_write: public_write)
30
+ end
31
+ end
32
+
33
+ # Check if a key exists
34
+ def exists?(key)
35
+ return false unless defined?(::GlobalMemory)
36
+
37
+ if @cache_enabled && Rails.cache.exist?(cache_key(key))
38
+ true
39
+ else
40
+ ::GlobalMemory.active.exists?(key: key)
41
+ end
42
+ end
43
+
44
+ # Delete a key
45
+ def delete(key)
46
+ return false unless defined?(::GlobalMemory)
47
+
48
+ delete_through(key) do
49
+ ::GlobalMemory.where(key: key).destroy_all.any?
50
+ end
51
+ end
52
+
53
+ # Get all keys in a category
54
+ def keys(category: nil)
55
+ return [] unless defined?(::GlobalMemory)
56
+
57
+ scope = ::GlobalMemory.active
58
+ scope = scope.by_category(category) if category
59
+ scope.pluck(:key)
60
+ end
61
+
62
+ # Get all values in a category
63
+ def by_category(category)
64
+ return {} unless defined?(::GlobalMemory)
65
+
66
+ ::GlobalMemory.active.by_category(category).pluck(:key, :value).to_h
67
+ end
68
+
69
+ # Check if readable by agent
70
+ def readable?(key, agent = nil)
71
+ return false unless defined?(::GlobalMemory)
72
+
73
+ memory = ::GlobalMemory.find_by(key: key)
74
+ memory&.readable_by?(agent)
75
+ end
76
+
77
+ # Check if writable by agent
78
+ def writable?(key, agent = nil)
79
+ return false unless defined?(::GlobalMemory)
80
+
81
+ memory = ::GlobalMemory.find_by(key: key)
82
+ memory&.writable_by?(agent)
83
+ end
84
+
85
+ # Get with permission check
86
+ def get_for_agent(key, agent)
87
+ return nil unless readable?(key, agent)
88
+
89
+ get(key)
90
+ end
91
+
92
+ # Set with permission check
93
+ def set_for_agent(key, value, agent, **)
94
+ # Allow creating new keys or updating writable ones
95
+ memory = ::GlobalMemory.find_by(key: key)
96
+ return false if memory && !memory.writable_by?(agent)
97
+
98
+ set(key, value, **)
99
+ end
100
+
101
+ # Remember something globally
102
+ def remember(key, **)
103
+ value = get(key)
104
+ return value if value.present?
105
+
106
+ value = yield
107
+ set(key, value, **) if value.present?
108
+ value
109
+ end
110
+
111
+ # Broadcast a value to all agents
112
+ def broadcast(key, value, expires_in: 5.minutes)
113
+ set(key, value, category: 'broadcast', expires_in: expires_in, public_read: true)
114
+
115
+ # Notify all agents if event router is available
116
+ if defined?(EventRouter)
117
+ EventRouter.instance.broadcast_event({
118
+ type: 'global_memory.broadcast',
119
+ key: key,
120
+ value: value
121
+ })
122
+ end
123
+
124
+ true
125
+ end
126
+
127
+ # Share data between specific agents
128
+ def share(key, value, agent_names, expires_in: nil)
129
+ set(key, {
130
+ value: value,
131
+ allowed_agents: agent_names
132
+ }, category: 'shared', expires_in: expires_in, public_read: false)
133
+ end
134
+
135
+ # Get shared data if allowed
136
+ def get_shared(key, agent)
137
+ data = get(key)
138
+ return nil unless data.is_a?(Hash) && data['allowed_agents']
139
+
140
+ allowed = data['allowed_agents']
141
+ return unless allowed.include?(agent.name) || allowed.include?('*')
142
+
143
+ data['value']
144
+ end
145
+
146
+ protected
147
+
148
+ def cache_key(key)
149
+ "global/#{key}"
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveMatrix
4
+ # Memory system for multi-agent architecture
5
+ module Memory
6
+ autoload :AgentMemory, 'active_matrix/memory/agent_memory'
7
+ autoload :ConversationMemory, 'active_matrix/memory/conversation_memory'
8
+ autoload :GlobalMemory, 'active_matrix/memory/global_memory'
9
+ autoload :Base, 'active_matrix/memory/base'
10
+
11
+ class << self
12
+ # Get memory interface for an agent
13
+ def for_agent(agent)
14
+ AgentMemory.new(agent)
15
+ end
16
+
17
+ # Get conversation memory for agent and user
18
+ def for_conversation(agent, user_id, room_id)
19
+ ConversationMemory.new(agent, user_id, room_id)
20
+ end
21
+
22
+ # Access global memory
23
+ def global
24
+ GlobalMemory.instance
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MatrixSdk
3
+ module ActiveMatrix
4
4
  class MXID
5
5
  attr_accessor :sigil, :localpart, :domain, :port
6
6
 
@@ -82,7 +82,7 @@ module MatrixSdk
82
82
  # Check if the ID is of a room
83
83
  # @return [Boolean] if the ID is of the room_id or room_alias types
84
84
  def room?
85
- type == :room_id || type == :room_alias
85
+ %i[room_id room_alias].include?(type)
86
86
  end
87
87
 
88
88
  # Check if the ID is of a event
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MatrixSdk::Protocols::AS
3
+ module ActiveMatrix::Protocols::AS
4
4
  def self.included(_klass)
5
5
  # XXX
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # rubocop:disable Metrics/ModuleLength
4
- module MatrixSdk::Protocols::CS
4
+ module ActiveMatrix::Protocols::CS
5
5
  # Gets the available client API versions
6
6
  # @return [Array]
7
7
  #
@@ -12,7 +12,7 @@ module MatrixSdk::Protocols::CS
12
12
  # # => 'latest'
13
13
  def client_api_versions
14
14
  (@client_api_versions ||= request(:get, :client, '/versions')).versions.tap do |vers|
15
- vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
15
+ vers.instance_eval <<-CODE, __FILE__, __LINE__ + 1
16
16
  if !respond_to? :latest
17
17
  def latest
18
18
  last
@@ -32,7 +32,7 @@ module MatrixSdk::Protocols::CS
32
32
  # # => true
33
33
  def client_api_unstable_features
34
34
  (@client_api_versions ||= request(:get, :client, '/versions')).unstable_features.tap do |vers|
35
- vers.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
35
+ vers.instance_eval <<-CODE, __FILE__, __LINE__ + 1
36
36
  def has?(feature)
37
37
  feature = feature.to_s.to_sym unless feature.is_a? Symbol
38
38
  fetch(feature, nil)
@@ -68,9 +68,7 @@ module MatrixSdk::Protocols::CS
68
68
  # @see https://matrix.org/docs/spec/client_server/latest.html#get-matrix-client-r0-sync
69
69
  # For more information on the parameters and what they mean
70
70
  def sync(timeout: 30.0, **params)
71
- query = params.select do |k, _v|
72
- %i[since filter full_state set_presence].include? k
73
- end
71
+ query = params.slice(:since, :filter, :full_state, :set_presence)
74
72
 
75
73
  query[:timeout] = (timeout * 1000).to_i if timeout
76
74
  query[:timeout] = params.delete(:timeout_ms).to_i if params.key? :timeout_ms
@@ -198,7 +196,7 @@ module MatrixSdk::Protocols::CS
198
196
 
199
197
  data = {
200
198
  type: login_type,
201
- initial_device_display_name: params.delete(:initial_device_display_name) { MatrixSdk::Api::USER_AGENT }
199
+ initial_device_display_name: params.delete(:initial_device_display_name) { ActiveMatrix::Api::USER_AGENT }
202
200
  }.merge params
203
201
  data[:device_id] = device_id if device_id
204
202
 
@@ -785,7 +783,7 @@ module MatrixSdk::Protocols::CS
785
783
  state_type = ERB::Util.url_encode state_type.to_s
786
784
  key = ERB::Util.url_encode key.to_s
787
785
 
788
- request(:get, client_api_latest, "/rooms/#{room_id}/state/#{state_type}#{key.empty? ? nil : "/#{key}"}", query: query)
786
+ request(:get, client_api_latest, "/rooms/#{room_id}/state/#{state_type}#{"/#{key}" unless key.empty?}", query: query)
789
787
  end
790
788
 
791
789
  # Retrieves all current state objects from a room
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MatrixSdk::Protocols::IS
3
+ module ActiveMatrix::Protocols::IS
4
4
  def identity_status
5
5
  request(:get, :identity_api_v1, '/')
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Preliminary support for unmerged MSCs (Matrix Spec Changes)
4
- module MatrixSdk::Protocols::MSC
4
+ module ActiveMatrix::Protocols::MSC
5
5
  def refresh_mscs
6
6
  @msc = {}
7
7
  end
@@ -9,12 +9,12 @@ module MatrixSdk::Protocols::MSC
9
9
  # Check if there's support for MSC2108 - Sync over Server Sent Events
10
10
  def msc2108?
11
11
  @msc ||= {}
12
- @msc[2108] ||= \
12
+ @msc[2108] ||=
13
13
  begin
14
14
  request(:get, :client_r0, '/sync/sse', skip_auth: true, headers: { accept: 'text/event-stream' })
15
- rescue MatrixSdk::MatrixNotAuthorizedError # Returns 401 if implemented
15
+ rescue ActiveMatrix::MatrixNotAuthorizedError # Returns 401 if implemented
16
16
  true
17
- rescue MatrixSdk::MatrixRequestError
17
+ rescue ActiveMatrix::MatrixRequestError
18
18
  false
19
19
  end
20
20
  rescue StandardError => e
@@ -41,9 +41,7 @@ module MatrixSdk::Protocols::MSC
41
41
  unless on_data.is_a?(Proc) && on_data.arity == 2
42
42
  raise 'Needs to be logged in' unless access_token # TODO: Better error
43
43
 
44
- query = params.select do |k, _v|
45
- %i[filter full_state set_presence].include? k
46
- end
44
+ query = params.slice(:filter, :full_state, :set_presence)
47
45
  query[:user_id] = params.delete(:user_id) if protocol?(:AS) && params.key?(:user_id)
48
46
 
49
47
  req = Net::HTTP::Get.new(homeserver.dup.tap do |u|
@@ -125,7 +123,7 @@ module MatrixSdk::Protocols::MSC
125
123
 
126
124
  if %w[sync sync_error].include? event
127
125
  data = JSON.parse(data, symbolize_names: true)
128
- yield((MatrixSdk::Response.new self, data), event: event, id: id)
126
+ yield((ActiveMatrix::Response.new self, data), event: event, id: id)
129
127
  elsif event
130
128
  logger.info "MSC2108 : #{stream_id} : Received unknown event '#{event}'; #{data}"
131
129
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MatrixSdk::Protocols::SS
3
+ module ActiveMatrix::Protocols::SS
4
4
  # Gets the server version
5
5
  def server_version
6
- MatrixSdk::Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
6
+ ActiveMatrix::Response.new(self, request(:get, :federation_v1, '/version').server).tap do |resp|
7
7
  resp.instance_eval <<-'CODE', __FILE__, __LINE__ + 1
8
8
  def to_s
9
9
  "#{name} #{version}"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/railtie'
4
+
5
+ module ActiveMatrix
6
+ class Railtie < Rails::Railtie
7
+ initializer 'activematrix.configure_rails_initialization' do
8
+ # Configure Rails.logger as the default logger
9
+ ActiveMatrix.logger = Rails.logger
10
+ end
11
+
12
+ initializer 'activematrix.configure_cache' do
13
+ # Rails cache adapter is automatically used when Rails is detected
14
+ require 'active_matrix/util/rails_cache_adapter'
15
+ ActiveMatrix::Util::Tinycache.adapter = ActiveMatrix::Util::RailsCacheAdapter
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module MatrixSdk
3
+ module ActiveMatrix
4
4
  # An usability wrapper for API responses as an extended [Hash]
5
5
  # All results can be read as both hash keys and as read-only methods on the key
6
6
  #
@@ -39,7 +39,7 @@ module MatrixSdk
39
39
  data.instance_variable_set(:@api, api)
40
40
 
41
41
  data.select { |_k, v| v.is_a? Hash }
42
- .each { |_v, v| Response.new api, v }
42
+ .each_value { |v| Response.new api, v }
43
43
 
44
44
  data
45
45
  end