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.
- checksums.yaml +4 -4
- data/README.md +218 -51
- data/lib/active_matrix/agent_manager.rb +275 -0
- data/lib/active_matrix/agent_registry.rb +154 -0
- data/lib/{matrix_sdk → active_matrix}/api.rb +18 -22
- data/lib/{matrix_sdk → active_matrix}/bot/base.rb +42 -39
- data/lib/{matrix_sdk → active_matrix}/bot/main.rb +4 -5
- data/lib/active_matrix/bot/multi_instance_base.rb +189 -0
- data/lib/active_matrix/bot.rb +7 -0
- data/lib/{matrix_sdk → active_matrix}/client.rb +21 -34
- data/lib/active_matrix/client_pool.rb +194 -0
- data/lib/{matrix_sdk → active_matrix}/errors.rb +4 -4
- data/lib/active_matrix/event_router.rb +215 -0
- data/lib/active_matrix/logging.rb +56 -0
- data/lib/active_matrix/memory/agent_memory.rb +128 -0
- data/lib/active_matrix/memory/base.rb +101 -0
- data/lib/active_matrix/memory/conversation_memory.rb +161 -0
- data/lib/active_matrix/memory/global_memory.rb +153 -0
- data/lib/active_matrix/memory.rb +28 -0
- data/lib/{matrix_sdk → active_matrix}/mxid.rb +2 -2
- data/lib/{matrix_sdk → active_matrix}/protocols/as.rb +1 -1
- data/lib/{matrix_sdk → active_matrix}/protocols/cs.rb +6 -8
- data/lib/{matrix_sdk → active_matrix}/protocols/is.rb +1 -1
- data/lib/{matrix_sdk → active_matrix}/protocols/msc.rb +6 -8
- data/lib/{matrix_sdk → active_matrix}/protocols/ss.rb +2 -2
- data/lib/active_matrix/railtie.rb +18 -0
- data/lib/{matrix_sdk → active_matrix}/response.rb +2 -2
- data/lib/{matrix_sdk → active_matrix}/room.rb +148 -72
- data/lib/{matrix_sdk → active_matrix}/rooms/space.rb +3 -7
- data/lib/{matrix_sdk → active_matrix}/user.rb +23 -15
- data/lib/active_matrix/util/account_data_cache.rb +129 -0
- data/lib/active_matrix/util/cacheable.rb +73 -0
- data/lib/{matrix_sdk → active_matrix}/util/events.rb +8 -8
- data/lib/{matrix_sdk → active_matrix}/util/extensions.rb +6 -15
- data/lib/active_matrix/util/state_event_cache.rb +167 -0
- data/lib/{matrix_sdk → active_matrix}/util/uri.rb +4 -4
- data/lib/active_matrix/version.rb +5 -0
- data/lib/active_matrix.rb +81 -0
- data/lib/generators/active_matrix/bot/bot_generator.rb +38 -0
- data/lib/generators/active_matrix/bot/templates/bot.rb.erb +111 -0
- data/lib/generators/active_matrix/bot/templates/bot_spec.rb.erb +68 -0
- data/lib/generators/active_matrix/install/install_generator.rb +44 -0
- data/lib/generators/active_matrix/install/templates/README +30 -0
- data/lib/generators/active_matrix/install/templates/active_matrix.rb +33 -0
- data/lib/generators/active_matrix/install/templates/agent_memory.rb +47 -0
- data/lib/generators/active_matrix/install/templates/conversation_context.rb +72 -0
- data/lib/generators/active_matrix/install/templates/create_agent_memories.rb +17 -0
- data/lib/generators/active_matrix/install/templates/create_conversation_contexts.rb +21 -0
- data/lib/generators/active_matrix/install/templates/create_global_memories.rb +20 -0
- data/lib/generators/active_matrix/install/templates/create_matrix_agents.rb +26 -0
- data/lib/generators/active_matrix/install/templates/global_memory.rb +70 -0
- data/lib/generators/active_matrix/install/templates/matrix_agent.rb +127 -0
- metadata +168 -30
- data/lib/matrix_sdk/bot.rb +0 -4
- data/lib/matrix_sdk/util/account_data_cache.rb +0 -91
- data/lib/matrix_sdk/util/state_event_cache.rb +0 -92
- data/lib/matrix_sdk/util/tinycache.rb +0 -140
- data/lib/matrix_sdk/util/tinycache_adapter.rb +0 -87
- data/lib/matrix_sdk/version.rb +0 -5
- data/lib/matrix_sdk.rb +0 -75
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/active_record'
|
5
|
+
|
6
|
+
module ActiveMatrix
|
7
|
+
module Generators
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
include ActiveRecord::Generators::Migration
|
10
|
+
|
11
|
+
source_root File.expand_path('templates', __dir__)
|
12
|
+
|
13
|
+
desc 'Creates ActiveMatrix migrations and initializers'
|
14
|
+
|
15
|
+
def create_migrations
|
16
|
+
migration_template 'create_matrix_agents.rb', 'db/migrate/create_matrix_agents.rb'
|
17
|
+
migration_template 'create_agent_memories.rb', 'db/migrate/create_agent_memories.rb'
|
18
|
+
migration_template 'create_conversation_contexts.rb', 'db/migrate/create_conversation_contexts.rb'
|
19
|
+
migration_template 'create_global_memories.rb', 'db/migrate/create_global_memories.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_initializer
|
23
|
+
template 'active_matrix.rb', 'config/initializers/active_matrix.rb'
|
24
|
+
end
|
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
|
+
def display_post_install
|
34
|
+
readme 'README' if behavior == :invoke
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def migration_version
|
40
|
+
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
===============================================================================
|
2
|
+
|
3
|
+
ActiveMatrix Multi-Agent System has been installed!
|
4
|
+
|
5
|
+
Next steps:
|
6
|
+
|
7
|
+
1. Run migrations:
|
8
|
+
rails db:migrate
|
9
|
+
|
10
|
+
2. Create your first bot:
|
11
|
+
rails generate active_matrix:bot MyFirstBot
|
12
|
+
|
13
|
+
3. Configure your agents in the Rails console:
|
14
|
+
agent = MatrixAgent.create!(
|
15
|
+
name: 'captain',
|
16
|
+
homeserver: 'https://matrix.org',
|
17
|
+
username: 'captain_bot',
|
18
|
+
password: 'secure_password',
|
19
|
+
bot_class: 'MyFirstBot'
|
20
|
+
)
|
21
|
+
|
22
|
+
4. Start the agent system:
|
23
|
+
ActiveMatrix::AgentManager.instance.start_all
|
24
|
+
|
25
|
+
Or start individual agents:
|
26
|
+
ActiveMatrix::AgentManager.instance.start_agent(agent)
|
27
|
+
|
28
|
+
For more information, visit: https://github.com/seuros/agent_smith
|
29
|
+
|
30
|
+
===============================================================================
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# ActiveMatrix configuration
|
4
|
+
ActiveMatrix.configure do |config|
|
5
|
+
# Agent configuration
|
6
|
+
config.agent_startup_delay = 2.seconds # Delay between starting each agent
|
7
|
+
config.max_agents_per_process = 10 # Maximum agents in a single process
|
8
|
+
config.agent_health_check_interval = 30.seconds
|
9
|
+
|
10
|
+
# Memory configuration
|
11
|
+
config.conversation_history_limit = 20
|
12
|
+
config.conversation_stale_after = 1.day
|
13
|
+
config.memory_cleanup_interval = 1.hour
|
14
|
+
|
15
|
+
# Event routing configuration
|
16
|
+
config.event_queue_size = 1000
|
17
|
+
config.event_processing_timeout = 30.seconds
|
18
|
+
|
19
|
+
# Client pool configuration
|
20
|
+
config.max_clients_per_homeserver = 5
|
21
|
+
config.client_idle_timeout = 5.minutes
|
22
|
+
|
23
|
+
# Logging
|
24
|
+
config.agent_log_level = :info
|
25
|
+
config.log_agent_events = Rails.env.development?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Start agent manager on Rails boot (can be disabled in environments)
|
29
|
+
if Rails.env.production? || ENV['START_AGENTS'].present?
|
30
|
+
Rails.application.config.after_initialize do
|
31
|
+
ActiveMatrix::AgentManager.instance.start_all
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ConversationContext < ApplicationRecord
|
4
|
+
belongs_to :matrix_agent
|
5
|
+
|
6
|
+
validates :user_id, presence: true
|
7
|
+
validates :room_id, presence: true
|
8
|
+
validates :user_id, uniqueness: { scope: %i[matrix_agent_id room_id] }
|
9
|
+
|
10
|
+
# Configuration
|
11
|
+
MAX_HISTORY_SIZE = 20
|
12
|
+
|
13
|
+
# Scopes
|
14
|
+
scope :recent, -> { order(last_message_at: :desc) }
|
15
|
+
scope :active, -> { where('last_message_at > ?', 1.hour.ago) }
|
16
|
+
scope :stale, -> { where('last_message_at < ?', 1.day.ago) }
|
17
|
+
|
18
|
+
# Add a message to the history
|
19
|
+
def add_message(message_data)
|
20
|
+
messages = message_history['messages'] || []
|
21
|
+
|
22
|
+
# Add new message
|
23
|
+
messages << {
|
24
|
+
'event_id' => message_data[:event_id],
|
25
|
+
'sender' => message_data[:sender],
|
26
|
+
'content' => message_data[:content],
|
27
|
+
'timestamp' => message_data[:timestamp] || Time.current.to_i
|
28
|
+
}
|
29
|
+
|
30
|
+
# Keep only recent messages
|
31
|
+
messages = messages.last(MAX_HISTORY_SIZE)
|
32
|
+
|
33
|
+
# Update record
|
34
|
+
self.message_history = { 'messages' => messages }
|
35
|
+
self.last_message_at = Time.current
|
36
|
+
self.message_count = messages.size
|
37
|
+
save!
|
38
|
+
|
39
|
+
# Update cache
|
40
|
+
write_to_cache
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get recent messages
|
44
|
+
def recent_messages(limit = 10)
|
45
|
+
messages = message_history['messages'] || []
|
46
|
+
messages.last(limit)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Clear old messages but keep context
|
50
|
+
def prune_history!
|
51
|
+
messages = message_history['messages'] || []
|
52
|
+
self.message_history = { 'messages' => messages.last(5) }
|
53
|
+
save!
|
54
|
+
end
|
55
|
+
|
56
|
+
# Cache integration
|
57
|
+
def cache_key
|
58
|
+
"conversation/#{matrix_agent_id}/#{user_id}/#{room_id}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_to_cache
|
62
|
+
Rails.cache.write(cache_key, {
|
63
|
+
context: context,
|
64
|
+
recent_messages: recent_messages,
|
65
|
+
last_message_at: last_message_at
|
66
|
+
}, expires_in: 1.hour)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.cleanup_stale!
|
70
|
+
stale.destroy_all
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateAgentMemories < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
create_table :agent_memories do |t|
|
6
|
+
t.references :matrix_agent, null: false, foreign_key: true
|
7
|
+
t.string :key, null: false
|
8
|
+
t.jsonb :value, default: {}
|
9
|
+
t.datetime :expires_at
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
|
13
|
+
t.index [:matrix_agent_id, :key], unique: true
|
14
|
+
t.index :expires_at
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateConversationContexts < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
create_table :conversation_contexts do |t|
|
6
|
+
t.references :matrix_agent, null: false, foreign_key: true
|
7
|
+
t.string :user_id, null: false
|
8
|
+
t.string :room_id, null: false
|
9
|
+
t.jsonb :context, default: {}
|
10
|
+
t.jsonb :message_history, default: { messages: [] }
|
11
|
+
t.datetime :last_message_at
|
12
|
+
t.integer :message_count, default: 0
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
|
16
|
+
t.index [:matrix_agent_id, :user_id, :room_id], unique: true, name: 'idx_conv_context_unique'
|
17
|
+
t.index :last_message_at
|
18
|
+
t.index :room_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateGlobalMemories < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
create_table :global_memories do |t|
|
6
|
+
t.string :key, null: false
|
7
|
+
t.jsonb :value, default: {}
|
8
|
+
t.string :category
|
9
|
+
t.datetime :expires_at
|
10
|
+
t.boolean :public_read, default: true
|
11
|
+
t.boolean :public_write, default: false
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
|
15
|
+
t.index :key, unique: true
|
16
|
+
t.index :category
|
17
|
+
t.index :expires_at
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateMatrixAgents < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
create_table :matrix_agents do |t|
|
6
|
+
t.string :name, null: false
|
7
|
+
t.string :homeserver, null: false
|
8
|
+
t.string :username, null: false
|
9
|
+
t.string :encrypted_password
|
10
|
+
t.string :access_token
|
11
|
+
t.string :state, default: 'offline', null: false
|
12
|
+
t.string :bot_class, null: false
|
13
|
+
t.jsonb :settings, default: {}
|
14
|
+
t.string :last_sync_token
|
15
|
+
t.datetime :last_active_at
|
16
|
+
t.integer :rooms_count, default: 0
|
17
|
+
t.integer :messages_handled, default: 0
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
|
21
|
+
t.index :name, unique: true
|
22
|
+
t.index :state
|
23
|
+
t.index [:homeserver, :username]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GlobalMemory < ApplicationRecord
|
4
|
+
validates :key, presence: true, uniqueness: true
|
5
|
+
|
6
|
+
scope :active, -> { where('expires_at IS NULL OR expires_at > ?', Time.current) }
|
7
|
+
scope :expired, -> { where('expires_at <= ?', Time.current) }
|
8
|
+
scope :by_category, ->(category) { where(category: category) }
|
9
|
+
scope :readable, -> { where(public_read: true) }
|
10
|
+
scope :writable, -> { where(public_write: true) }
|
11
|
+
|
12
|
+
def expired?
|
13
|
+
expires_at.present? && expires_at <= Time.current
|
14
|
+
end
|
15
|
+
|
16
|
+
def readable_by?(agent)
|
17
|
+
public_read || (agent.is_a?(MatrixAgent) && agent.admin?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def writable_by?(agent)
|
21
|
+
public_write || (agent.is_a?(MatrixAgent) && agent.admin?)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Cache integration
|
25
|
+
def cache_key
|
26
|
+
"global/#{key}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_to_cache
|
30
|
+
return unless active?
|
31
|
+
|
32
|
+
ttl = expires_at.present? ? expires_at - Time.current : nil
|
33
|
+
Rails.cache.write(cache_key, value, expires_in: ttl)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get(key)
|
37
|
+
# Try cache first
|
38
|
+
cached = Rails.cache.read("global/#{key}")
|
39
|
+
return cached if cached.present?
|
40
|
+
|
41
|
+
# Fallback to database
|
42
|
+
memory = find_by(key: key)
|
43
|
+
return unless memory&.active?
|
44
|
+
|
45
|
+
memory.write_to_cache
|
46
|
+
memory.value
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.set(key, value, category: nil, expires_in: nil, public_read: true, public_write: false)
|
50
|
+
memory = find_or_initialize_by(key: key)
|
51
|
+
memory.value = value
|
52
|
+
memory.category = category
|
53
|
+
memory.expires_at = expires_in.present? ? Time.current + expires_in : nil
|
54
|
+
memory.public_read = public_read
|
55
|
+
memory.public_write = public_write
|
56
|
+
memory.save!
|
57
|
+
memory.write_to_cache
|
58
|
+
memory
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.cleanup_expired!
|
62
|
+
expired.destroy_all
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def active?
|
68
|
+
!expired?
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class MatrixAgent < ApplicationRecord
|
4
|
+
# Associations
|
5
|
+
has_many :agent_memories, dependent: :destroy
|
6
|
+
has_many :conversation_contexts, dependent: :destroy
|
7
|
+
|
8
|
+
# Validations
|
9
|
+
validates :name, presence: true, uniqueness: true
|
10
|
+
validates :homeserver, presence: true
|
11
|
+
validates :username, presence: true
|
12
|
+
validates :bot_class, presence: true
|
13
|
+
validate :valid_bot_class?
|
14
|
+
|
15
|
+
# Scopes
|
16
|
+
scope :active, -> { where.not(state: %i[offline error]) }
|
17
|
+
scope :online, -> { where(state: %i[online_idle online_busy]) }
|
18
|
+
scope :offline, -> { where(state: :offline) }
|
19
|
+
|
20
|
+
# Encrypts password before saving
|
21
|
+
before_save :encrypt_password, if: :password_changed?
|
22
|
+
|
23
|
+
# State machine for agent lifecycle
|
24
|
+
state_machine :state, initial: :offline do
|
25
|
+
state :offline
|
26
|
+
state :connecting
|
27
|
+
state :online_idle
|
28
|
+
state :online_busy
|
29
|
+
state :error
|
30
|
+
state :paused
|
31
|
+
|
32
|
+
event :connect do
|
33
|
+
transition %i[offline error paused] => :connecting
|
34
|
+
end
|
35
|
+
|
36
|
+
event :connection_established do
|
37
|
+
transition connecting: :online_idle
|
38
|
+
end
|
39
|
+
|
40
|
+
after_transition to: :online_idle do |agent|
|
41
|
+
agent.update(last_active_at: Time.current)
|
42
|
+
end
|
43
|
+
|
44
|
+
event :start_processing do
|
45
|
+
transition online_idle: :online_busy
|
46
|
+
end
|
47
|
+
|
48
|
+
event :finish_processing do
|
49
|
+
transition online_busy: :online_idle
|
50
|
+
end
|
51
|
+
|
52
|
+
event :disconnect do
|
53
|
+
transition %i[connecting online_idle online_busy] => :offline
|
54
|
+
end
|
55
|
+
|
56
|
+
event :encounter_error do
|
57
|
+
transition any => :error
|
58
|
+
end
|
59
|
+
|
60
|
+
event :pause do
|
61
|
+
transition %i[online_idle online_busy] => :paused
|
62
|
+
end
|
63
|
+
|
64
|
+
event :resume do
|
65
|
+
transition paused: :connecting
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Instance methods
|
70
|
+
def bot_instance
|
71
|
+
@bot_instance ||= bot_class.constantize.new(client) if running?
|
72
|
+
end
|
73
|
+
|
74
|
+
def client
|
75
|
+
@client ||= if access_token.present?
|
76
|
+
ActiveMatrix::Client.new(homeserver, access_token: access_token)
|
77
|
+
else
|
78
|
+
ActiveMatrix::Client.new(homeserver)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def running?
|
83
|
+
%i[online_idle online_busy].include?(state.to_sym)
|
84
|
+
end
|
85
|
+
|
86
|
+
def memory
|
87
|
+
@memory ||= ActiveMatrix::Memory::AgentMemory.new(self)
|
88
|
+
end
|
89
|
+
|
90
|
+
def increment_messages_handled!
|
91
|
+
increment!(:messages_handled)
|
92
|
+
end
|
93
|
+
|
94
|
+
def update_activity!
|
95
|
+
update(last_active_at: Time.current)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Password handling
|
99
|
+
attr_accessor :password
|
100
|
+
|
101
|
+
def authenticate(password)
|
102
|
+
return false unless encrypted_password.present?
|
103
|
+
|
104
|
+
BCrypt::Password.new(encrypted_password) == password
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def password_changed?
|
110
|
+
password.present?
|
111
|
+
end
|
112
|
+
|
113
|
+
def encrypt_password
|
114
|
+
self.encrypted_password = BCrypt::Password.create(password) if password.present?
|
115
|
+
end
|
116
|
+
|
117
|
+
def valid_bot_class?
|
118
|
+
return false if bot_class.blank?
|
119
|
+
|
120
|
+
begin
|
121
|
+
klass = bot_class.constantize
|
122
|
+
errors.add(:bot_class, 'must inherit from ActiveMatrix::Bot::Base') unless klass < ActiveMatrix::Bot::Base
|
123
|
+
rescue NameError
|
124
|
+
errors.add(:bot_class, 'must be a valid class name')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|