activematrix 0.0.1 → 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/active_matrix/bot/multi_instance_base.rb +189 -0
- data/lib/active_matrix/client.rb +5 -15
- data/lib/active_matrix/client_pool.rb +194 -0
- data/lib/active_matrix/event_router.rb +215 -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/active_matrix/room.rb +131 -51
- data/lib/active_matrix/rooms/space.rb +1 -5
- data/lib/active_matrix/user.rb +10 -0
- data/lib/active_matrix/util/account_data_cache.rb +62 -24
- data/lib/active_matrix/util/cacheable.rb +73 -0
- data/lib/active_matrix/util/extensions.rb +4 -0
- data/lib/active_matrix/util/state_event_cache.rb +106 -31
- data/lib/active_matrix/version.rb +1 -1
- data/lib/active_matrix.rb +51 -3
- 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 +110 -4
- data/lib/active_matrix/util/rails_cache_adapter.rb +0 -37
- data/lib/active_matrix/util/tinycache.rb +0 -145
- data/lib/active_matrix/util/tinycache_adapter.rb +0 -87
@@ -0,0 +1,215 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'concurrent'
|
5
|
+
|
6
|
+
module ActiveMatrix
|
7
|
+
# Routes Matrix events to appropriate agents
|
8
|
+
class EventRouter
|
9
|
+
include Singleton
|
10
|
+
include ActiveMatrix::Logging
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@routes = Concurrent::Array.new
|
14
|
+
@event_queue = Queue.new
|
15
|
+
@processing = false
|
16
|
+
@worker_thread = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Register an event route
|
20
|
+
def register_route(agent_id:, room_id: nil, event_type: nil, user_id: nil, priority: 50, &block)
|
21
|
+
route = {
|
22
|
+
id: SecureRandom.uuid,
|
23
|
+
agent_id: agent_id,
|
24
|
+
room_id: room_id,
|
25
|
+
event_type: event_type,
|
26
|
+
user_id: user_id,
|
27
|
+
priority: priority,
|
28
|
+
handler: block
|
29
|
+
}
|
30
|
+
|
31
|
+
@routes << route
|
32
|
+
@routes.sort_by! { |r| -r[:priority] } # Higher priority first
|
33
|
+
|
34
|
+
logger.debug "Registered route: #{route.except(:handler).inspect}"
|
35
|
+
route[:id]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Unregister a route
|
39
|
+
def unregister_route(route_id)
|
40
|
+
@routes.delete_if { |route| route[:id] == route_id }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Clear all routes for an agent
|
44
|
+
def clear_agent_routes(agent_id)
|
45
|
+
@routes.delete_if { |route| route[:agent_id] == agent_id }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Route an event to appropriate agents
|
49
|
+
def route_event(event)
|
50
|
+
return unless @processing
|
51
|
+
|
52
|
+
# Queue the event for processing
|
53
|
+
@event_queue << event
|
54
|
+
end
|
55
|
+
|
56
|
+
# Start the event router
|
57
|
+
def start
|
58
|
+
return if @processing
|
59
|
+
|
60
|
+
@processing = true
|
61
|
+
@worker_thread = Thread.new do
|
62
|
+
Thread.current.name = 'event-router'
|
63
|
+
process_events
|
64
|
+
end
|
65
|
+
|
66
|
+
logger.info 'Event router started'
|
67
|
+
end
|
68
|
+
|
69
|
+
# Stop the event router
|
70
|
+
def stop
|
71
|
+
@processing = false
|
72
|
+
@worker_thread&.kill
|
73
|
+
@event_queue.clear
|
74
|
+
|
75
|
+
logger.info 'Event router stopped'
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check if router is running
|
79
|
+
def running?
|
80
|
+
@processing && @worker_thread&.alive?
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get routes for debugging
|
84
|
+
def routes_summary
|
85
|
+
@routes.map { |r| r.except(:handler) }
|
86
|
+
end
|
87
|
+
|
88
|
+
# Broadcast an event to all agents
|
89
|
+
def broadcast_event(event)
|
90
|
+
AgentRegistry.instance.all_instances.each do |bot|
|
91
|
+
bot._handle_event(event) if bot.respond_to?(:_handle_event)
|
92
|
+
rescue StandardError => e
|
93
|
+
logger.error "Error broadcasting to bot: #{e.message}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def process_events
|
100
|
+
while @processing
|
101
|
+
begin
|
102
|
+
# Wait for event with timeout
|
103
|
+
event = nil
|
104
|
+
Timeout.timeout(1) { event = @event_queue.pop }
|
105
|
+
|
106
|
+
next unless event
|
107
|
+
|
108
|
+
# Find matching routes
|
109
|
+
matching_routes = find_matching_routes(event)
|
110
|
+
|
111
|
+
if matching_routes.empty?
|
112
|
+
logger.debug "No routes matched for event: #{event[:type]} in #{event[:room_id]}"
|
113
|
+
next
|
114
|
+
end
|
115
|
+
|
116
|
+
# Process routes in priority order
|
117
|
+
matching_routes.each do |route|
|
118
|
+
process_route(route, event)
|
119
|
+
end
|
120
|
+
rescue Timeout::Error
|
121
|
+
# Normal timeout, continue loop
|
122
|
+
rescue StandardError => e
|
123
|
+
logger.error "Event router error: #{e.message}"
|
124
|
+
logger.error e.backtrace.join("\n")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def find_matching_routes(event)
|
130
|
+
@routes.select do |route|
|
131
|
+
# Check room match
|
132
|
+
next false if route[:room_id] && route[:room_id] != event[:room_id]
|
133
|
+
|
134
|
+
# Check event type match
|
135
|
+
next false if route[:event_type] && route[:event_type] != event[:type]
|
136
|
+
|
137
|
+
# Check user match
|
138
|
+
next false if route[:user_id] && route[:user_id] != event[:sender]
|
139
|
+
|
140
|
+
# Check if agent is running
|
141
|
+
registry = AgentRegistry.instance
|
142
|
+
agent_entry = registry.get(route[:agent_id])
|
143
|
+
next false unless agent_entry
|
144
|
+
|
145
|
+
true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def process_route(route, event)
|
150
|
+
registry = AgentRegistry.instance
|
151
|
+
agent_entry = registry.get(route[:agent_id])
|
152
|
+
|
153
|
+
return unless agent_entry
|
154
|
+
|
155
|
+
bot = agent_entry[:instance]
|
156
|
+
|
157
|
+
begin
|
158
|
+
if route[:handler]
|
159
|
+
# Custom handler
|
160
|
+
route[:handler].call(bot, event)
|
161
|
+
elsif bot.respond_to?(:_handle_event)
|
162
|
+
# Default handling
|
163
|
+
bot._handle_event(event)
|
164
|
+
end
|
165
|
+
rescue StandardError => e
|
166
|
+
logger.error "Error processing route for agent #{agent_entry[:record].name}: #{e.message}"
|
167
|
+
logger.error e.backtrace.first(5).join("\n")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Routing DSL for bots
|
173
|
+
module Bot
|
174
|
+
class MultiInstanceBase
|
175
|
+
# Route events to this bot
|
176
|
+
def self.route(event_type: nil, room_id: nil, user_id: nil, priority: 50, &block)
|
177
|
+
# Routes will be registered when bot instance is created
|
178
|
+
@event_routes ||= []
|
179
|
+
@event_routes << {
|
180
|
+
event_type: event_type,
|
181
|
+
room_id: room_id,
|
182
|
+
user_id: user_id,
|
183
|
+
priority: priority,
|
184
|
+
handler: block
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
# Get defined routes
|
189
|
+
def self.event_routes
|
190
|
+
@event_routes || []
|
191
|
+
end
|
192
|
+
|
193
|
+
# Register routes for this instance
|
194
|
+
def register_routes
|
195
|
+
return unless @agent_record
|
196
|
+
|
197
|
+
router = EventRouter.instance
|
198
|
+
|
199
|
+
self.class.event_routes.each do |route_def|
|
200
|
+
router.register_route(
|
201
|
+
agent_id: @agent_record.id,
|
202
|
+
**route_def
|
203
|
+
)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Clear routes for this instance
|
208
|
+
def clear_routes
|
209
|
+
return unless @agent_record
|
210
|
+
|
211
|
+
EventRouter.instance.clear_agent_routes(@agent_record.id)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveMatrix
|
4
|
+
module Memory
|
5
|
+
# Per-agent private memory storage
|
6
|
+
class AgentMemory < Base
|
7
|
+
attr_reader :agent
|
8
|
+
|
9
|
+
def initialize(agent)
|
10
|
+
super()
|
11
|
+
@agent = agent
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get a value from agent memory
|
15
|
+
def get(key)
|
16
|
+
fetch_with_cache(key) do
|
17
|
+
return nil unless defined?(::AgentMemory)
|
18
|
+
|
19
|
+
memory = @agent.agent_memories.active.find_by(key: key)
|
20
|
+
memory&.value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set a value in agent memory
|
25
|
+
def set(key, value, expires_in: nil)
|
26
|
+
return false unless defined?(::AgentMemory)
|
27
|
+
|
28
|
+
write_through(key, value, expires_in: expires_in) do
|
29
|
+
memory = @agent.agent_memories.find_or_initialize_by(key: key)
|
30
|
+
memory.value = value
|
31
|
+
memory.expires_at = expires_in.present? ? Time.current + expires_in : nil
|
32
|
+
memory.save!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check if a key exists
|
37
|
+
def exists?(key)
|
38
|
+
return false unless defined?(::AgentMemory)
|
39
|
+
|
40
|
+
if @cache_enabled && Rails.cache.exist?(cache_key(key))
|
41
|
+
true
|
42
|
+
else
|
43
|
+
@agent.agent_memories.active.exists?(key: key)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Delete a key
|
48
|
+
def delete(key)
|
49
|
+
return false unless defined?(::AgentMemory)
|
50
|
+
|
51
|
+
delete_through(key) do
|
52
|
+
@agent.agent_memories.where(key: key).destroy_all.any?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get all keys
|
57
|
+
def keys
|
58
|
+
return [] unless defined?(::AgentMemory)
|
59
|
+
|
60
|
+
@agent.agent_memories.active.pluck(:key)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get all memory as hash
|
64
|
+
def all
|
65
|
+
return {} unless defined?(::AgentMemory)
|
66
|
+
|
67
|
+
@agent.agent_memories.active.pluck(:key, :value).to_h
|
68
|
+
end
|
69
|
+
|
70
|
+
# Clear all agent memory
|
71
|
+
def clear!
|
72
|
+
return false unless defined?(::AgentMemory)
|
73
|
+
|
74
|
+
@agent.agent_memories.destroy_all
|
75
|
+
|
76
|
+
# Clear cache entries
|
77
|
+
keys.each { |key| Rails.cache.delete(cache_key(key)) } if @cache_enabled
|
78
|
+
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
# Remember something with optional TTL
|
83
|
+
def remember(key, expires_in: nil)
|
84
|
+
value = get(key)
|
85
|
+
return value if value.present?
|
86
|
+
|
87
|
+
value = yield
|
88
|
+
set(key, value, expires_in: expires_in) if value.present?
|
89
|
+
value
|
90
|
+
end
|
91
|
+
|
92
|
+
# Increment a counter
|
93
|
+
def increment(key, amount = 1)
|
94
|
+
current = get(key) || 0
|
95
|
+
new_value = current + amount
|
96
|
+
set(key, new_value)
|
97
|
+
new_value
|
98
|
+
end
|
99
|
+
|
100
|
+
# Decrement a counter
|
101
|
+
def decrement(key, amount = 1)
|
102
|
+
increment(key, -amount)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Add to a list
|
106
|
+
def push(key, value)
|
107
|
+
list = get(key) || []
|
108
|
+
list << value
|
109
|
+
set(key, list)
|
110
|
+
list
|
111
|
+
end
|
112
|
+
|
113
|
+
# Remove from a list
|
114
|
+
def pull(key, value)
|
115
|
+
list = get(key) || []
|
116
|
+
list.delete(value)
|
117
|
+
set(key, list)
|
118
|
+
list
|
119
|
+
end
|
120
|
+
|
121
|
+
protected
|
122
|
+
|
123
|
+
def cache_key(key)
|
124
|
+
"agent_memory/#{@agent.id}/#{key}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveMatrix
|
4
|
+
module Memory
|
5
|
+
# Base class for memory implementations
|
6
|
+
class Base
|
7
|
+
include ActiveMatrix::Logging
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@cache_enabled = Rails.cache.present? rescue false
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get a value from memory
|
14
|
+
def get(key)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set a value in memory
|
19
|
+
def set(key, value, expires_in: nil)
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
# Check if a key exists
|
24
|
+
def exists?(key)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Delete a key
|
29
|
+
def delete(key)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get multiple keys at once
|
34
|
+
def get_multi(*keys)
|
35
|
+
keys.to_h { |key| [key, get(key)] }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set multiple keys at once
|
39
|
+
def set_multi(hash, expires_in: nil)
|
40
|
+
hash.each { |key, value| set(key, value, expires_in: expires_in) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Clear all memory (use with caution)
|
44
|
+
def clear!
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
# Generate cache key
|
51
|
+
def cache_key(key)
|
52
|
+
raise NotImplementedError
|
53
|
+
end
|
54
|
+
|
55
|
+
# Try cache first, then database
|
56
|
+
def fetch_with_cache(key, expires_in: nil)
|
57
|
+
return yield unless @cache_enabled
|
58
|
+
|
59
|
+
cached_key = cache_key(key)
|
60
|
+
|
61
|
+
# Try cache first
|
62
|
+
cached = Rails.cache.read(cached_key)
|
63
|
+
return cached if cached.present?
|
64
|
+
|
65
|
+
# Get from source
|
66
|
+
value = yield
|
67
|
+
return nil if value.nil?
|
68
|
+
|
69
|
+
# Write to cache
|
70
|
+
Rails.cache.write(cached_key, value, expires_in: expires_in)
|
71
|
+
value
|
72
|
+
end
|
73
|
+
|
74
|
+
# Write through to cache and database
|
75
|
+
def write_through(key, value, expires_in: nil)
|
76
|
+
cached_key = cache_key(key)
|
77
|
+
|
78
|
+
# Write to database first
|
79
|
+
result = yield
|
80
|
+
|
81
|
+
# Then update cache if enabled
|
82
|
+
Rails.cache.write(cached_key, value, expires_in: expires_in) if @cache_enabled && result
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
# Delete from cache and database
|
88
|
+
def delete_through(key)
|
89
|
+
cached_key = cache_key(key)
|
90
|
+
|
91
|
+
# Delete from database
|
92
|
+
result = yield
|
93
|
+
|
94
|
+
# Delete from cache if enabled
|
95
|
+
Rails.cache.delete(cached_key) if @cache_enabled
|
96
|
+
|
97
|
+
result
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveMatrix
|
4
|
+
module Memory
|
5
|
+
# Per-conversation memory storage (speaker-specific)
|
6
|
+
class ConversationMemory < Base
|
7
|
+
attr_reader :agent, :user_id, :room_id
|
8
|
+
|
9
|
+
def initialize(agent, user_id, room_id)
|
10
|
+
super()
|
11
|
+
@agent = agent
|
12
|
+
@user_id = user_id
|
13
|
+
@room_id = room_id
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get conversation context
|
17
|
+
def context
|
18
|
+
fetch_with_cache('context', expires_in: 1.hour) do
|
19
|
+
return {} unless defined?(::ConversationContext)
|
20
|
+
|
21
|
+
record = find_or_create_record
|
22
|
+
record.context
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Update conversation context
|
27
|
+
def update_context(data)
|
28
|
+
return false unless defined?(::ConversationContext)
|
29
|
+
|
30
|
+
record = find_or_create_record
|
31
|
+
record.context = record.context.merge(data)
|
32
|
+
record.save!
|
33
|
+
|
34
|
+
# Update cache
|
35
|
+
invalidate_cache
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
# Add a message to history
|
40
|
+
def add_message(event)
|
41
|
+
return false unless defined?(::ConversationContext)
|
42
|
+
|
43
|
+
record = find_or_create_record
|
44
|
+
record.add_message({
|
45
|
+
event_id: event[:event_id],
|
46
|
+
sender: event[:sender],
|
47
|
+
content: event.dig(:content, :body),
|
48
|
+
timestamp: event[:origin_server_ts] || (Time.current.to_i * 1000)
|
49
|
+
})
|
50
|
+
|
51
|
+
# Update agent activity
|
52
|
+
@agent.update_activity!
|
53
|
+
@agent.increment_messages_handled!
|
54
|
+
|
55
|
+
# Invalidate cache
|
56
|
+
invalidate_cache
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get recent messages
|
61
|
+
def recent_messages(limit = 10)
|
62
|
+
fetch_with_cache('recent_messages', expires_in: 5.minutes) do
|
63
|
+
return [] unless defined?(::ConversationContext)
|
64
|
+
|
65
|
+
record = find_or_create_record
|
66
|
+
record.recent_messages(limit)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get last message timestamp
|
71
|
+
def last_message_at
|
72
|
+
return nil unless defined?(::ConversationContext)
|
73
|
+
|
74
|
+
record = conversation_record
|
75
|
+
record&.last_message_at
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check if conversation is active (recent activity)
|
79
|
+
def active?
|
80
|
+
last_at = last_message_at
|
81
|
+
last_at.present? && last_at > 1.hour.ago
|
82
|
+
end
|
83
|
+
|
84
|
+
# Clear conversation history but keep context
|
85
|
+
def clear_history!
|
86
|
+
return false unless defined?(::ConversationContext)
|
87
|
+
|
88
|
+
record = conversation_record
|
89
|
+
return false unless record
|
90
|
+
|
91
|
+
record.prune_history!
|
92
|
+
invalidate_cache
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Get or set a specific context value
|
97
|
+
def [](key)
|
98
|
+
context[key.to_s]
|
99
|
+
end
|
100
|
+
|
101
|
+
def []=(key, value)
|
102
|
+
update_context(key.to_s => value)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Remember something in conversation context
|
106
|
+
def remember(key)
|
107
|
+
value = self[key]
|
108
|
+
return value if value.present?
|
109
|
+
|
110
|
+
value = yield
|
111
|
+
self[key] = value if value.present?
|
112
|
+
value
|
113
|
+
end
|
114
|
+
|
115
|
+
# Get conversation summary
|
116
|
+
def summary
|
117
|
+
{
|
118
|
+
user_id: @user_id,
|
119
|
+
room_id: @room_id,
|
120
|
+
active: active?,
|
121
|
+
message_count: conversation_record&.message_count || 0,
|
122
|
+
last_message_at: last_message_at,
|
123
|
+
context: context
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
def cache_key(suffix)
|
130
|
+
"conversation/#{@agent.id}/#{@user_id}/#{@room_id}/#{suffix}"
|
131
|
+
end
|
132
|
+
|
133
|
+
def conversation_record
|
134
|
+
return nil unless defined?(::ConversationContext)
|
135
|
+
|
136
|
+
::ConversationContext.find_by(
|
137
|
+
matrix_agent: @agent,
|
138
|
+
user_id: @user_id,
|
139
|
+
room_id: @room_id
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
def find_or_create_record
|
144
|
+
return nil unless defined?(::ConversationContext)
|
145
|
+
|
146
|
+
::ConversationContext.find_or_create_by!(
|
147
|
+
matrix_agent: @agent,
|
148
|
+
user_id: @user_id,
|
149
|
+
room_id: @room_id
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def invalidate_cache
|
154
|
+
return unless @cache_enabled
|
155
|
+
|
156
|
+
Rails.cache.delete(cache_key('context'))
|
157
|
+
Rails.cache.delete(cache_key('recent_messages'))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|