brainiac-discord 0.0.19 → 0.0.21

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '039a353d5ca3679a9ac10b849382d8df6df5080c89a15f6eda1a843585c60beb'
4
- data.tar.gz: 0a8944ada2fa21e0ece41680930b773620b8b68c7c6cc003847d21ac86beda9f
3
+ metadata.gz: '0867d7c12ec729c881db2a3a8dd9f02da284f677b3f7226a8771958b97da07b5'
4
+ data.tar.gz: 073f0bbceca7c578ea06cd888c2e333b113efeede5ebde4b02b257247df15c9d
5
5
  SHA512:
6
- metadata.gz: b119932ccf37b19d4bdeaebefc49538ba1d560060103064e8931804c1827ef7656de9903a8231b866872d425043e638254061d5358c4d2bc771e451749f206b4
7
- data.tar.gz: ca37078a141d0829cfbfb26602155b91962616a9b0882801844b63fbd045f3a0a0de1c07ef18577599de20e09282a9a01746b96e67c1ed3238ce0a96786e45a1
6
+ metadata.gz: 5c103f0b92d230a5789424e41d9ea9881636a7ede849278db072c93b42c18ac42266ea264abb7128086e92e0639a042ff894460d9ee1405aabb5348d71918bda
7
+ data.tar.gz: 2a236d41ec8676a4e3459bcd26bf5d47019a3f4cc5e67bfa4b1d2b8027c00e0803680c5ca37166285449d4a0f2ccffd7a0b81fde785a4ea977f476994aa158d3
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "websocket-client-simple"
4
4
  require "websocket"
5
+ require "time"
5
6
 
6
7
  module Brainiac
7
8
  module Plugins
@@ -23,6 +24,12 @@ module Brainiac
23
24
  BACKOFF_HANDSHAKE_BASE = 30
24
25
  BACKOFF_CAP = 300
25
26
 
27
+ # How long after a message is posted an edit still counts as a real,
28
+ # conversational edit worth re-dispatching on. Edits that land outside
29
+ # this window are treated as server-side embed refreshes (Discord
30
+ # restamping edited_timestamp when it unfurls a link), not human intent.
31
+ EDIT_FRESHNESS_WINDOW = 300 # seconds (5 minutes)
32
+
26
33
  # Per-bot state: { agent_key => { token:, user_id:, status:, thread: } }
27
34
  @bots = {}
28
35
  @bots_mutex = Mutex.new
@@ -376,7 +383,16 @@ module Brainiac
376
383
  LOG.error "[Discord:#{agent_display}] Error handling message: #{e.message}\n#{e.backtrace.first(3).join("\n")}" if defined?(LOG)
377
384
  end
378
385
  when "MESSAGE_UPDATE"
379
- if data["edited_timestamp"]
386
+ # Discord emits MESSAGE_UPDATE for genuine human edits AND for
387
+ # server-side embed (un)furls on existing messages — e.g. lazily
388
+ # generating a link preview days after the message was posted. Both
389
+ # stamp edited_timestamp, so re-dispatching on every update means a
390
+ # bare URL in an old agent-mentioning message can silently wake the
391
+ # agent long after the fact. Only treat an update as actionable when
392
+ # the edit happened close to the message's own creation time, which
393
+ # is what a real conversational edit (typo fix, afterthought) looks
394
+ # like. See message.rb for the shared dispatch path.
395
+ if data["edited_timestamp"] && !stale_edit?(data["timestamp"], data["edited_timestamp"])
380
396
  Thread.new do
381
397
  Message.handle(data, agent_key, bot_token, bot_user_id)
382
398
  rescue StandardError => e
@@ -384,6 +400,9 @@ module Brainiac
384
400
  LOG.error "[Discord:#{agent_display}] Error handling message update: #{e.message}\n#{e.backtrace.first(3).join("\n")}"
385
401
  end
386
402
  end
403
+ elsif data["edited_timestamp"] && defined?(LOG)
404
+ LOG.info "[Discord:#{agent_display}] Ignoring stale MESSAGE_UPDATE " \
405
+ "(likely embed refresh) on message #{data["id"]}"
387
406
  end
388
407
  when "MESSAGE_REACTION_ADD"
389
408
  Thread.new do
@@ -416,6 +435,25 @@ module Brainiac
416
435
  bot_user_id
417
436
  end
418
437
 
438
+ # True when a MESSAGE_UPDATE's edit happened long enough after the
439
+ # message was created that it's almost certainly a server-side embed
440
+ # refresh rather than a human edit. Guards against spurious agent
441
+ # dispatches from Discord lazily unfurling link previews on old
442
+ # messages that mention the bot.
443
+ #
444
+ # Fails open (returns false → treat as a real edit) when either
445
+ # timestamp is missing or unparseable, so a parsing hiccup never
446
+ # silently swallows a genuine edit.
447
+ def stale_edit?(created_at, edited_at)
448
+ return false if created_at.nil? || edited_at.nil?
449
+
450
+ created = Time.iso8601(created_at.to_s)
451
+ edited = Time.iso8601(edited_at.to_s)
452
+ (edited - created) > EDIT_FRESHNESS_WINDOW
453
+ rescue ArgumentError
454
+ false
455
+ end
456
+
419
457
  def mark_bot_ready(agent_key, agent_display, bot_user_id, data)
420
458
  @bots_mutex.synchronize do
421
459
  @bots[agent_key][:user_id] = bot_user_id
@@ -11,6 +11,12 @@ module Brainiac
11
11
  CHANNEL = <<~PROMPT
12
12
  ## Discord Channel Rules
13
13
 
14
+ ### Current Message Priority
15
+ The message in "**Message:**" above is your PRIMARY task. Everything else is context.
16
+ - Original thread topic: reference only — don't answer questions that weren't asked
17
+ - Channel history: context only — helps you understand the conversation flow
18
+ - Your job: respond to the current message, not summarize the thread
19
+
14
20
  ### Mentions
15
21
  Discord does NOT support plain-text @mentions. Writing `@Galen` renders as plain text.
16
22
  To actually mention someone, use the `<@USER_ID>` format. Here are the known IDs:
@@ -3,7 +3,7 @@
3
3
  module Brainiac
4
4
  module Plugins
5
5
  module Discord
6
- VERSION = "0.0.19"
6
+ VERSION = "0.0.21"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainiac-discord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.19
4
+ version: 0.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Davis