Details: Considerations for the "pet fact" random responder

  The YAGPDB bot's pet-fact commands can be as short as "cat" and "dog", and the effect of any valid syntax is to look up random quotes from two respective databases and respond into the channel where the command was invoked.  That's fun in environments where ordinary users are able to send bot commands, but on the Arisia server those were locked down to administrative use.  Some different means of triggering the bot was needed, and one thought was to try and have another bot do it and authorize that path.  What if Dynobot, for instance, could send in a message invoking a YAGPDB command and then delete its own send to be sneakier about it?  As klunky as that might seem, it could still insulate Yag from direct user action.
 
'Do bots listen to other bots?' searching But the problem is that bots have a distinct tendency to ignore other entities identifiable as bots, for semi-obvious reasons.  Two bots responding to each other could easily get into a vicious and unending loop, generating huge amounts of traffic and load.  This sort of thing has happened once in a while, and bot operators have had to scramble and shut paths down externally.  Badly written bots that are vulnerable to abuse tend to get punted out of Discord, so guarding against such things is important.  Still, I thought, there may be some exceptions to that rule that I could utilize; I went off to the bot support forums and tried some targeted searching for any old messages that might hint at those.  Results were mixed; general opinion was, again, that bots should generally ignore other bots, with one or two controlled exceptions that I couldn't really use.

Some initial tests confirmed that Yag was not about to take any guff from Dyno, so trying to let Dyno invoke a "catfact" on behalf of the requester didn't seem likely.


webhook attempt for bot pickup: fail For completeness, I tried sending a command as a webhook, and this shows a lot more detail about how a webhook message is marshaled up and sent.  I was trying this completely by hand, composing a complete request with the JSON added in carrying the test message.  The protocol is actually fairly simple; the webhook URL incorporates a self-authorizing token, and all it needs is a Content-length field sufficient to cover the POST content, and the whole blob jammed down Discord's throat with a TLS transport handler.  My thought here was to possibly trigger the webhook from outside Discord, on a random-time basis, so pet facts would occasionally just pop up in the #pets channel.  But webhook delivery evidently shows up as a sufficiently bot-like message that Yag was going to ignore that stuff too.

At this point, I started digging more into YAGPDB's full custom-commands interface, and the big *a-ha* moment was realizing that Yag's regular command set could be directly invoked FROM within a custom command block.  And that custom commands could trigger in a whole variety of ways.


catfact trigger freq randomizer, yag code With a regular expression trigger, in fact, I could simply look for channel traffic that even vaguely *mentioned* cats or dogs, or kittens and puppies, or expressions of cuteness, or whatever.  As this developed I had to handle minor special cases like sentences beginning with the key words, punctuation afterward, and minor other variants, but with this simple setup the bot would handily respond with a cat or dog fact whenever someone commented on either.

Except that was far too frequently, as seen in the main-story image, where the bot was even picking up multiple triggers from within one message.  To avoid it turning into a total spam-fest, the final code added a simple randomizer so that the quote responses would only fire about half the time, and after a short delay to make it a little less clear why.  I could also wrap the quote in a little extra markdown to explain why these random sends from a bot were coming in at all.

And the best part?  Custom commands don't need any special privilege to invoke, as it technically isn't a direct bot command.  So this would work for everyone.


how the yag .User object gets returned The randomization tests and tuning were carried out on my own server first, and then the tweaked code set up on the Arisia side.  It worked quite well, and I don't think anyone actually caught on to what was happening or tried to suss out the algorithm with test messages.

The final working code, notably *without* deleting the trigger message so as to not disrupt ordinary conversation:

{{$n := randInt 9}}{{if lt $n 4}}
{{sleep 3}}
***Random cat fact:***
{{exec "cat"}}
{{end}}

and a corresponding one for dog-related regexes invoking "dog".

If this image seems to have nothing to do with that, I was testing a couple of different things at the same time -- this started out exploring how the ".User" object comes back in YAGPDB, so I could figure out how to parse it for, say, the "mute" function.  But the randomizer was also running in this, which would or wouldn't trigger the cat-fact function as noted by the output.  My own server collected a lot of mangled bot-parts and command debris over the course of the weekend, but it was good that I could do all the crash-testing over there and bring the cleaned-up work product back to the Arisia server.

_H*   210202