Class: RubynCode::Teams::Mailbox

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/teams/mailbox.rb

Overview

JSONL-based mailbox for inter-agent messaging backed by SQLite.

Messages are stored in the ‘mailbox_messages` table with structured JSON content. Each message tracks read/unread state per recipient.

Instance Method Summary collapse

Constructor Details

#initialize(db) ⇒ Mailbox

Returns a new instance of Mailbox.

Parameters:



14
15
16
17
# File 'lib/rubyn_code/teams/mailbox.rb', line 14

def initialize(db)
  @db = db
  ensure_table!
end

Instance Method Details

#broadcast(from:, content:, all_names:) ⇒ Array<String>

Broadcasts a message from one agent to all other agents.

Parameters:

  • from (String)

    sender agent name

  • content (String)

    message body

  • all_names (Array<String>)

    list of all agent names in the team

Returns:

  • (Array<String>)

    message ids



85
86
87
88
89
90
91
# File 'lib/rubyn_code/teams/mailbox.rb', line 85

def broadcast(from:, content:, all_names:)
  recipients = all_names.reject { |n| n == from }

  recipients.map do |recipient|
    send(from: from, to: recipient, content: content, message_type: 'broadcast')
  end
end

#pending_for(name) ⇒ Array<Hash>

Returns unread messages for the given agent WITHOUT marking them as read. Used by IdlePoller to check for pending work without consuming messages.

Parameters:

  • name (String)

    the recipient agent name

Returns:

  • (Array<Hash>)

    parsed message hashes



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/rubyn_code/teams/mailbox.rb', line 98

def pending_for(name)
  rows = @db.query(
    <<~SQL,
      SELECT payload FROM mailbox_messages
      WHERE recipient = ? AND read = 0
      ORDER BY created_at ASC
    SQL
    [name]
  ).to_a

  rows.map { |r| JSON.parse(r['payload'], symbolize_names: true) }
end

#read_inbox(name) ⇒ Array<Hash>

Reads all unread messages for the given agent and marks them as read.

Parameters:

  • name (String)

    the recipient agent name

Returns:

  • (Array<Hash>)

    parsed message hashes



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rubyn_code/teams/mailbox.rb', line 54

def read_inbox(name)
  rows = @db.query(
    <<~SQL,
      SELECT id, payload FROM mailbox_messages
      WHERE recipient = ? AND read = 0
      ORDER BY created_at ASC
    SQL
    [name]
  ).to_a

  return [] if rows.empty?

  ids = rows.map { |r| r['id'] }
  messages = rows.map { |r| JSON.parse(r['payload'], symbolize_names: true) }

  # Mark all fetched messages as read in a single statement
  placeholders = ids.map { '?' }.join(', ')
  @db.execute(
    "UPDATE mailbox_messages SET read = 1 WHERE id IN (#{placeholders})",
    ids
  )

  messages
end

#send(from:, to:, content:, message_type: 'message') ⇒ String

Sends a message from one agent to another.

Parameters:

  • from (String)

    sender agent name

  • to (String)

    recipient agent name

  • content (String)

    message body

  • message_type (String) (defaults to: 'message')

    type of message (default: “message”)

Returns:

  • (String)

    the message id



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rubyn_code/teams/mailbox.rb', line 26

def send(from:, to:, content:, message_type: 'message')
  id = SecureRandom.uuid
  now = Time.now.utc.iso8601

  payload = JSON.generate({
                            id: id,
                            from: from,
                            to: to,
                            content: content,
                            message_type: message_type,
                            timestamp: now
                          })

  @db.execute(
    <<~SQL,
      INSERT INTO mailbox_messages (id, sender, recipient, message_type, payload, read, created_at)
      VALUES (?, ?, ?, ?, ?, 0, ?)
    SQL
    [id, from, to, message_type, payload, now]
  )

  id
end

#unread_count(name) ⇒ Integer

Returns the count of unread messages for the given agent.

Parameters:

  • name (String)

    the recipient agent name

Returns:

  • (Integer)


115
116
117
118
119
120
121
# File 'lib/rubyn_code/teams/mailbox.rb', line 115

def unread_count(name)
  rows = @db.query(
    'SELECT COUNT(*) AS cnt FROM mailbox_messages WHERE recipient = ? AND read = 0',
    [name]
  ).to_a
  rows.first&.fetch('cnt', 0) || 0
end