Gopherbot comes with brain methods allowing plugin authors to store information long-term information like a TODO
list, or short-term contextual
information, such as a particular list item under discussion. An important supplement to this guide can be found in the example scripting
plugins in the plugins/
directory, and the links
and lists
Go plugins in the goplugins
directory (from the source,
not included in the distributed .zip
files).
Table of Contents
Memory Scoping
Long-term memories are scoped per-plugin by key, and so the data is not shareable between plugins. Short-term memories are stored for each user/channel combination, and can be freely shared between plugins.
Sharing Memories
For multiple jobs and/or plugins to share the same memory namespace, create an entry in the robot's NameSpaces:
, and set the NameSpace:
for each job or plugin.
Simple Task Memory NameSpace
By default, simple tasks in a job or plugin pipeline inherit the NameSpace from the pipeline, allowing memory-using tasks to be re-used. If a particular task needs to use the same memories for different plugins and jobs, create a unique entry for the task in the robot's NameSpaces:
, and set that task's NameSpace:
accordingly.
Long-Term Memories
The following methods are available for manipulating long-term memories:
CheckoutDatum(key, RWflag)
- returns a complex data item (memory) with a short-term exclusive lock on the datum if RW istrue
CheckinDatum(memory)
- signals the robot to release the lock without updatingUpdateDatum(memory)
- updates the memory and releases the lock
When checking out a memory read-write, the engine grants a short-term lock on the memory lasting 1-2 seconds. For tasks where the time between checkout and update could be longer than one second, you should check the return value on UpdateDatum
- DatumLockExpired
indicates another waiting task took the lock. It's worth noting that for low-contention memories, a given task can keep the memory checked out indefinitely and still update successfully; the 1-2 seconds is guaranteed, but the lock isn't actually lost unless another task checks out the memory read-write. This also means that a read-only checkout may get an outdated memory.
Long-Term Memory Code Examples
The memory stored can be an arbitrarily complex data item; a hash, array, or combination - anything that can be serialized to/from
JSON. The example plugins for Python and Ruby implement a remember function that remembers a list (array)
of items. For the code examples, we'll start with a memory whose key is memory
, and has two items defined by this snippet of JSON:
["the Alamo", "Ferris Bueller"]
The examples will check if the memory exists, add "the answer is 42", and then update the memory.
Note that long-term memory commands aren't current implemented for bash
.
Python
memory = bot.CheckoutDatum("memory", True)
if memory.exists:
memory.datum.append("the answer is 42")
else:
memory.datum = [ thing ]
ret = bot.UpdateDatum(memory)
if ret != Robot.Ok:
bot.Say("Uh-oh, I must be gettin' old - having memory problems!")
Ruby
Note: the Ruby example is a little more complicated; adapted from plugins/rubydemo.rb.
memory = bot.CheckoutDatum("memory", true)
remembered = false
if memory.exists
if memory.datum.include?(thing)
bot.Say("That's already one of my fondest memories")
bot.CheckinDatum(memory)
else
remembered = true
memory.datum.push("the answer is 42")
end
else
remembered = true
memory.datum = [ "the answer is 42" ]
end
if remembered
ret = bot.UpdateDatum(memory)
if ret != Robot::Ok
bot.Say("Dang it, having problems with my memory")
end
end
Long-Term Memory Sample Transcript
Using the terminal
connector, you can see the remember
function in action:
c:general/u:alice -> floyd, remember the answer is 42
general: Ok, I'll remember "the answer is 42"
c:general/u:alice -> |ubob
Changed current user to: bob
c:general/u:bob -> floyd, recall
general: Here's everything I can remember:
#1: the Alamo
#2: Ferris Bueller
#3: the answer is 42
From the transcript you can see that alice
added the item to the list, which
was then visible to bob
. The links
and lists
plugins are more useful, and
allow easy sharing of bookmark items or TODO
lists, for example.
Short-Term Memories
Short term memories are simple key -> string values stored for each user / channel combination, and expiring
after a time. The best example of this uses the built-in links
and lists
plugins, shown in this example
using the terminal
plugin:
c:general/u:alice -> link tuna casserole to https://www.allrecipes.com/recipe/17219/best-tuna-casserole/, floyd
general: Link added
c:general/u:alice -> add it to the dinner meals list
c:general/u:alice -> floyd
general: Ok, I added tuna casserole to the dinner meals list
c:general/u:alice -> floyd
general: Yes?
c:general/u:bob -> floyd, pick a random item from the dinner meals list
general: Here you go: tuna casserole
c:general/u:bob -> look it up, floyd
general: Here's what I have for "tuna casserole":
https://www.allrecipes.com/recipe/17219/best-tuna-casserole/: tuna casserole
Here, the robot is using short-term memories several times. When I forgot to address my command to the robot, the command
add it to the dinner meals list
was stored in short-term memory for user alice
in the general
channel; then, when
I typed the robot's name, it checked short-term memory for the last thing alice
said (stored automatically). Then,
the links
plugin stored tuna casserole
in the item
short-term contextual memory; when I used it
in the lists command,
the lists plugin checked the item
short-term memory (see contexts
in the plugin config for lists
) and
substituted the value from the short-term memory.
Method Summary
These methods are available for short-term memories:
Remember(key, value)
- associate the stringvalue
tokey
, always returnsOk
RememberContext(context, value)
- store a short-term contextual memory for use with other pluginsRecall(key)
- return the short-term memory associated withkey
, or the empty string when the memory doesn't exist
Note that the short-term memory API doesn't have complicated return values. They are always stored in the robot's working memory and never persisted, and expire after several minutes - so plugins should always be prepared to get blank return values.
Short-Term Memory Code Examples
Note that the short-term memory API is super trivial, so I didn't go to great lengths to provide
detailed examples. The bash
example comes from the bashdemo.sh
plugin.
Bash
Remember "$1" "$2"
Say "I'll remember \"$1\" is \"$2\" - but eventually I'll forget!"
MEMORY=$(Recall "$1")
if [ -z "$MEMORY" ]
then
Reply "Gosh, I have no idea - I'm so forgetful!"
else
Say "$1 is $MEMORY"
fi
Python
bot.Remember(key, value)
mem = bot.Recall(key)
Ruby
bot.Remember(key, value)
mem = bot.Recall(key)
Short-Term Memory Sample Transcript
Here you can see the robot's short term memories of Ferris Bueller in action (using
the bashdemo.sh
plugin):
c:general/u:bob -> floyd, what is Ferris Bueller
general: @bob Gosh, I have no idea - I'm so forgetful!
c:general/u:bob -> floyd, store Ferris Bueller is a Righteous Dude
general: I'll remember "Ferris Bueller" is "a Righteous Dude" - but eventually I'll forget!
c:general/u:bob -> floyd, what is Ferris Bueller
general: Ferris Bueller is a Righteous Dude
c:general/u:bob -> |ualice
Changed current user to: alice
c:general/u:alice -> floyd, what is Ferris Bueller
general: @alice Gosh, I have no idea - I'm so forgetful!
c:general/u:alice -> |ubob
Changed current user to: bob
c:general/u:bob -> floyd, what is Ferris Bueller
general: Ferris Bueller is a Righteous Dude