smart_message 0.0.1
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 +7 -0
- data/.envrc +3 -0
- data/.gitignore +8 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +100 -0
- data/COMMITS.md +196 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +71 -0
- data/README.md +303 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/README.md +52 -0
- data/docs/architecture.md +370 -0
- data/docs/dispatcher.md +593 -0
- data/docs/examples.md +808 -0
- data/docs/getting-started.md +235 -0
- data/docs/ideas_to_think_about.md +329 -0
- data/docs/serializers.md +575 -0
- data/docs/transports.md +501 -0
- data/docs/troubleshooting.md +582 -0
- data/examples/01_point_to_point_orders.rb +200 -0
- data/examples/02_publish_subscribe_events.rb +364 -0
- data/examples/03_many_to_many_chat.rb +608 -0
- data/examples/README.md +335 -0
- data/examples/tmux_chat/README.md +283 -0
- data/examples/tmux_chat/bot_agent.rb +272 -0
- data/examples/tmux_chat/human_agent.rb +197 -0
- data/examples/tmux_chat/room_monitor.rb +158 -0
- data/examples/tmux_chat/shared_chat_system.rb +295 -0
- data/examples/tmux_chat/start_chat_demo.sh +190 -0
- data/examples/tmux_chat/stop_chat_demo.sh +22 -0
- data/lib/simple_stats.rb +57 -0
- data/lib/smart_message/base.rb +284 -0
- data/lib/smart_message/dispatcher/.keep +0 -0
- data/lib/smart_message/dispatcher.rb +146 -0
- data/lib/smart_message/errors.rb +29 -0
- data/lib/smart_message/header.rb +20 -0
- data/lib/smart_message/logger/base.rb +8 -0
- data/lib/smart_message/logger.rb +7 -0
- data/lib/smart_message/serializer/base.rb +23 -0
- data/lib/smart_message/serializer/json.rb +22 -0
- data/lib/smart_message/serializer.rb +10 -0
- data/lib/smart_message/transport/base.rb +85 -0
- data/lib/smart_message/transport/memory_transport.rb +69 -0
- data/lib/smart_message/transport/registry.rb +59 -0
- data/lib/smart_message/transport/stdout_transport.rb +62 -0
- data/lib/smart_message/transport.rb +41 -0
- data/lib/smart_message/version.rb +7 -0
- data/lib/smart_message/wrapper.rb +43 -0
- data/lib/smart_message.rb +54 -0
- data/smart_message.gemspec +53 -0
- metadata +252 -0
@@ -0,0 +1,608 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# examples/03_many_to_many_chat.rb
|
3
|
+
#
|
4
|
+
# Many-to-Many Messaging Example: Distributed Chat System
|
5
|
+
#
|
6
|
+
# This example demonstrates many-to-many messaging where multiple chat agents
|
7
|
+
# can send messages to multiple chat rooms, and other agents receive and respond
|
8
|
+
# to messages based on their interests and capabilities.
|
9
|
+
|
10
|
+
require_relative '../lib/smart_message'
|
11
|
+
|
12
|
+
puts "=== SmartMessage Example: Many-to-Many Distributed Chat ==="
|
13
|
+
puts
|
14
|
+
|
15
|
+
# Define the Chat Message
|
16
|
+
class ChatMessage < SmartMessage::Base
|
17
|
+
property :message_id
|
18
|
+
property :room_id
|
19
|
+
property :sender_id
|
20
|
+
property :sender_name
|
21
|
+
property :content
|
22
|
+
property :message_type # 'user', 'bot', 'system'
|
23
|
+
property :timestamp
|
24
|
+
property :mentions # Array of user IDs mentioned
|
25
|
+
property :metadata
|
26
|
+
|
27
|
+
config do
|
28
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
29
|
+
serializer SmartMessage::Serializer::JSON.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.process(message_header, message_payload)
|
33
|
+
chat_data = JSON.parse(message_payload)
|
34
|
+
puts "š¬ Chat message in #{chat_data['room_id']}: #{chat_data['content']}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Define Bot Command Message
|
39
|
+
class BotCommandMessage < SmartMessage::Base
|
40
|
+
property :command_id
|
41
|
+
property :room_id
|
42
|
+
property :user_id
|
43
|
+
property :command
|
44
|
+
property :parameters
|
45
|
+
property :timestamp
|
46
|
+
|
47
|
+
config do
|
48
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
49
|
+
serializer SmartMessage::Serializer::JSON.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.process(message_header, message_payload)
|
53
|
+
command_data = JSON.parse(message_payload)
|
54
|
+
puts "š¤ Bot command: #{command_data['command']} in #{command_data['room_id']}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Define System Notification Message
|
59
|
+
class SystemNotificationMessage < SmartMessage::Base
|
60
|
+
property :notification_id
|
61
|
+
property :room_id
|
62
|
+
property :notification_type # 'user_joined', 'user_left', 'room_created'
|
63
|
+
property :content
|
64
|
+
property :timestamp
|
65
|
+
property :metadata
|
66
|
+
|
67
|
+
config do
|
68
|
+
transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
|
69
|
+
serializer SmartMessage::Serializer::JSON.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.process(message_header, message_payload)
|
73
|
+
notif_data = JSON.parse(message_payload)
|
74
|
+
puts "š System: #{notif_data['content']} in #{notif_data['room_id']}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Human Chat Agent
|
79
|
+
class HumanChatAgent
|
80
|
+
attr_reader :user_id, :name, :active_rooms
|
81
|
+
|
82
|
+
def initialize(user_id:, name:)
|
83
|
+
@user_id = user_id
|
84
|
+
@name = name
|
85
|
+
@active_rooms = []
|
86
|
+
@message_counter = 0
|
87
|
+
|
88
|
+
puts "š¤ #{@name} (#{@user_id}): Joining chat system..."
|
89
|
+
|
90
|
+
# Subscribe to all message types this agent cares about
|
91
|
+
ChatMessage.subscribe("HumanChatAgent.handle_chat_message_#{@user_id}")
|
92
|
+
SystemNotificationMessage.subscribe("HumanChatAgent.handle_system_notification_#{@user_id}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def join_room(room_id)
|
96
|
+
return if @active_rooms.include?(room_id)
|
97
|
+
|
98
|
+
@active_rooms << room_id
|
99
|
+
puts "š¤ #{@name}: Joining room #{room_id}"
|
100
|
+
|
101
|
+
# Send system notification
|
102
|
+
send_system_notification(
|
103
|
+
room_id: room_id,
|
104
|
+
notification_type: 'user_joined',
|
105
|
+
content: "#{@name} joined the room"
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
def leave_room(room_id)
|
110
|
+
return unless @active_rooms.include?(room_id)
|
111
|
+
|
112
|
+
@active_rooms.delete(room_id)
|
113
|
+
puts "š¤ #{@name}: Leaving room #{room_id}"
|
114
|
+
|
115
|
+
send_system_notification(
|
116
|
+
room_id: room_id,
|
117
|
+
notification_type: 'user_left',
|
118
|
+
content: "#{@name} left the room"
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def send_message(room_id:, content:, mentions: [])
|
123
|
+
return unless @active_rooms.include?(room_id)
|
124
|
+
|
125
|
+
puts "š¤ #{@name}: Sending message to #{room_id}: '#{content}'"
|
126
|
+
|
127
|
+
# Check if this is a bot command
|
128
|
+
if content.start_with?('/')
|
129
|
+
send_bot_command(room_id, content)
|
130
|
+
else
|
131
|
+
message = ChatMessage.new(
|
132
|
+
message_id: generate_message_id,
|
133
|
+
room_id: room_id,
|
134
|
+
sender_id: @user_id,
|
135
|
+
sender_name: @name,
|
136
|
+
content: content,
|
137
|
+
message_type: 'user',
|
138
|
+
timestamp: Time.now.iso8601,
|
139
|
+
mentions: mentions,
|
140
|
+
metadata: { client: 'human_agent' }
|
141
|
+
)
|
142
|
+
|
143
|
+
message.publish
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Class method for message handling (required by SmartMessage)
|
148
|
+
def self.method_missing(method_name, *args)
|
149
|
+
if method_name.to_s.start_with?('handle_chat_message_')
|
150
|
+
user_id = method_name.to_s.split('_').last
|
151
|
+
agent = @@agents[user_id]
|
152
|
+
agent&.handle_chat_message(*args)
|
153
|
+
elsif method_name.to_s.start_with?('handle_system_notification_')
|
154
|
+
user_id = method_name.to_s.split('_').last
|
155
|
+
agent = @@agents[user_id]
|
156
|
+
agent&.handle_system_notification(*args)
|
157
|
+
else
|
158
|
+
super
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.register_agent(agent)
|
163
|
+
@@agents ||= {}
|
164
|
+
@@agents[agent.user_id] = agent
|
165
|
+
end
|
166
|
+
|
167
|
+
def handle_chat_message(message_header, message_payload)
|
168
|
+
chat_data = JSON.parse(message_payload)
|
169
|
+
|
170
|
+
# Only process messages from rooms we're in and not our own messages
|
171
|
+
return unless @active_rooms.include?(chat_data['room_id'])
|
172
|
+
return if chat_data['sender_id'] == @user_id
|
173
|
+
|
174
|
+
puts "š¤ #{@name}: Received message in #{chat_data['room_id']}"
|
175
|
+
|
176
|
+
# Respond if mentioned
|
177
|
+
if chat_data['mentions']&.include?(@user_id)
|
178
|
+
respond_to_mention(chat_data)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def handle_system_notification(message_header, message_payload)
|
183
|
+
notif_data = JSON.parse(message_payload)
|
184
|
+
|
185
|
+
# Only process notifications from rooms we're in
|
186
|
+
return unless @active_rooms.include?(notif_data['room_id'])
|
187
|
+
|
188
|
+
puts "š¤ #{@name}: Received system notification in #{notif_data['room_id']}"
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def send_bot_command(room_id, content)
|
194
|
+
command_parts = content[1..-1].split(' ')
|
195
|
+
command = command_parts.first
|
196
|
+
parameters = command_parts[1..-1]
|
197
|
+
|
198
|
+
bot_command = BotCommandMessage.new(
|
199
|
+
command_id: "CMD-#{Time.now.to_i}-#{rand(1000)}",
|
200
|
+
room_id: room_id,
|
201
|
+
user_id: @user_id,
|
202
|
+
command: command,
|
203
|
+
parameters: parameters,
|
204
|
+
timestamp: Time.now.iso8601
|
205
|
+
)
|
206
|
+
|
207
|
+
bot_command.publish
|
208
|
+
end
|
209
|
+
|
210
|
+
def respond_to_mention(chat_data)
|
211
|
+
# Simulate thinking time
|
212
|
+
sleep(0.2)
|
213
|
+
|
214
|
+
responses = [
|
215
|
+
"Thanks for mentioning me!",
|
216
|
+
"I'm here, what's up?",
|
217
|
+
"How can I help?",
|
218
|
+
"Yes, I saw that!",
|
219
|
+
"Interesting point!"
|
220
|
+
]
|
221
|
+
|
222
|
+
send_message(
|
223
|
+
room_id: chat_data['room_id'],
|
224
|
+
content: responses.sample
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
def send_system_notification(room_id:, notification_type:, content:)
|
229
|
+
notification = SystemNotificationMessage.new(
|
230
|
+
notification_id: "NOTIF-#{Time.now.to_i}-#{rand(1000)}",
|
231
|
+
room_id: room_id,
|
232
|
+
notification_type: notification_type,
|
233
|
+
content: content,
|
234
|
+
timestamp: Time.now.iso8601,
|
235
|
+
metadata: { triggered_by: @user_id }
|
236
|
+
)
|
237
|
+
|
238
|
+
notification.publish
|
239
|
+
end
|
240
|
+
|
241
|
+
def generate_message_id
|
242
|
+
@message_counter += 1
|
243
|
+
"MSG-#{@user_id}-#{@message_counter}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Bot Agent - Responds to commands and provides services
|
248
|
+
class BotAgent
|
249
|
+
def initialize(bot_id:, name:, capabilities: [])
|
250
|
+
@bot_id = bot_id
|
251
|
+
@name = name
|
252
|
+
@capabilities = capabilities
|
253
|
+
@active_rooms = []
|
254
|
+
|
255
|
+
puts "š¤ #{@name} (#{@bot_id}): Starting bot with capabilities: #{@capabilities.join(', ')}"
|
256
|
+
|
257
|
+
# Subscribe to bot commands and chat messages
|
258
|
+
BotCommandMessage.subscribe('BotAgent.handle_bot_command')
|
259
|
+
ChatMessage.subscribe('BotAgent.handle_chat_message')
|
260
|
+
end
|
261
|
+
|
262
|
+
def join_room(room_id)
|
263
|
+
return if @active_rooms.include?(room_id)
|
264
|
+
|
265
|
+
@active_rooms << room_id
|
266
|
+
puts "š¤ #{@name}: Joining room #{room_id}"
|
267
|
+
|
268
|
+
# Announce capabilities
|
269
|
+
send_chat_message(
|
270
|
+
room_id: room_id,
|
271
|
+
content: "š¤ Hello! I'm #{@name}. Available commands: #{@capabilities.map { |c| "/#{c}" }.join(', ')}"
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.handle_bot_command(message_header, message_payload)
|
276
|
+
command_data = JSON.parse(message_payload)
|
277
|
+
@@bots ||= []
|
278
|
+
|
279
|
+
# Find bot that can handle this command and is in the room
|
280
|
+
capable_bot = @@bots.find do |bot|
|
281
|
+
bot.can_handle_command?(command_data['command']) &&
|
282
|
+
bot.in_room?(command_data['room_id'])
|
283
|
+
end
|
284
|
+
|
285
|
+
capable_bot&.process_command(command_data)
|
286
|
+
end
|
287
|
+
|
288
|
+
def self.handle_chat_message(message_header, message_payload)
|
289
|
+
chat_data = JSON.parse(message_payload)
|
290
|
+
@@bots ||= []
|
291
|
+
|
292
|
+
# Let all bots in the room process the message
|
293
|
+
@@bots.each do |bot|
|
294
|
+
bot.process_chat_message(chat_data) if bot.in_room?(chat_data['room_id'])
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.register_bot(bot)
|
299
|
+
@@bots ||= []
|
300
|
+
@@bots << bot
|
301
|
+
end
|
302
|
+
|
303
|
+
def can_handle_command?(command)
|
304
|
+
@capabilities.include?(command)
|
305
|
+
end
|
306
|
+
|
307
|
+
def in_room?(room_id)
|
308
|
+
@active_rooms.include?(room_id)
|
309
|
+
end
|
310
|
+
|
311
|
+
def process_command(command_data)
|
312
|
+
puts "š¤ #{@name}: Processing command /#{command_data['command']}"
|
313
|
+
|
314
|
+
case command_data['command']
|
315
|
+
when 'weather'
|
316
|
+
handle_weather_command(command_data)
|
317
|
+
when 'joke'
|
318
|
+
handle_joke_command(command_data)
|
319
|
+
when 'help'
|
320
|
+
handle_help_command(command_data)
|
321
|
+
when 'stats'
|
322
|
+
handle_stats_command(command_data)
|
323
|
+
else
|
324
|
+
send_chat_message(
|
325
|
+
room_id: command_data['room_id'],
|
326
|
+
content: "Sorry, I don't know how to handle /#{command_data['command']}"
|
327
|
+
)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def process_chat_message(chat_data)
|
332
|
+
# Bot can respond to certain keywords or patterns
|
333
|
+
content = chat_data['content'].downcase
|
334
|
+
|
335
|
+
if content.include?('hello') || content.include?('hi')
|
336
|
+
send_chat_message(
|
337
|
+
room_id: chat_data['room_id'],
|
338
|
+
content: "Hello #{chat_data['sender_name']}! š"
|
339
|
+
)
|
340
|
+
elsif content.include?('help') && !content.start_with?('/')
|
341
|
+
send_chat_message(
|
342
|
+
room_id: chat_data['room_id'],
|
343
|
+
content: "Type /help to see available commands!"
|
344
|
+
)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
def handle_weather_command(command_data)
|
351
|
+
location = command_data['parameters'].first || 'your location'
|
352
|
+
weather_responses = [
|
353
|
+
"āļø It's sunny in #{location}!",
|
354
|
+
"š§ļø Looks like rain in #{location}",
|
355
|
+
"āļø Snow expected in #{location}",
|
356
|
+
"ā
Partly cloudy in #{location}"
|
357
|
+
]
|
358
|
+
|
359
|
+
send_chat_message(
|
360
|
+
room_id: command_data['room_id'],
|
361
|
+
content: weather_responses.sample
|
362
|
+
)
|
363
|
+
end
|
364
|
+
|
365
|
+
def handle_joke_command(command_data)
|
366
|
+
jokes = [
|
367
|
+
"Why don't scientists trust atoms? Because they make up everything!",
|
368
|
+
"Why did the scarecrow win an award? He was outstanding in his field!",
|
369
|
+
"What do you call a fake noodle? An impasta!",
|
370
|
+
"Why don't eggs tell jokes? They'd crack each other up!"
|
371
|
+
]
|
372
|
+
|
373
|
+
send_chat_message(
|
374
|
+
room_id: command_data['room_id'],
|
375
|
+
content: "š #{jokes.sample}"
|
376
|
+
)
|
377
|
+
end
|
378
|
+
|
379
|
+
def handle_help_command(command_data)
|
380
|
+
help_text = @capabilities.map { |cmd| "/#{cmd} - #{get_command_description(cmd)}" }.join("\n")
|
381
|
+
|
382
|
+
send_chat_message(
|
383
|
+
room_id: command_data['room_id'],
|
384
|
+
content: "š¤ Available commands:\n#{help_text}"
|
385
|
+
)
|
386
|
+
end
|
387
|
+
|
388
|
+
def handle_stats_command(command_data)
|
389
|
+
send_chat_message(
|
390
|
+
room_id: command_data['room_id'],
|
391
|
+
content: "š Bot Stats: Active in #{@active_rooms.length} rooms, #{@capabilities.length} capabilities"
|
392
|
+
)
|
393
|
+
end
|
394
|
+
|
395
|
+
def get_command_description(command)
|
396
|
+
descriptions = {
|
397
|
+
'weather' => 'Get weather information',
|
398
|
+
'joke' => 'Tell a random joke',
|
399
|
+
'help' => 'Show this help message',
|
400
|
+
'stats' => 'Show bot statistics'
|
401
|
+
}
|
402
|
+
|
403
|
+
descriptions[command] || 'No description available'
|
404
|
+
end
|
405
|
+
|
406
|
+
def send_chat_message(room_id:, content:)
|
407
|
+
message = ChatMessage.new(
|
408
|
+
message_id: "BOT-MSG-#{Time.now.to_i}-#{rand(1000)}",
|
409
|
+
room_id: room_id,
|
410
|
+
sender_id: @bot_id,
|
411
|
+
sender_name: @name,
|
412
|
+
content: content,
|
413
|
+
message_type: 'bot',
|
414
|
+
timestamp: Time.now.iso8601,
|
415
|
+
mentions: [],
|
416
|
+
metadata: { bot_type: 'service_bot' }
|
417
|
+
)
|
418
|
+
|
419
|
+
message.publish
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# Room Manager - Manages chat rooms and routing
|
424
|
+
class RoomManager
|
425
|
+
def initialize
|
426
|
+
puts "š¢ RoomManager: Starting up..."
|
427
|
+
@rooms = {}
|
428
|
+
|
429
|
+
# Subscribe to system notifications to track room membership
|
430
|
+
SystemNotificationMessage.subscribe('RoomManager.handle_system_notification')
|
431
|
+
end
|
432
|
+
|
433
|
+
def create_room(room_id:, name:, description: '')
|
434
|
+
return if @rooms.key?(room_id)
|
435
|
+
|
436
|
+
@rooms[room_id] = {
|
437
|
+
name: name,
|
438
|
+
description: description,
|
439
|
+
created_at: Time.now,
|
440
|
+
members: []
|
441
|
+
}
|
442
|
+
|
443
|
+
puts "š¢ RoomManager: Created room #{room_id} (#{name})"
|
444
|
+
|
445
|
+
# Send system notification
|
446
|
+
notification = SystemNotificationMessage.new(
|
447
|
+
notification_id: "ROOM-#{Time.now.to_i}",
|
448
|
+
room_id: room_id,
|
449
|
+
notification_type: 'room_created',
|
450
|
+
content: "Room '#{name}' was created",
|
451
|
+
timestamp: Time.now.iso8601,
|
452
|
+
metadata: { description: description }
|
453
|
+
)
|
454
|
+
|
455
|
+
notification.publish
|
456
|
+
end
|
457
|
+
|
458
|
+
def self.handle_system_notification(message_header, message_payload)
|
459
|
+
@@instance ||= new
|
460
|
+
@@instance.process_system_notification(message_header, message_payload)
|
461
|
+
end
|
462
|
+
|
463
|
+
def process_system_notification(message_header, message_payload)
|
464
|
+
notif_data = JSON.parse(message_payload)
|
465
|
+
room_id = notif_data['room_id']
|
466
|
+
|
467
|
+
return unless @rooms.key?(room_id)
|
468
|
+
|
469
|
+
case notif_data['notification_type']
|
470
|
+
when 'user_joined'
|
471
|
+
# Could track membership if needed
|
472
|
+
puts "š¢ RoomManager: Noted user joined #{room_id}"
|
473
|
+
when 'user_left'
|
474
|
+
puts "š¢ RoomManager: Noted user left #{room_id}"
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
def list_rooms
|
479
|
+
@rooms
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# Demo Runner
|
484
|
+
class DistributedChatDemo
|
485
|
+
def run
|
486
|
+
puts "š Starting Distributed Chat Demo\n"
|
487
|
+
|
488
|
+
# Start room manager
|
489
|
+
room_manager = RoomManager.new
|
490
|
+
|
491
|
+
# Create some chat rooms
|
492
|
+
room_manager.create_room(room_id: 'general', name: 'General Chat', description: 'Main discussion room')
|
493
|
+
room_manager.create_room(room_id: 'tech', name: 'Tech Talk', description: 'Technology discussions')
|
494
|
+
room_manager.create_room(room_id: 'random', name: 'Random', description: 'Off-topic conversations')
|
495
|
+
|
496
|
+
sleep(0.5)
|
497
|
+
|
498
|
+
# Create human agents
|
499
|
+
alice = HumanChatAgent.new(user_id: 'user-001', name: 'Alice')
|
500
|
+
bob = HumanChatAgent.new(user_id: 'user-002', name: 'Bob')
|
501
|
+
carol = HumanChatAgent.new(user_id: 'user-003', name: 'Carol')
|
502
|
+
|
503
|
+
# Register agents for message routing
|
504
|
+
HumanChatAgent.register_agent(alice)
|
505
|
+
HumanChatAgent.register_agent(bob)
|
506
|
+
HumanChatAgent.register_agent(carol)
|
507
|
+
|
508
|
+
# Create bot agents
|
509
|
+
helper_bot = BotAgent.new(
|
510
|
+
bot_id: 'bot-001',
|
511
|
+
name: 'HelperBot',
|
512
|
+
capabilities: ['help', 'stats']
|
513
|
+
)
|
514
|
+
|
515
|
+
fun_bot = BotAgent.new(
|
516
|
+
bot_id: 'bot-002',
|
517
|
+
name: 'FunBot',
|
518
|
+
capabilities: ['joke', 'weather']
|
519
|
+
)
|
520
|
+
|
521
|
+
# Register bots
|
522
|
+
BotAgent.register_bot(helper_bot)
|
523
|
+
BotAgent.register_bot(fun_bot)
|
524
|
+
|
525
|
+
sleep(0.5)
|
526
|
+
|
527
|
+
puts "\n" + "="*80
|
528
|
+
puts "Chat Simulation Starting"
|
529
|
+
puts "="*80
|
530
|
+
|
531
|
+
# Users join rooms
|
532
|
+
alice.join_room('general')
|
533
|
+
alice.join_room('tech')
|
534
|
+
sleep(0.3)
|
535
|
+
|
536
|
+
bob.join_room('general')
|
537
|
+
bob.join_room('random')
|
538
|
+
sleep(0.3)
|
539
|
+
|
540
|
+
carol.join_room('tech')
|
541
|
+
carol.join_room('random')
|
542
|
+
sleep(0.3)
|
543
|
+
|
544
|
+
# Bots join rooms
|
545
|
+
helper_bot.join_room('general')
|
546
|
+
helper_bot.join_room('tech')
|
547
|
+
sleep(0.3)
|
548
|
+
|
549
|
+
fun_bot.join_room('general')
|
550
|
+
fun_bot.join_room('random')
|
551
|
+
sleep(0.5)
|
552
|
+
|
553
|
+
# Simulate conversation
|
554
|
+
puts "\n--- Conversation in General ---"
|
555
|
+
alice.send_message(room_id: 'general', content: 'Hello everyone!')
|
556
|
+
sleep(0.5)
|
557
|
+
|
558
|
+
bob.send_message(room_id: 'general', content: 'Hi Alice! How are you?')
|
559
|
+
sleep(0.5)
|
560
|
+
|
561
|
+
alice.send_message(room_id: 'general', content: '/help')
|
562
|
+
sleep(0.8)
|
563
|
+
|
564
|
+
bob.send_message(room_id: 'general', content: '/joke')
|
565
|
+
sleep(0.8)
|
566
|
+
|
567
|
+
puts "\n--- Conversation in Tech ---"
|
568
|
+
alice.send_message(room_id: 'tech', content: 'Anyone working on Ruby today?')
|
569
|
+
sleep(0.5)
|
570
|
+
|
571
|
+
carol.send_message(room_id: 'tech', content: 'Yes! Working on messaging systems')
|
572
|
+
sleep(0.5)
|
573
|
+
|
574
|
+
alice.send_message(room_id: 'tech', content: 'Cool! @user-003 what kind of messaging?', mentions: ['user-003'])
|
575
|
+
sleep(0.8)
|
576
|
+
|
577
|
+
puts "\n--- Conversation in Random ---"
|
578
|
+
bob.send_message(room_id: 'random', content: '/weather New York')
|
579
|
+
sleep(0.8)
|
580
|
+
|
581
|
+
carol.send_message(room_id: 'random', content: 'Hello fun bot!')
|
582
|
+
sleep(0.5)
|
583
|
+
|
584
|
+
# Some users leave
|
585
|
+
puts "\n--- Users Leaving ---"
|
586
|
+
alice.leave_room('tech')
|
587
|
+
sleep(0.3)
|
588
|
+
|
589
|
+
bob.leave_room('random')
|
590
|
+
sleep(0.5)
|
591
|
+
|
592
|
+
puts "\n⨠Demo completed!"
|
593
|
+
puts "\nThis example demonstrated:"
|
594
|
+
puts "⢠Many-to-many messaging between multiple agents"
|
595
|
+
puts "⢠Different types of agents (humans, bots) in the same system"
|
596
|
+
puts "⢠Room-based message routing and filtering"
|
597
|
+
puts "⢠Multiple message types (chat, commands, notifications)"
|
598
|
+
puts "⢠Dynamic subscription and unsubscription"
|
599
|
+
puts "⢠Event-driven responses and interactions"
|
600
|
+
puts "⢠Service discovery and capability advertisement"
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
# Run the demo if this file is executed directly
|
605
|
+
if __FILE__ == $0
|
606
|
+
demo = DistributedChatDemo.new
|
607
|
+
demo.run
|
608
|
+
end
|